init
This commit is contained in:
384
src/views/Home/Index.vue
Normal file
384
src/views/Home/Index.vue
Normal file
@@ -0,0 +1,384 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-card shadow="never">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<el-row :gutter="16" justify="space-between">
|
||||
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<div class="flex items-center">
|
||||
<el-avatar :src="avatar" :size="70" class="mr-16px">
|
||||
<img src="@/assets/imgs/avatar.jpg" alt="" />
|
||||
</el-avatar>
|
||||
<div>
|
||||
<div class="text-20px">
|
||||
{{ t('workplace.welcome') }} {{ username }} {{ t('workplace.happyDay') }}
|
||||
</div>
|
||||
<div class="mt-10px text-14px text-gray-500">
|
||||
{{ t('workplace.toady') }},20℃ - 32℃!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :xl="12" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<div class="h-70px flex items-center justify-end lt-sm:mt-10px">
|
||||
<div class="px-8px text-right">
|
||||
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.project') }}</div>
|
||||
<CountTo
|
||||
class="text-20px"
|
||||
:start-val="0"
|
||||
:end-val="totalSate.project"
|
||||
:duration="2600"
|
||||
/>
|
||||
</div>
|
||||
<el-divider direction="vertical" />
|
||||
<div class="px-8px text-right">
|
||||
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.toDo') }}</div>
|
||||
<CountTo
|
||||
class="text-20px"
|
||||
:start-val="0"
|
||||
:end-val="totalSate.todo"
|
||||
:duration="2600"
|
||||
/>
|
||||
</div>
|
||||
<el-divider direction="vertical" border-style="dashed" />
|
||||
<div class="px-8px text-right">
|
||||
<div class="mb-16px text-14px text-gray-400">{{ t('workplace.access') }}</div>
|
||||
<CountTo
|
||||
class="text-20px"
|
||||
:start-val="0"
|
||||
:end-val="totalSate.access"
|
||||
:duration="2600"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<el-row class="mt-8px" :gutter="8" justify="space-between">
|
||||
<el-col :xl="16" :lg="16" :md="24" :sm="24" :xs="24" class="mb-8px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="h-3 flex justify-between">
|
||||
<span>{{ t('workplace.project') }}</span>
|
||||
<el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<el-row>
|
||||
<el-col
|
||||
v-for="(item, index) in projects"
|
||||
:key="`card-${index}`"
|
||||
:xl="8"
|
||||
:lg="8"
|
||||
:md="8"
|
||||
:sm="24"
|
||||
:xs="24"
|
||||
>
|
||||
<el-card shadow="hover">
|
||||
<div class="flex items-center">
|
||||
<Icon :icon="item.icon" :size="25" class="mr-8px" />
|
||||
<span class="text-16px">{{ item.name }}</span>
|
||||
</div>
|
||||
<div class="mt-16px text-14px text-gray-400">{{ t(item.message) }}</div>
|
||||
<div class="mt-16px flex justify-between text-12px text-gray-400">
|
||||
<span>{{ item.personal }}</span>
|
||||
<span>{{ formatTime(item.time, 'yyyy-MM-dd') }}</span>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mt-8px">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<el-row :gutter="20" justify="space-between">
|
||||
<el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
|
||||
<el-card shadow="hover" class="mb-8px">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :options="pieOptionsData" :height="280" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
|
||||
<el-card shadow="hover" class="mb-8px">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :options="barOptionsData" :height="280" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
|
||||
<el-card shadow="never">
|
||||
<template #header>
|
||||
<div class="h-3 flex justify-between">
|
||||
<span>{{ t('workplace.shortcutOperation') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<el-row>
|
||||
<el-col v-for="item in shortcut" :key="`team-${item.name}`" :span="8" class="mb-8px">
|
||||
<div class="flex items-center">
|
||||
<Icon :icon="item.icon" class="mr-8px" />
|
||||
<el-link type="default" :underline="false" @click="setWatermark(item.name)">
|
||||
{{ item.name }}
|
||||
</el-link>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="mt-8px">
|
||||
<template #header>
|
||||
<div class="h-3 flex justify-between">
|
||||
<span>{{ t('workplace.notice') }}</span>
|
||||
<el-link type="primary" :underline="false">{{ t('action.more') }}</el-link>
|
||||
</div>
|
||||
</template>
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<div v-for="(item, index) in notice" :key="`dynamics-${index}`">
|
||||
<div class="flex items-center">
|
||||
<el-avatar :src="avatar" :size="35" class="mr-16px">
|
||||
<img src="@/assets/imgs/avatar.jpg" alt="" />
|
||||
</el-avatar>
|
||||
<div>
|
||||
<div class="text-14px">
|
||||
<Highlight :keys="item.keys.map((v) => t(v))">
|
||||
{{ item.type }} : {{ item.title }}
|
||||
</Highlight>
|
||||
</div>
|
||||
<div class="mt-16px text-12px text-gray-400">
|
||||
{{ formatTime(item.date, 'yyyy-MM-dd') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-divider />
|
||||
</div>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { set } from 'lodash-es'
|
||||
import { EChartsOption } from 'echarts'
|
||||
import { formatTime } from '@/utils'
|
||||
|
||||
import { useUserStore } from '@/store/modules/user'
|
||||
import { useWatermark } from '@/hooks/web/useWatermark'
|
||||
import type { WorkplaceTotal, Project, Notice, Shortcut } from './types'
|
||||
import { pieOptions, barOptions } from './echarts-data'
|
||||
|
||||
defineOptions({ name: 'Home' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const userStore = useUserStore()
|
||||
const { setWatermark } = useWatermark()
|
||||
const loading = ref(true)
|
||||
const avatar = userStore.getUser.avatar
|
||||
const username = userStore.getUser.nickname
|
||||
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
|
||||
// 获取统计数
|
||||
let totalSate = reactive<WorkplaceTotal>({
|
||||
project: 0,
|
||||
access: 0,
|
||||
todo: 0
|
||||
})
|
||||
|
||||
const getCount = async () => {
|
||||
const data = {
|
||||
project: 40,
|
||||
access: 2340,
|
||||
todo: 10
|
||||
}
|
||||
totalSate = Object.assign(totalSate, data)
|
||||
}
|
||||
|
||||
// 获取项目数
|
||||
let projects = reactive<Project[]>([])
|
||||
const getProject = async () => {
|
||||
const data = [
|
||||
{
|
||||
name: 'Github',
|
||||
icon: 'akar-icons:github-fill',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'Vue',
|
||||
icon: 'logos:vue',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'Angular',
|
||||
icon: 'logos:angular-icon',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'React',
|
||||
icon: 'logos:react',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'Webpack',
|
||||
icon: 'logos:webpack',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
},
|
||||
{
|
||||
name: 'Vite',
|
||||
icon: 'vscode-icons:file-type-vite',
|
||||
message: 'workplace.introduction',
|
||||
personal: 'Archer',
|
||||
time: new Date()
|
||||
}
|
||||
]
|
||||
projects = Object.assign(projects, data)
|
||||
}
|
||||
|
||||
// 获取通知公告
|
||||
let notice = reactive<Notice[]>([])
|
||||
const getNotice = async () => {
|
||||
const data = [
|
||||
{
|
||||
title: '系统升级版本',
|
||||
type: '通知',
|
||||
keys: ['通知', '升级'],
|
||||
date: new Date()
|
||||
},
|
||||
{
|
||||
title: '系统凌晨维护',
|
||||
type: '公告',
|
||||
keys: ['公告', '维护'],
|
||||
date: new Date()
|
||||
},
|
||||
{
|
||||
title: '系统升级版本',
|
||||
type: '通知',
|
||||
keys: ['通知', '升级'],
|
||||
date: new Date()
|
||||
},
|
||||
{
|
||||
title: '系统凌晨维护',
|
||||
type: '公告',
|
||||
keys: ['公告', '维护'],
|
||||
date: new Date()
|
||||
}
|
||||
]
|
||||
notice = Object.assign(notice, data)
|
||||
}
|
||||
|
||||
// 获取快捷入口
|
||||
let shortcut = reactive<Shortcut[]>([])
|
||||
|
||||
const getShortcut = async () => {
|
||||
const data = [
|
||||
{
|
||||
name: 'Github',
|
||||
icon: 'akar-icons:github-fill',
|
||||
url: 'github.io'
|
||||
},
|
||||
{
|
||||
name: 'Vue',
|
||||
icon: 'logos:vue',
|
||||
url: 'vuejs.org'
|
||||
},
|
||||
{
|
||||
name: 'Vite',
|
||||
icon: 'vscode-icons:file-type-vite',
|
||||
url: 'https://vitejs.dev/'
|
||||
},
|
||||
{
|
||||
name: 'Angular',
|
||||
icon: 'logos:angular-icon',
|
||||
url: 'github.io'
|
||||
},
|
||||
{
|
||||
name: 'React',
|
||||
icon: 'logos:react',
|
||||
url: 'github.io'
|
||||
},
|
||||
{
|
||||
name: 'Webpack',
|
||||
icon: 'logos:webpack',
|
||||
url: 'github.io'
|
||||
}
|
||||
]
|
||||
shortcut = Object.assign(shortcut, data)
|
||||
}
|
||||
|
||||
// 用户来源
|
||||
const getUserAccessSource = async () => {
|
||||
const data = [
|
||||
{ value: 335, name: 'analysis.directAccess' },
|
||||
{ value: 310, name: 'analysis.mailMarketing' },
|
||||
{ value: 234, name: 'analysis.allianceAdvertising' },
|
||||
{ value: 135, name: 'analysis.videoAdvertising' },
|
||||
{ value: 1548, name: 'analysis.searchEngines' }
|
||||
]
|
||||
set(
|
||||
pieOptionsData,
|
||||
'legend.data',
|
||||
data.map((v) => t(v.name))
|
||||
)
|
||||
pieOptionsData!.series![0].data = data.map((v) => {
|
||||
return {
|
||||
name: t(v.name),
|
||||
value: v.value
|
||||
}
|
||||
})
|
||||
}
|
||||
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
|
||||
|
||||
// 周活跃量
|
||||
const getWeeklyUserActivity = async () => {
|
||||
const data = [
|
||||
{ value: 13253, name: 'analysis.monday' },
|
||||
{ value: 34235, name: 'analysis.tuesday' },
|
||||
{ value: 26321, name: 'analysis.wednesday' },
|
||||
{ value: 12340, name: 'analysis.thursday' },
|
||||
{ value: 24643, name: 'analysis.friday' },
|
||||
{ value: 1322, name: 'analysis.saturday' },
|
||||
{ value: 1324, name: 'analysis.sunday' }
|
||||
]
|
||||
set(
|
||||
barOptionsData,
|
||||
'xAxis.data',
|
||||
data.map((v) => t(v.name))
|
||||
)
|
||||
set(barOptionsData, 'series', [
|
||||
{
|
||||
name: t('analysis.activeQuantity'),
|
||||
data: data.map((v) => v.value),
|
||||
type: 'bar'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
const getAllApi = async () => {
|
||||
await Promise.all([
|
||||
getCount(),
|
||||
getProject(),
|
||||
getNotice(),
|
||||
getShortcut(),
|
||||
getUserAccessSource(),
|
||||
getWeeklyUserActivity()
|
||||
])
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
getAllApi()
|
||||
</script>
|
||||
1800
src/views/Home/Index10.vue
Normal file
1800
src/views/Home/Index10.vue
Normal file
File diff suppressed because it is too large
Load Diff
466
src/views/Home/Index11.vue
Normal file
466
src/views/Home/Index11.vue
Normal file
@@ -0,0 +1,466 @@
|
||||
<template>
|
||||
<div class="w-100%" v-loading="loading">
|
||||
<div class="search-top flex justify-right">
|
||||
<!-- <div class="search-top flex justify-between"> -->
|
||||
<!-- 租户搜索 -->
|
||||
<!-- <div>
|
||||
<span class="text-13px c-#656565"> 租户名称:</span>
|
||||
<el-select
|
||||
v-model="zhName"
|
||||
placeholder="请选择"
|
||||
size="large"
|
||||
style="width: 264px"
|
||||
@change="selectChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in zhOption"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div> -->
|
||||
<!-- 切换日期 -->
|
||||
<div class="flex">
|
||||
<div class="w-200px grid grid-cols-3 mr-20px items-center">
|
||||
<div
|
||||
class="text-13px text-center cursor-pointer"
|
||||
:style="{ color: btnActive == item.name ? '#692AFB' : '#656565' }"
|
||||
v-for="item in btnList"
|
||||
:key="item.type"
|
||||
@click="btnClick(item)"
|
||||
>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-date-picker
|
||||
v-model="pickerValue"
|
||||
type="daterange"
|
||||
range-separator="~"
|
||||
start-placeholder="Start date"
|
||||
end-placeholder="End date"
|
||||
value-format="YYYY-MM-DD"
|
||||
size="default"
|
||||
:editable="false"
|
||||
@change="pirckerChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-20px">
|
||||
<div
|
||||
class="text-13px c-#333333 font-700 bg-white h-45px pl-20px flex items-center b-1px b-solid b-#E4E4E4 b-t-0 b-l-0 b-r-0 .dark:b-#6B7280 .dark:c-#6B7280 .dark:bg-#1D1E1F"
|
||||
>
|
||||
登录次数/使用人数对比分析
|
||||
</div>
|
||||
<Echart :options="login_option" width="100%" height="423px" />
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-x-20px mt-30px">
|
||||
<div class="bg-#fff b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid .dark:bg-#1D1E1F">
|
||||
<div
|
||||
class="h-45px flex items-center text-13px c-#333333 font-700 pl-20px b-1px b-solid b-#E4E4E4 b-t-0 b-l-0 b-r-0 .dark:c-#6B7280 .dark:b-#6B7280"
|
||||
style="font-family: Arial-BoldMT, 'Arial Bold', Arial, sans-serif"
|
||||
>
|
||||
使用人数最多的模块top5
|
||||
</div>
|
||||
<div class="p-20px">
|
||||
<avue-crud :option="mostOption" :data="mostData"></avue-crud>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-#fff b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid">
|
||||
<div
|
||||
class="h-45px flex items-center text-13px c-#333333 font-700 pl-20px b-1px b-solid b-#E4E4E4 b-t-0 b-l-0 b-r-0 .dark:c-#6B7280 .dark:b-#6B7280"
|
||||
style="font-family: Arial-BoldMT, 'Arial Bold', Arial, sans-serif"
|
||||
>
|
||||
使用人数最少的模块bottom5
|
||||
</div>
|
||||
<div class="p-20px">
|
||||
<avue-crud :option="mostOption" :data="leastData"></avue-crud>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
|
||||
import { getTableList, batchGetTableList } from '@/api/design/report'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import Icon from '@/components/Icon/src/Icon.vue'
|
||||
|
||||
defineOptions({ name: 'Home11' })
|
||||
|
||||
interface LoginXdata {
|
||||
value: string | number
|
||||
textStyle: {
|
||||
color: string
|
||||
fontSize: number
|
||||
}
|
||||
}
|
||||
interface TabData {
|
||||
mk: string
|
||||
pm: number
|
||||
syyhs: number
|
||||
zzf: string
|
||||
zzfFlag: number
|
||||
}
|
||||
|
||||
const cardCellColor = ref('rgb(0 0 0 / 64.7%)')
|
||||
|
||||
const loading = ref(false)
|
||||
|
||||
const zhName = ref<string>('')
|
||||
// 租户字典
|
||||
const zhOption = ref([
|
||||
// {
|
||||
// value: 'Option1',
|
||||
// label: 'Option1'
|
||||
// }
|
||||
])
|
||||
// 租户字典的change
|
||||
const selectChange = (val) => {
|
||||
}
|
||||
|
||||
// 获取日期
|
||||
let now = new Date()
|
||||
const pickerValue = ref<Date | [Date, Date] | [string, string]>()
|
||||
const dayArr = ref<[string, string]>()
|
||||
const weekArr = ref<[string, string]>()
|
||||
const monthArr = ref<[string, string]>()
|
||||
const getDay = () => {
|
||||
let day = formatDate(now, 'YYYY-MM-DD')
|
||||
dayArr.value = [day, day]
|
||||
}
|
||||
const getWeek = () => {
|
||||
var firstDayOfWeek = new Date(now)
|
||||
firstDayOfWeek.setDate(firstDayOfWeek.getDate() - firstDayOfWeek.getDay() + 1)
|
||||
var lastDayOfWeek = new Date(firstDayOfWeek)
|
||||
lastDayOfWeek.setDate(firstDayOfWeek.getDate() + 6)
|
||||
var first =
|
||||
firstDayOfWeek.getFullYear() +
|
||||
'-' +
|
||||
String(firstDayOfWeek.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(firstDayOfWeek.getDate()).padStart(2, '0')
|
||||
var last =
|
||||
lastDayOfWeek.getFullYear() +
|
||||
'-' +
|
||||
String(lastDayOfWeek.getMonth() + 1).padStart(2, '0') +
|
||||
'-' +
|
||||
String(lastDayOfWeek.getDate()).padStart(2, '0')
|
||||
|
||||
weekArr.value = [first, last]
|
||||
}
|
||||
const getMonth = () => {
|
||||
let month = now.getMonth()
|
||||
let year = now.getFullYear()
|
||||
var first = formatDate(new Date(year, month, 1), 'YYYY-MM-DD')
|
||||
var last = formatDate(new Date(year, month + 1, 0), 'YYYY-MM-DD')
|
||||
monthArr.value = [first, last]
|
||||
}
|
||||
|
||||
// 切换日期
|
||||
const btnList = ref([
|
||||
{ name: '本日', type: 1 },
|
||||
{ name: '本周', type: 2 },
|
||||
{ name: '本月', type: 3 }
|
||||
])
|
||||
const btnActive = ref('本月')
|
||||
const btnClick = (val) => {
|
||||
btnActive.value = val.name
|
||||
if (val.type == 1) {
|
||||
pickerValue.value = dayArr.value
|
||||
} else if (val.type == 2) {
|
||||
pickerValue.value = weekArr.value
|
||||
} else if (val.type == 3) {
|
||||
pickerValue.value = monthArr.value
|
||||
}
|
||||
}
|
||||
|
||||
const pirckerChange = (val) => {
|
||||
btnActive.value = ''
|
||||
}
|
||||
|
||||
// 登录分析柱形图
|
||||
const loginSeries1 = ref<number[]>([])
|
||||
const loginSeries2 = ref<number[]>([])
|
||||
const loginX = ref<any>([])
|
||||
const loginXutil = ref({
|
||||
color: 'rgba(0, 0, 0, 0.647058823529412)',
|
||||
fontSize: 14
|
||||
})
|
||||
const loginXdata = ref<LoginXdata[]>([])
|
||||
|
||||
const login_option = ref({
|
||||
backgroundColor: 'white',
|
||||
grid: { left: '3%', right: '4%', bottom: '10%', containLabel: true },
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: {
|
||||
left: 'center',
|
||||
bottom: '3%',
|
||||
itemGap: 20,
|
||||
itemWidth: 34,
|
||||
itemHeight: 13,
|
||||
textStyle: {
|
||||
color: '#656565'
|
||||
},
|
||||
data: ['登录次数', '使用人数']
|
||||
},
|
||||
xAxis: {
|
||||
axisTick: {
|
||||
alignWithLabel: true
|
||||
},
|
||||
data: loginXdata.value
|
||||
},
|
||||
yAxis: {
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#E8E8E8'
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '登录次数',
|
||||
type: 'bar',
|
||||
color: 'rgba(105, 42, 251, 1)',
|
||||
itemStyle: {
|
||||
borderRadius: [25, 25, 0, 0]
|
||||
},
|
||||
barGap: 0,
|
||||
data: loginSeries1.value
|
||||
},
|
||||
{
|
||||
name: '使用人数',
|
||||
type: 'bar',
|
||||
color: 'rgba(54, 203, 203, 0.996078431372549)',
|
||||
itemStyle: {
|
||||
borderRadius: [25, 25, 0, 0]
|
||||
},
|
||||
data: loginSeries2.value
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const mostOption = ref({
|
||||
menu: false,
|
||||
header: false,
|
||||
border: false,
|
||||
height: 350,
|
||||
column: [
|
||||
{
|
||||
// headerAlign: 'right',
|
||||
label: '排名',
|
||||
prop: 'pm'
|
||||
},
|
||||
{
|
||||
// headerAlign: 'left',
|
||||
label: '模块',
|
||||
prop: 'mk'
|
||||
},
|
||||
{
|
||||
// headerAlign: 'left',
|
||||
label: '使用用户数',
|
||||
prop: 'syyhs'
|
||||
},
|
||||
{
|
||||
label: '模块使用数',
|
||||
prop: 'mksys'
|
||||
}
|
||||
// {
|
||||
// headerAlign: 'right',
|
||||
// label: '周涨幅',
|
||||
// prop: 'zzf',
|
||||
// render: ({ row }) => {
|
||||
// let icon
|
||||
// if (row.zzfFlag == 1) {
|
||||
// icon = h(Icon, { icon: 'ep:top', size: 20, color: '#00A854' })
|
||||
// } else {
|
||||
// icon = h(Icon, { icon: 'ep:bottom', size: 20, color: '#F04134' })
|
||||
// }
|
||||
|
||||
// return h(
|
||||
// 'div',
|
||||
// {
|
||||
// style: { display: 'flex', alignItems: 'center', justifyContent: 'right' }
|
||||
// },
|
||||
// [h('span', { style: { marginRight: '5px' } }, row.zzf), icon]
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
]
|
||||
})
|
||||
|
||||
const mostData = ref<TabData[]>()
|
||||
const leastData = ref<TabData[]>()
|
||||
|
||||
const appStore = useAppStore()
|
||||
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList('example_sytj_syzdmk,example_sytj_syzsmk')
|
||||
mostData.value = oneres.example_sytj_syzdmk.records
|
||||
leastData.value = oneres.example_sytj_syzsmk.records
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
getDay()
|
||||
getWeek()
|
||||
getMonth()
|
||||
let item = btnList.value.find((r) => r.name == btnActive.value)
|
||||
if (item) {
|
||||
let arr = [dayArr.value, weekArr.value, monthArr.value]
|
||||
pickerValue.value = arr[item.type - 1]
|
||||
} else {
|
||||
pickerValue.value = monthArr.value
|
||||
}
|
||||
|
||||
await init()
|
||||
|
||||
// 判断是否为暗色模式
|
||||
const { wsCache } = useCache()
|
||||
if (wsCache.get(CACHE_KEY.IS_DARK)) {
|
||||
cardCellColor.value = ''
|
||||
login_option.value.backgroundColor = '#1D1E1F'
|
||||
login_option.value.legend.textStyle.color = '#6B7280'
|
||||
|
||||
loginXdata.value.forEach((ele) => {
|
||||
ele.textStyle.color = '#6B7280'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => appStore.isDark,
|
||||
(val) => {
|
||||
if (val) {
|
||||
cardCellColor.value = ''
|
||||
login_option.value.backgroundColor = '#1D1E1F'
|
||||
login_option.value.legend.textStyle.color = '#6B7280'
|
||||
loginXdata.value.forEach((ele) => {
|
||||
ele.textStyle.color = '#6B7280'
|
||||
})
|
||||
} else {
|
||||
cardCellColor.value = 'rgb(0 0 0 / 64.7%)'
|
||||
login_option.value.backgroundColor = 'white'
|
||||
login_option.value.legend.textStyle.color = '#656565'
|
||||
loginXdata.value.forEach((ele) => {
|
||||
ele.textStyle.color = 'rgba(0, 0, 0, 0.647058823529412)'
|
||||
})
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
() => pickerValue.value,
|
||||
async (val) => {
|
||||
if (!val) return
|
||||
let date = val?.[0] + ',' + val?.[1]
|
||||
loading.value = true
|
||||
let res = await getTableList('example_sytj_dlsyrs', { sj: date })
|
||||
|
||||
let dlsyrs = res.records
|
||||
if (dlsyrs && dlsyrs.length > 0) {
|
||||
loginXdata.value = []
|
||||
loginX.value = []
|
||||
loginSeries1.value = []
|
||||
loginSeries2.value = []
|
||||
dlsyrs.forEach((ele) => {
|
||||
loginX.value.push(ele.sj)
|
||||
loginSeries1.value.push(ele.login_num)
|
||||
loginSeries2.value.push(ele.users_num)
|
||||
})
|
||||
|
||||
loginX.value.forEach((ele) => {
|
||||
if (val?.[0] == val?.[1]) {
|
||||
loginXdata.value.push({
|
||||
value: ele + ':00',
|
||||
textStyle: loginXutil.value
|
||||
})
|
||||
} else {
|
||||
loginXdata.value.push({
|
||||
value: ele,
|
||||
textStyle: loginXutil.value
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
login_option.value.xAxis.data = loginXdata.value
|
||||
login_option.value.series[0].data = loginSeries1.value
|
||||
login_option.value.series[1].data = loginSeries2.value
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
h5,
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.search-top {
|
||||
::v-deep(.el-select) {
|
||||
.el-select__wrapper {
|
||||
min-height: 32px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-date-editor) {
|
||||
width: 280px;
|
||||
|
||||
.el-range__icon {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-range-input {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.el-range-separator {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.avue-crud) {
|
||||
.el-form {
|
||||
.el-table__inner-wrapper {
|
||||
.el-table__header-wrapper {
|
||||
.el-table__cell {
|
||||
height: 57px;
|
||||
|
||||
.cell {
|
||||
font-family: 'Microsoft Tai Le Bold', 'Microsoft Tai Le Regular', 'Microsoft Tai Le',
|
||||
sans-serif;
|
||||
color: v-bind('cardCellColor');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-table__body {
|
||||
.el-table__row {
|
||||
height: 57px;
|
||||
|
||||
&:last-child {
|
||||
.el-table__cell {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
319
src/views/Home/Index2.vue
Normal file
319
src/views/Home/Index2.vue
Normal file
@@ -0,0 +1,319 @@
|
||||
<template>
|
||||
<el-row :class="prefixCls" :gutter="20" justify="space-between">
|
||||
<el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" :rows="2" animated>
|
||||
<template #default>
|
||||
<div :class="`${prefixCls}__item flex justify-between`">
|
||||
<div>
|
||||
<div
|
||||
:class="`${prefixCls}__item--icon ${prefixCls}__item--peoples p-16px inline-block rounded-6px`"
|
||||
>
|
||||
<Icon :size="40" icon="svg-icon:peoples" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
|
||||
>{{ t('analysis.newUser') }}
|
||||
</div>
|
||||
<CountTo
|
||||
:duration="2600"
|
||||
:end-val="102400"
|
||||
:start-val="0"
|
||||
class="text-right text-20px font-700"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" :rows="2" animated>
|
||||
<template #default>
|
||||
<div :class="`${prefixCls}__item flex justify-between`">
|
||||
<div>
|
||||
<div
|
||||
:class="`${prefixCls}__item--icon ${prefixCls}__item--message p-16px inline-block rounded-6px`"
|
||||
>
|
||||
<Icon :size="40" icon="svg-icon:message" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
|
||||
>{{ t('analysis.unreadInformation') }}
|
||||
</div>
|
||||
<CountTo
|
||||
:duration="2600"
|
||||
:end-val="81212"
|
||||
:start-val="0"
|
||||
class="text-right text-20px font-700"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" :rows="2" animated>
|
||||
<template #default>
|
||||
<div :class="`${prefixCls}__item flex justify-between`">
|
||||
<div>
|
||||
<div
|
||||
:class="`${prefixCls}__item--icon ${prefixCls}__item--money p-16px inline-block rounded-6px`"
|
||||
>
|
||||
<Icon :size="40" icon="svg-icon:money" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
|
||||
>{{ t('analysis.transactionAmount') }}
|
||||
</div>
|
||||
<CountTo
|
||||
:duration="2600"
|
||||
:end-val="9280"
|
||||
:start-val="0"
|
||||
class="text-right text-20px font-700"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<el-col :lg="6" :md="12" :sm="12" :xl="6" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" :rows="2" animated>
|
||||
<template #default>
|
||||
<div :class="`${prefixCls}__item flex justify-between`">
|
||||
<div>
|
||||
<div
|
||||
:class="`${prefixCls}__item--icon ${prefixCls}__item--shopping p-16px inline-block rounded-6px`"
|
||||
>
|
||||
<Icon :size="40" icon="svg-icon:shopping" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col justify-between">
|
||||
<div :class="`${prefixCls}__item--text text-16px text-gray-500 text-right`"
|
||||
>{{ t('analysis.totalShopping') }}
|
||||
</div>
|
||||
<CountTo
|
||||
:duration="2600"
|
||||
:end-val="13600"
|
||||
:start-val="0"
|
||||
class="text-right text-20px font-700"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" justify="space-between">
|
||||
<el-col :lg="10" :md="24" :sm="24" :xl="10" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :height="300" :options="pieOptionsData" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :lg="14" :md="24" :sm="24" :xl="14" :xs="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" animated>
|
||||
<Echart :height="300" :options="barOptionsData" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-card class="mb-20px" shadow="hover">
|
||||
<el-skeleton :loading="loading" :rows="4" animated>
|
||||
<Echart :height="350" :options="lineOptionsData" />
|
||||
</el-skeleton>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { set } from 'lodash-es'
|
||||
import { EChartsOption } from 'echarts'
|
||||
|
||||
import { useDesign } from '@/hooks/web/useDesign'
|
||||
import type { AnalysisTotalTypes } from './types'
|
||||
import { barOptions, lineOptions, pieOptions } from './echarts-data'
|
||||
|
||||
defineOptions({ name: 'Home2' })
|
||||
|
||||
const { t } = useI18n()
|
||||
const loading = ref(true)
|
||||
const { getPrefixCls } = useDesign()
|
||||
const prefixCls = getPrefixCls('panel')
|
||||
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption
|
||||
|
||||
let totalState = reactive<AnalysisTotalTypes>({
|
||||
users: 0,
|
||||
messages: 0,
|
||||
moneys: 0,
|
||||
shoppings: 0
|
||||
})
|
||||
|
||||
const getCount = async () => {
|
||||
const data = {
|
||||
users: 102400,
|
||||
messages: 81212,
|
||||
moneys: 9280,
|
||||
shoppings: 13600
|
||||
}
|
||||
totalState = Object.assign(totalState, data)
|
||||
}
|
||||
|
||||
// 用户来源
|
||||
const getUserAccessSource = async () => {
|
||||
const data = [
|
||||
{ value: 335, name: 'analysis.directAccess' },
|
||||
{ value: 310, name: 'analysis.mailMarketing' },
|
||||
{ value: 234, name: 'analysis.allianceAdvertising' },
|
||||
{ value: 135, name: 'analysis.videoAdvertising' },
|
||||
{ value: 1548, name: 'analysis.searchEngines' }
|
||||
]
|
||||
set(
|
||||
pieOptionsData,
|
||||
'legend.data',
|
||||
data.map((v) => t(v.name))
|
||||
)
|
||||
set(pieOptionsData, 'series.data', data)
|
||||
}
|
||||
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
|
||||
|
||||
// 周活跃量
|
||||
const getWeeklyUserActivity = async () => {
|
||||
const data = [
|
||||
{ value: 13253, name: 'analysis.monday' },
|
||||
{ value: 34235, name: 'analysis.tuesday' },
|
||||
{ value: 26321, name: 'analysis.wednesday' },
|
||||
{ value: 12340, name: 'analysis.thursday' },
|
||||
{ value: 24643, name: 'analysis.friday' },
|
||||
{ value: 1322, name: 'analysis.saturday' },
|
||||
{ value: 1324, name: 'analysis.sunday' }
|
||||
]
|
||||
set(
|
||||
barOptionsData,
|
||||
'xAxis.data',
|
||||
data.map((v) => t(v.name))
|
||||
)
|
||||
set(barOptionsData, 'series', [
|
||||
{
|
||||
name: t('analysis.activeQuantity'),
|
||||
data: data.map((v) => v.value),
|
||||
type: 'bar'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
const lineOptionsData = reactive<EChartsOption>(lineOptions) as EChartsOption
|
||||
|
||||
// 每月销售总额
|
||||
const getMonthlySales = async () => {
|
||||
const data = [
|
||||
{ estimate: 100, actual: 120, name: 'analysis.january' },
|
||||
{ estimate: 120, actual: 82, name: 'analysis.february' },
|
||||
{ estimate: 161, actual: 91, name: 'analysis.march' },
|
||||
{ estimate: 134, actual: 154, name: 'analysis.april' },
|
||||
{ estimate: 105, actual: 162, name: 'analysis.may' },
|
||||
{ estimate: 160, actual: 140, name: 'analysis.june' },
|
||||
{ estimate: 165, actual: 145, name: 'analysis.july' },
|
||||
{ estimate: 114, actual: 250, name: 'analysis.august' },
|
||||
{ estimate: 163, actual: 134, name: 'analysis.september' },
|
||||
{ estimate: 185, actual: 56, name: 'analysis.october' },
|
||||
{ estimate: 118, actual: 99, name: 'analysis.november' },
|
||||
{ estimate: 123, actual: 123, name: 'analysis.december' }
|
||||
]
|
||||
set(
|
||||
lineOptionsData,
|
||||
'xAxis.data',
|
||||
data.map((v) => t(v.name))
|
||||
)
|
||||
set(lineOptionsData, 'series', [
|
||||
{
|
||||
name: t('analysis.estimate'),
|
||||
smooth: true,
|
||||
type: 'line',
|
||||
data: data.map((v) => v.estimate),
|
||||
animationDuration: 2800,
|
||||
animationEasing: 'cubicInOut'
|
||||
},
|
||||
{
|
||||
name: t('analysis.actual'),
|
||||
smooth: true,
|
||||
type: 'line',
|
||||
itemStyle: {},
|
||||
data: data.map((v) => v.actual),
|
||||
animationDuration: 2800,
|
||||
animationEasing: 'quadraticOut'
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
const getAllApi = async () => {
|
||||
await Promise.all([getCount(), getUserAccessSource(), getWeeklyUserActivity(), getMonthlySales()])
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
getAllApi()
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
$prefix-cls: #{$namespace}-panel;
|
||||
|
||||
.#{$prefix-cls} {
|
||||
&__item {
|
||||
&--peoples {
|
||||
color: #40c9c6;
|
||||
}
|
||||
|
||||
&--message {
|
||||
color: #36a3f7;
|
||||
}
|
||||
|
||||
&--money {
|
||||
color: #f4516c;
|
||||
}
|
||||
|
||||
&--shopping {
|
||||
color: #34bfa3;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
:deep(.#{$namespace}-icon) {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.#{$prefix-cls}__item--icon {
|
||||
transition: all 0.38s ease-out;
|
||||
}
|
||||
|
||||
.#{$prefix-cls}__item--peoples {
|
||||
background: #40c9c6;
|
||||
}
|
||||
|
||||
.#{$prefix-cls}__item--message {
|
||||
background: #36a3f7;
|
||||
}
|
||||
|
||||
.#{$prefix-cls}__item--money {
|
||||
background: #f4516c;
|
||||
}
|
||||
|
||||
.#{$prefix-cls}__item--shopping {
|
||||
background: #34bfa3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
347
src/views/Home/Index3.vue
Normal file
347
src/views/Home/Index3.vue
Normal file
@@ -0,0 +1,347 @@
|
||||
<template>
|
||||
<div class="w-100%">
|
||||
<div class="flex justify-between items-center">
|
||||
<div
|
||||
class="w-[calc(50%-50px)] py-16px px-20px bg-#fff border-rd-10px b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<h5 class="text">服务器基本信息</h5>
|
||||
<div class="w-100% inline-grid grid-cols-4 gap-4 text-center">
|
||||
<div class="left-bottom-box" v-for="(item, index) in topLeftData" :key="index">
|
||||
<p>{{ item.title }}</p>
|
||||
<div>
|
||||
<span>{{ item.num }}</span> {{ item.dw }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex w-[calc(50%-50px)] px-20px bg-#fff border-rd-10px justify-between items-center b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<div class="conter-right-box" v-for="(item, index) in arr" :key="index">
|
||||
<p class="text-conter">{{ item.title }}</p>
|
||||
<div class="chart">
|
||||
<Echart :options="syl_pie_option" width="140px" height="130px"></Echart>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="conter-right-box">
|
||||
<p class="text-conter">内存使用率</p>
|
||||
<div class="chart">
|
||||
<Echart :options="syl_pie_option" width="140px" height="130px"></Echart>
|
||||
</div>
|
||||
</div>
|
||||
<div class="conter-right-box">
|
||||
<p class="text-conter">系统平均负载(1m)</p>
|
||||
<div class="chart">
|
||||
<Echart :options="syl_pie_option" width="140px" height="130px"></Echart>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between mt-20px">
|
||||
<div
|
||||
class="w-[calc(50%-50px)] bg-#fff border-rd-10px p-20px b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<Echart :options="cpu_line_option" width="100%" height="350px" />
|
||||
</div>
|
||||
<div
|
||||
class="w-[calc(50%-50px)] bg-#fff border-rd-10px p-20px b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<Echart :options="nc_line_option" width="100%" height="350px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between mt-20px">
|
||||
<div
|
||||
class="w-[calc(50%-50px)] bg-#fff border-rd-10px p-20px b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<Echart :options="ll_line_option" width="100%" height="350px" />
|
||||
</div>
|
||||
<div
|
||||
class="w-[calc(50%-50px)] bg-#fff border-rd-10px p-20px b-1px .dark:bg-#1D1E1F .dark:b-#2A2B2C .dark:b-solid"
|
||||
>
|
||||
<Echart :options="cp_line_option" width="100%" height="350px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
|
||||
import { batchGetTableList } from '@/api/design/report'
|
||||
|
||||
defineOptions({ name: 'Home3' })
|
||||
|
||||
interface TopLeftData {
|
||||
title: string
|
||||
dw: string
|
||||
dictionary: string
|
||||
num?: number
|
||||
}
|
||||
|
||||
const topLeftData = ref<TopLeftData[]>([
|
||||
{ title: '系统运行时间', dw: '天', dictionary: 'xtyxsj' },
|
||||
{ title: 'cpu核心数', dw: '', dictionary: 'cpuhxs' },
|
||||
{ title: '内存总量', dw: 'G', dictionary: 'nczl' },
|
||||
{ title: '系统平均负数', dw: '', dictionary: 'xtpjfz' }
|
||||
])
|
||||
|
||||
const arr = ref<any>([
|
||||
{ title: 'CPU使用率(1m)', dictionary: 'cpusyl' },
|
||||
{ title: '内存使用率', dictionary: 'ncsyl' },
|
||||
{ title: '系统平均负载(1m)', dictionary: 'xtpjfzl' }
|
||||
])
|
||||
|
||||
const syl_pie_option = ref<any>({
|
||||
title: { text: '50%', left: 'center', top: 'center' },
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
stillShowZeroSum: false,
|
||||
label: { show: false },
|
||||
hoverAnimation: false,
|
||||
data: [
|
||||
{ value: 100, name: 'A' },
|
||||
{ value: 0, name: 'B' }
|
||||
],
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: function (params) {
|
||||
var colors = ['#e9e9e9', '#0099ff', '#51d351']
|
||||
return colors[params.dataIndex % colors.length]
|
||||
}
|
||||
}
|
||||
},
|
||||
radius: ['50%', '70%']
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const cpuLineXAxis = ref<string[]>([])
|
||||
const cpuLineSeries = ref<string[]>([])
|
||||
const cpu_line_option = reactive<any>({
|
||||
title: {
|
||||
text: 'CPU使用率',
|
||||
textStyle: {}
|
||||
},
|
||||
tooltip: {},
|
||||
legend: { data: ['使用率'], x: 'right', selectedMode: false },
|
||||
xAxis: {
|
||||
data: cpuLineXAxis.value
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
series: [
|
||||
{
|
||||
name: '使用率',
|
||||
data: cpuLineSeries.value,
|
||||
type: 'line',
|
||||
stack: 'x',
|
||||
areaStyle: { color: '#ffd7dc' },
|
||||
itemStyle: { normal: { color: '#ffd7dc', lineStyle: { color: '#ff7a8c' } } }
|
||||
}
|
||||
]
|
||||
})
|
||||
const ncLineXAxis = ref<string[]>([])
|
||||
const ncLineSeries = ref<string[]>([])
|
||||
const nc_line_option = reactive<any>({
|
||||
title: {
|
||||
text: '内存使用率',
|
||||
textStyle: {}
|
||||
},
|
||||
tooltip: {},
|
||||
legend: { data: ['使用率'], x: 'right', selectedMode: false },
|
||||
xAxis: {
|
||||
data: ncLineXAxis.value
|
||||
},
|
||||
yAxis: { type: 'value' },
|
||||
series: [
|
||||
{
|
||||
name: '使用率',
|
||||
data: ncLineSeries.value,
|
||||
type: 'line',
|
||||
stack: 'x',
|
||||
areaStyle: { color: '#b2e0ff' },
|
||||
itemStyle: { normal: { color: '#b2e0ff', lineStyle: { color: '#0099ff' } } }
|
||||
}
|
||||
]
|
||||
})
|
||||
const llLineXAxis = ref<string[]>([])
|
||||
const llLineSeries1 = ref<string[]>([])
|
||||
const llLineSeries2 = ref<string[]>([])
|
||||
const ll_line_option = reactive<any>({
|
||||
title: {
|
||||
text: '服务器流量',
|
||||
textStyle: {}
|
||||
},
|
||||
tooltip: {},
|
||||
legend: { data: ['上传', '下载'], x: 'right', selectedMode: false },
|
||||
xAxis: { data: llLineXAxis.value },
|
||||
yAxis: { type: 'value' },
|
||||
series: [
|
||||
{
|
||||
name: '上传',
|
||||
data: llLineSeries1.value,
|
||||
type: 'line',
|
||||
// stack: 'x',
|
||||
areaStyle: { color: '#caf1ca' },
|
||||
itemStyle: { normal: { color: '#51d351', lineStyle: { color: '#51d351' } } }
|
||||
},
|
||||
{
|
||||
name: '下载',
|
||||
data: llLineSeries2.value,
|
||||
type: 'line',
|
||||
// stack: 'x',
|
||||
areaStyle: { color: '#ffe5c9' },
|
||||
itemStyle: { normal: { color: '#ffb465', lineStyle: { color: '#ffb465' } } }
|
||||
}
|
||||
]
|
||||
})
|
||||
const cpLineXAxis = ref<string[]>([])
|
||||
const cpLineSeries1 = ref<string[]>([])
|
||||
const cpLineSeries2 = ref<string[]>([])
|
||||
const cp_line_option = reactive<any>({
|
||||
title: {
|
||||
text: '服务器磁盘IO',
|
||||
textStyle: {}
|
||||
},
|
||||
tooltip: {},
|
||||
legend: { data: ['输出', '输入'], x: 'right', selectedMode: false },
|
||||
xAxis: { data: cpLineXAxis.value },
|
||||
yAxis: { type: 'value' },
|
||||
series: [
|
||||
{
|
||||
name: '输出',
|
||||
data: cpLineSeries1.value,
|
||||
type: 'line',
|
||||
// stack: 'x',
|
||||
areaStyle: { color: '#bdf1f1' },
|
||||
itemStyle: { normal: { color: '#78e3e4', lineStyle: { color: '#78e3e4' } } }
|
||||
},
|
||||
{
|
||||
name: '输入',
|
||||
data: cpLineSeries2.value,
|
||||
type: 'line',
|
||||
// stack: 'x',
|
||||
areaStyle: { color: '#d9d1fc' },
|
||||
itemStyle: { normal: { color: '#8167f5', lineStyle: { color: '#8167f5' } } }
|
||||
}
|
||||
]
|
||||
})
|
||||
const textStyle = reactive({
|
||||
color: ''
|
||||
})
|
||||
const appStore = useAppStore()
|
||||
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList(
|
||||
'example_systemmonitor_server_information,example_systemmonitor_cpu_utilization,example_systemmonitor_memory_utilization,example_systemmonitor_server_traffic,example_systemmonitor_disk_io'
|
||||
)
|
||||
|
||||
let serverInformation = oneres.example_systemmonitor_server_information.records[0]
|
||||
topLeftData.value = topLeftData.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
num: serverInformation[item.dictionary]
|
||||
})
|
||||
})
|
||||
arr.value = arr.value.map((item) => {
|
||||
syl_pie_option.value.title.text = serverInformation[item.dictionary] + '%'
|
||||
syl_pie_option.value.series[0].data[1].value = serverInformation[item.dictionary]
|
||||
return item
|
||||
})
|
||||
//CPU使用率
|
||||
let cpuUtilization = oneres.example_systemmonitor_cpu_utilization.records
|
||||
cpuUtilization.forEach((ele) => {
|
||||
cpuLineXAxis.value.push(ele.sj)
|
||||
cpuLineSeries.value.push(ele.syl)
|
||||
})
|
||||
//内存使用率
|
||||
let memoryUtilization = oneres.example_systemmonitor_memory_utilization.records
|
||||
memoryUtilization.forEach((ele) => {
|
||||
ncLineXAxis.value.push(ele.sj)
|
||||
ncLineSeries.value.push(ele.syl)
|
||||
})
|
||||
//服务器流量
|
||||
let serverTraffic = oneres.example_systemmonitor_server_traffic.records
|
||||
serverTraffic.forEach((ele) => {
|
||||
llLineXAxis.value.push(ele.sj)
|
||||
llLineSeries1.value.push(ele.sc)
|
||||
llLineSeries2.value.push(ele.xz)
|
||||
})
|
||||
//服务器磁盘IO
|
||||
let diskIo = oneres.example_systemmonitor_disk_io.records
|
||||
diskIo.forEach((ele) => {
|
||||
cpLineXAxis.value.push(ele.sj)
|
||||
cpLineSeries1.value.push(ele.sc)
|
||||
cpLineSeries2.value.push(ele.sr)
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await init()
|
||||
// 判断是否为暗色模式
|
||||
const { wsCache } = useCache()
|
||||
if (wsCache.get(CACHE_KEY.IS_DARK)) {
|
||||
textStyle.color = '#E5EAF3'
|
||||
cpu_line_option.title.textStyle = textStyle
|
||||
nc_line_option.title.textStyle = textStyle
|
||||
ll_line_option.title.textStyle = textStyle
|
||||
cp_line_option.title.textStyle = textStyle
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => appStore.isDark,
|
||||
(val) => {
|
||||
if (val) {
|
||||
textStyle.color = '#E5EAF3'
|
||||
} else {
|
||||
textStyle.color = 'black'
|
||||
}
|
||||
cpu_line_option.title.textStyle = textStyle
|
||||
nc_line_option.title.textStyle = textStyle
|
||||
ll_line_option.title.textStyle = textStyle
|
||||
cp_line_option.title.textStyle = textStyle
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
h5,
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.conter-right-box {
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
|
||||
.text-conter {
|
||||
margin-top: 15px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.left-bottom-box {
|
||||
margin: 20px 0;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
601
src/views/Home/Index4.vue
Normal file
601
src/views/Home/Index4.vue
Normal file
@@ -0,0 +1,601 @@
|
||||
<template>
|
||||
<div class="w-100%">
|
||||
<div class="w-100% flex gap-x-20px">
|
||||
<div class="el-card top-card">
|
||||
<div class="card-box">
|
||||
<div class="text text-gray-500">月销售金额(元)</div>
|
||||
<Icon color="#bdbdbd" class="cursor-pointer" icon="quill:warning-alt" />
|
||||
</div>
|
||||
<span class="text-value">
|
||||
<avue-count-up :end="topList?.yxsje.value"></avue-count-up>
|
||||
</span>
|
||||
<div class="card-box mt-20px">
|
||||
<div class="text">
|
||||
<span class="mr-5px text-gray-500">周同比</span>
|
||||
<Icon
|
||||
v-if="topList?.yxsje.ztbType == 'top'"
|
||||
:size="12"
|
||||
color="#F56C6C"
|
||||
icon="ep:caret-top"
|
||||
></Icon>
|
||||
<Icon
|
||||
v-else-if="topList?.yxsje.ztbType == 'bottom'"
|
||||
:size="12"
|
||||
color="#19BE6B"
|
||||
icon="ep:caret-bottom"
|
||||
></Icon>
|
||||
<span>{{ topList?.yxsje.ztb }}</span>
|
||||
</div>
|
||||
<div class="text">
|
||||
<span class="mr-5px text-gray-500">日环比</span>
|
||||
<Icon
|
||||
v-if="topList?.yxsje.rhbType == 'top'"
|
||||
:size="12"
|
||||
color="#F56C6C"
|
||||
icon="ep:caret-top"
|
||||
></Icon>
|
||||
<Icon
|
||||
v-else-if="topList?.yxsje.rhbType == 'bottom'"
|
||||
:size="12"
|
||||
color="#19BE6B"
|
||||
icon="ep:caret-bottom"
|
||||
></Icon>
|
||||
<span>{{ topList?.yxsje.rhb }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-card top-card">
|
||||
<div class="card-box">
|
||||
<div class="text text-gray-500">月回款金额(元)</div>
|
||||
<Icon color="#bdbdbd" class="cursor-pointer" icon="quill:warning-alt" />
|
||||
</div>
|
||||
<span class="text-value">
|
||||
<avue-count-up :end="topList?.yhkje.value"></avue-count-up>
|
||||
</span>
|
||||
<div class="card-box w-[calc(100%+20px)]! ml--10px">
|
||||
<div class="pos-relative w-100%">
|
||||
<Echart
|
||||
class="w-100% mt-10px pos-absolute left-0 top--30px"
|
||||
:options="returned_money_option"
|
||||
width="100%"
|
||||
height="60px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-card top-card">
|
||||
<div class="card-box">
|
||||
<div class="text text-gray-500">本月成交订单</div>
|
||||
<Icon color="#bdbdbd" class="cursor-pointer" icon="quill:warning-alt" />
|
||||
</div>
|
||||
<span class="text-value">
|
||||
<avue-count-up :end="topList?.bycjdd.value"></avue-count-up>
|
||||
</span>
|
||||
<div class="card-box w-[calc(100%+20px)]! ml--10px">
|
||||
<div class="pos-relative w-100%">
|
||||
<Echart
|
||||
class="w-100% mt-10px pos-absolute left-0 top--30px"
|
||||
:options="submit_order_option"
|
||||
width="100%"
|
||||
height="60px"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-card top-card pos-relative">
|
||||
<div class="card-box">
|
||||
<div class="text text-gray-500">完成销售目标</div>
|
||||
<Icon class="cursor-pointer" color="#bdbdbd" icon="quill:warning-alt" />
|
||||
</div>
|
||||
<div class="text-value">{{ topList?.wcxsmb.value }}%</div>
|
||||
<div class="pos-absolute right-30px top-50px">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="completeValue"
|
||||
:stroke-width="9"
|
||||
:width="60"
|
||||
:show-text="false"
|
||||
:indeterminate="true"
|
||||
></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="el-card top-card">
|
||||
<div class="card-box">
|
||||
<div class="text text-gray-500">回款达成率</div>
|
||||
<Icon color="#bdbdbd" class="cursor-pointer" icon="quill:warning-alt" />
|
||||
</div>
|
||||
<div class="text-value mb-30px!">{{ topList?.hkdcl.value }}%</div>
|
||||
<el-progress
|
||||
:percentage="returnedValue"
|
||||
:stroke-width="9"
|
||||
:show-text="false"
|
||||
class="jdt"
|
||||
></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100% flex gap-x-20px">
|
||||
<div class="flex-grow-3 flex-shrink flex-basis-0">
|
||||
<el-card header="数据简报">
|
||||
<div class="data-bulletin grid grid-cols-4 gap-y-4 text-center py-10px">
|
||||
<template v-for="(item, index) in dataBulletin" :key="index">
|
||||
<div class="p-14px">
|
||||
<div class="text-gray-500 text-14px">{{ item.label }}</div>
|
||||
<div class="text-28px fw-bold c-#666 dark:c-[var(--el-text-color-primary)]">
|
||||
<avue-count-up :end="item.value"></avue-count-up>
|
||||
</div>
|
||||
<div :style="{ color: item.type == 'pos' ? '#19BE6B' : '#F56C6C' }"
|
||||
>{{ item.type == 'pos' ? '+' : '-' }}{{ item.percent }}</div
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="业绩目标">
|
||||
<Echart :options="target_bar_option" width="100%" height="350px" />
|
||||
</el-card>
|
||||
<el-card header="销售预测">
|
||||
<Echart :options="forecast_bar_option" width="100%" height="350px" />
|
||||
</el-card>
|
||||
<el-card header="销售漏斗">
|
||||
<div id="forecast-funnel-chart" class="w-100% h-350px"></div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="flex-grow-2 flex-shrink flex-basis-0">
|
||||
<el-card header="销售排名">
|
||||
<div class="ranking-box">
|
||||
<div class="flex items-center gap-x-10px text-left text-12px c-#999 px-14px mb-10px">
|
||||
<div v-for="(item, index) in rankingTopList" :key="index" :class="item.width">{{
|
||||
item.label
|
||||
}}</div>
|
||||
</div>
|
||||
<template v-for="(item, index) in rankingList" :key="index">
|
||||
<div
|
||||
class="flex items-center gap-x-10px text-left text-12px c-#666 p-14px b-0 b-b-1px b-[var(--el-card-border-color)] b-solid"
|
||||
>
|
||||
<div class="w-10% text-left">
|
||||
<div
|
||||
class="w-23px h-23px text-center line-height-23px bg-#ccc border-rd-4px c-#fff"
|
||||
:style="index < 3 ? { background: '#ff9900' } : ''"
|
||||
>{{ index + 1 }}</div
|
||||
>
|
||||
</div>
|
||||
<div class="w-20%">{{ item.name }}</div>
|
||||
<div class="w-25%">{{ item.money }}</div>
|
||||
<div class="w-45%">
|
||||
<el-progress
|
||||
:percentage="item.percent"
|
||||
:stroke-width="8"
|
||||
:color="rankingColor[index] || '#409EFF'"
|
||||
></el-progress>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="快捷菜单">
|
||||
<div class="fast-menu-box grid grid-cols-3 gap-y-20px c-#666 dark:c-#cfd3dc">
|
||||
<template v-for="(item, index) in fastMenuList" :key="index">
|
||||
<div
|
||||
class="flex justify-center items-center flex-col hover:bg-#f1f1f1 hover:b-#dedddd! hover:dark:bg-#1e1e1e cursor-pointer"
|
||||
>
|
||||
<div class="h-70px w-70px flex justify-center items-center">
|
||||
<Icon :icon="item.icon" :size="item.size"></Icon>
|
||||
</div>
|
||||
<div class="mt-4px text-12px">{{ item.label }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card header="系统通知">
|
||||
<div class="notifier-box">
|
||||
<template v-for="(item, index) in notifierList" :key="index">
|
||||
<div class="flex items-center py-12px px-10px">
|
||||
<div class="bg-#F56C6C w-4px h-4px border-rd-50% flex-shrink-0"></div>
|
||||
<div class="text-14px flex-1 ml-5px mr-20px">{{ item.label }}</div>
|
||||
<div class="text-gray-500 text-12px flex-shrink-0">{{ item.time }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from 'echarts'
|
||||
import { batchGetTableList } from '@/api/design/report'
|
||||
|
||||
defineOptions({ name: 'Home4' })
|
||||
|
||||
interface TopList {
|
||||
bycjdd: {
|
||||
data: number[]
|
||||
value: string
|
||||
}
|
||||
hkdcl: {
|
||||
value: number
|
||||
}
|
||||
wcxsmb: {
|
||||
value: number
|
||||
}
|
||||
yhkje: {
|
||||
data: number[]
|
||||
value: string
|
||||
}
|
||||
yxsje: {
|
||||
value: string
|
||||
rhb: string
|
||||
rhbType: string
|
||||
ztb: string
|
||||
ztbType: string
|
||||
}
|
||||
}
|
||||
interface DataBulletin {
|
||||
label: string
|
||||
dictionary: string
|
||||
value?: string
|
||||
percent?: string
|
||||
type?: string
|
||||
}
|
||||
interface RankingList {
|
||||
name: string
|
||||
money: string
|
||||
percent: number
|
||||
}
|
||||
interface RankingTopList {
|
||||
label: string
|
||||
width: string
|
||||
}
|
||||
interface SalesTarget {
|
||||
cjje: string
|
||||
sj: string
|
||||
mbje: string
|
||||
}
|
||||
interface SalesForecast {
|
||||
yjxsje: string
|
||||
sj: string
|
||||
glje: string
|
||||
}
|
||||
interface SalesFunnelgraphic {
|
||||
dictionary: string
|
||||
name: string
|
||||
value?: number
|
||||
}
|
||||
interface NotifierList {
|
||||
label: string
|
||||
time: string
|
||||
}
|
||||
|
||||
let topList = ref<TopList>()
|
||||
|
||||
let returned_money_option = ref({
|
||||
grid: { bottom: '60%', containLabel: false },
|
||||
xAxis: {
|
||||
show: false,
|
||||
type: 'category',
|
||||
boundaryGap: false
|
||||
},
|
||||
yAxis: {
|
||||
show: false,
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: topList.value?.yhkje.data,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
color: '#FF7A8C'
|
||||
},
|
||||
lineStyle: {
|
||||
color: '#FF7A8C'
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const submit_order_option = ref({
|
||||
grid: { bottom: '60%', containLabel: false },
|
||||
xAxis: {
|
||||
show: false,
|
||||
type: 'category'
|
||||
},
|
||||
yAxis: {
|
||||
show: false,
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: topList.value?.bycjdd.data,
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
color: '#52C1F5'
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
const completeValue = ref(0)
|
||||
const returnedValue = ref(0)
|
||||
|
||||
const dataBulletin = ref<DataBulletin[]>([
|
||||
{ label: '新增客户', dictionary: 'xzkh' },
|
||||
{ label: '新增线索', dictionary: 'xzxs' },
|
||||
{ label: '新增商机', dictionary: 'xzsj' },
|
||||
{ label: '新增订单', dictionary: 'xzdd' },
|
||||
{ label: '新增联系人', dictionary: 'xnlxr' },
|
||||
{ label: '跟进次数', dictionary: 'gjcs' },
|
||||
{ label: '处理任务', dictionary: 'clrw' },
|
||||
{ label: '处理工单', dictionary: 'clgd' }
|
||||
])
|
||||
|
||||
const salesTarget = ref<SalesTarget[]>()
|
||||
let salesTargetXAxis = ref<string[]>([])
|
||||
let salesTargetSeries1 = ref<string[]>([])
|
||||
let salesTargetSeries2 = ref<string[]>([])
|
||||
const target_bar_option = ref({
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { data: ['目标金额', '成交金额'] },
|
||||
xAxis: {
|
||||
data: salesTargetXAxis.value
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '目标金额',
|
||||
type: 'bar',
|
||||
data: salesTargetSeries1.value,
|
||||
color: '#6CCAF6'
|
||||
},
|
||||
{
|
||||
name: '成交金额',
|
||||
type: 'bar',
|
||||
data: salesTargetSeries2.value,
|
||||
color: '#93D99A'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const salesForecast = ref<SalesForecast[]>()
|
||||
let salesForecastXAxis = ref<string[]>([])
|
||||
let salesForecastSeries1 = ref<string[]>([])
|
||||
let salesForecastSeries2 = ref<string[]>([])
|
||||
const forecast_bar_option = ref({
|
||||
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { data: ['预计销售金额', '概率金额'] },
|
||||
xAxis: {
|
||||
data: salesForecastXAxis.value
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '预计销售金额',
|
||||
type: 'bar',
|
||||
data: salesForecastSeries1.value,
|
||||
color: '#FF8E9D'
|
||||
},
|
||||
{
|
||||
name: '概率金额',
|
||||
type: 'bar',
|
||||
data: salesForecastSeries2.value,
|
||||
color: '#88AEFB'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const salesFunnelgraphic = ref<SalesFunnelgraphic[]>([
|
||||
{ name: '初步洽谈', dictionary: 'cbqt' },
|
||||
{ name: '深入沟通', dictionary: 'srgt' },
|
||||
{ name: '产品报价', dictionary: 'cpbj' },
|
||||
{ name: '成交商机', dictionary: 'cjsj' },
|
||||
{ name: '流失商机', dictionary: 'lssj' }
|
||||
])
|
||||
const forecast_funnel_option = ref({
|
||||
title: {
|
||||
text: ''
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c}%'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Funnel',
|
||||
type: 'funnel',
|
||||
width: '90%',
|
||||
height: '100%',
|
||||
left: '5%',
|
||||
top: '3%',
|
||||
label: {
|
||||
position: 'right'
|
||||
},
|
||||
data: salesFunnelgraphic.value
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const rankingColor = ref(['#FB6260', '#FFA94C', '#4BCED0'])
|
||||
|
||||
const rankingTopList = ref<RankingTopList[]>([
|
||||
{
|
||||
label: '排名',
|
||||
width: 'w-10%'
|
||||
},
|
||||
{
|
||||
label: '姓名',
|
||||
width: 'w-20%'
|
||||
},
|
||||
{
|
||||
label: '销售金额',
|
||||
width: 'w-25%'
|
||||
},
|
||||
{
|
||||
label: '完成目标',
|
||||
width: 'w-45%'
|
||||
}
|
||||
])
|
||||
const rankingList = ref<RankingList[]>()
|
||||
|
||||
const fastMenuList = ref([
|
||||
{ label: '客户管理', size: 65, icon: 'la:user-tie' },
|
||||
{ label: '线索管理', size: 55, icon: 'akar-icons:light-bulb' },
|
||||
{ label: '商机管理', size: 55, icon: 'hugeicons:money-add-01' },
|
||||
{ label: '联系人管理', size: 45, icon: 'uiw:user' },
|
||||
{ label: '写新跟进', size: 55, icon: 'ph:pen' },
|
||||
{ label: '回款管理', size: 55, icon: 'fluent:calendar-reply-32-light' },
|
||||
{ label: '发票管理', size: 55, icon: 'hugeicons:invoice-01' },
|
||||
{ label: '费用管理', size: 50, icon: 'teenyicons:cost-estimate-outline' },
|
||||
{ label: '报销管理', size: 55, icon: 'hugeicons:money-bag-02' },
|
||||
{ label: '工作报告', size: 55, icon: 'line-md:document-report' },
|
||||
{ label: '工单管理', size: 60, icon: 'material-symbols-light:order-approve-outline-sharp' },
|
||||
{ label: '产品管理', size: 55, icon: 'fluent-mdl2:product' }
|
||||
])
|
||||
|
||||
const notifierList = ref<NotifierList[]>()
|
||||
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList(
|
||||
'example_client_month_data,example_client_data_briefs,example_client_salesman_rank,example_client_sales_target'
|
||||
)
|
||||
|
||||
topList.value = oneres.example_client_month_data.records[0]
|
||||
returned_money_option.value.series[0].data = topList.value?.yhkje.data
|
||||
submit_order_option.value.series[0].data = topList.value?.bycjdd.data
|
||||
completeValue.value = topList.value?.wcxsmb.value || 0
|
||||
returnedValue.value = topList.value?.hkdcl.value || 0
|
||||
dataBulletin.value = dataBulletin.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
...oneres.example_client_data_briefs.records[0][item.dictionary]
|
||||
})
|
||||
})
|
||||
rankingList.value = oneres.example_client_salesman_rank.records
|
||||
salesTarget.value = oneres.example_client_sales_target.records
|
||||
salesTarget.value?.forEach((ele) => {
|
||||
salesTargetXAxis.value.push(ele.sj)
|
||||
salesTargetSeries1.value.push(ele.mbje)
|
||||
salesTargetSeries2.value.push(ele.cjje)
|
||||
})
|
||||
target_bar_option.value.xAxis.data = salesTargetXAxis.value
|
||||
target_bar_option.value.series[0].data = salesTargetSeries1.value
|
||||
target_bar_option.value.series[1].data = salesTargetSeries2.value
|
||||
|
||||
let endres = await batchGetTableList(
|
||||
'example_client_sales_forecast,example_client_sales_funnelgraphic,example_client_system_notification'
|
||||
)
|
||||
salesForecast.value = endres.example_client_sales_forecast.records
|
||||
salesForecast.value?.forEach((ele) => {
|
||||
salesForecastXAxis.value.push(ele.sj)
|
||||
salesForecastSeries1.value.push(ele.yjxsje)
|
||||
salesForecastSeries2.value.push(ele.glje)
|
||||
})
|
||||
forecast_bar_option.value.xAxis.data = salesForecastXAxis.value
|
||||
forecast_bar_option.value.series[0].data = salesForecastSeries1.value
|
||||
forecast_bar_option.value.series[1].data = salesForecastSeries2.value
|
||||
|
||||
salesFunnelgraphic.value = salesFunnelgraphic.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
value: endres.example_client_sales_funnelgraphic.records[0][item.dictionary]
|
||||
})
|
||||
})
|
||||
forecast_funnel_option.value.series[0].data = salesFunnelgraphic.value
|
||||
notifierList.value = endres.example_client_system_notification.records
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await init()
|
||||
let xsldId = document.getElementById('forecast-funnel-chart')
|
||||
if (xsldId) {
|
||||
let forecastFunnelChart = echarts.init(xsldId)
|
||||
forecastFunnelChart.setOption(forecast_funnel_option.value)
|
||||
}
|
||||
|
||||
const timer_1 = setInterval(() => {
|
||||
completeValue.value = completeValue.value + 10
|
||||
if (completeValue.value >= 75) {
|
||||
completeValue.value = 75
|
||||
clearInterval(timer_1)
|
||||
}
|
||||
}, 20)
|
||||
const timer_2 = setInterval(() => {
|
||||
returnedValue.value = returnedValue.value + 10
|
||||
if (returnedValue.value >= 80) {
|
||||
returnedValue.value = 80
|
||||
clearInterval(timer_2)
|
||||
}
|
||||
}, 20)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.top-card {
|
||||
position: relative;
|
||||
padding: 15px;
|
||||
margin-top: 0 !important;
|
||||
border-radius: 10px;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
flex: 1;
|
||||
|
||||
.card-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
|
||||
.text-value {
|
||||
margin-bottom: 15px;
|
||||
font-size: 30px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.text-value {
|
||||
margin-bottom: 15px;
|
||||
font-size: 28px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep(.el-card) {
|
||||
margin-top: 20px;
|
||||
border-radius: 8px;
|
||||
|
||||
.el-card__header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
.data-bulletin {
|
||||
& > div {
|
||||
border-right: 1px solid var(--el-card-border-color);
|
||||
|
||||
&:nth-child(4n) {
|
||||
border-right: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ranking-box {
|
||||
.el-progress__text {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.fast-menu-box > div {
|
||||
padding: 10px 0;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.notifier-box > div {
|
||||
border-bottom: 1px solid var(--el-card-border-color);
|
||||
}
|
||||
|
||||
.notifier-box > div:nth-child(1) {
|
||||
padding-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1102
src/views/Home/Index5.vue
Normal file
1102
src/views/Home/Index5.vue
Normal file
File diff suppressed because it is too large
Load Diff
913
src/views/Home/Index6.vue
Normal file
913
src/views/Home/Index6.vue
Normal file
@@ -0,0 +1,913 @@
|
||||
<template>
|
||||
<div class="w-100%">
|
||||
<div class="w-100% top-box">
|
||||
<div
|
||||
class="top-card bg-#fff .dark:bg-#1D1E1F! b-1px b-transparent .dark:b-#2A2B2C b-solid"
|
||||
v-for="(item, index) in topCardList"
|
||||
:class="item.border"
|
||||
:key="index"
|
||||
>
|
||||
<div class="card-box">
|
||||
<div class="title">{{ item.title }}</div>
|
||||
<Icon
|
||||
icon="akar-icons:info-fill"
|
||||
width="48"
|
||||
height="48"
|
||||
class="cursor-pointer"
|
||||
style="color: #bdbdbd"
|
||||
/>
|
||||
</div>
|
||||
<span class="text-value .dark:c-#fff!">
|
||||
<span v-if="item.unit == '¥'">{{ item.unit }}</span>
|
||||
|
||||
<avue-count-up :end="item.num"></avue-count-up>
|
||||
<span v-if="item.unit == '家'" class="text-dw">{{ item.unit }}</span>
|
||||
</span>
|
||||
<div class="card-box mt-10px">
|
||||
<div class="" style="display: flex; align-items: center; height: 12px">
|
||||
<span v-if="item.type == 'pos'" class="icon">
|
||||
<Icon icon="ep:top" width="12" height="12" style="color: #f56c6c" />
|
||||
</span>
|
||||
<span v-else-if="item.type == 'neg'" class="icons">
|
||||
<Icon icon="ep:bottom" width="12" height="12" style="color: #19be6b" />
|
||||
</span>
|
||||
<span
|
||||
class="text-ts"
|
||||
:class="item.type == 'pos' ? 'text-zeng' : item.type == 'neg' ? 'text-jian' : ''"
|
||||
>{{ item.percentage }}</span
|
||||
>
|
||||
<span class="mr-5px text"> {{ item.tendency }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="content-left">
|
||||
<p class="content-title .dark:c-#fff!">商户外拓</p>
|
||||
<div class="jdt" v-for="(item, index) in jdtData" :key="index">
|
||||
<div class="jdt-top">
|
||||
<div style="display: flex; align-items: center" class="jdt-top-text">
|
||||
<span class="acitive" :class="'bj' + (index >= 3 ? 0 : index)"></span>
|
||||
{{ item.title }}
|
||||
</div>
|
||||
<div class=".dark:c-#fff!">
|
||||
<span class="num .dark:c-#fff!">{{ item.leftNum }}</span>
|
||||
<span class="num" style="font-size: 14px; font-weight: 400"
|
||||
>/{{ item.rightNum }}</span
|
||||
>
|
||||
<span class="jdt-top-text .dark:c-#fff!">{{ item.dw }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="jdt-bottom demo-progress">
|
||||
<el-progress
|
||||
:text-inside="true"
|
||||
:stroke-width="12"
|
||||
:percentage="item.jd"
|
||||
:status="item.type"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-center">
|
||||
<p class="content-title .dark:c-#fff!">商户分布</p>
|
||||
<div id="main" style="width: 380px; height: 300px"></div>
|
||||
</div>
|
||||
<div class="content-right">
|
||||
<p class="content-title .dark:c-#fff!">交易漏斗</p>
|
||||
<div id="ldMain" style="width: 380px; height: 280px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="eCharts">
|
||||
<div
|
||||
class="eCharts-left .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent .dark:c-#fff!"
|
||||
>
|
||||
<div class="eCharts-title .dark:c-#fff!">
|
||||
<p>日交易额</p>
|
||||
<p style="font-size: 14px" class="font">¥6,000,000</p>
|
||||
</div>
|
||||
<div id="zxtMain" style="width: 380px; height: 300px"></div>
|
||||
</div>
|
||||
<div class="eCharts-center .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="eCharts-title .dark:c-#fff!">
|
||||
<p>周订单量</p>
|
||||
<p style="font-size: 16px" class="font">10,000<span class="fontFamily">单</span></p>
|
||||
</div>
|
||||
<div id="zddlMain" style="width: 380px; height: 300px"></div>
|
||||
</div>
|
||||
<div
|
||||
class="eCharts-right .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent"
|
||||
style="position: relative"
|
||||
>
|
||||
<div style="position: absolute">
|
||||
<div class="eCharts-title .dark:c-#fff! w-100%">
|
||||
<p>开拓商家</p>
|
||||
<p style="margin-left: 235px; font-size: 14px">1,000家</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ktsjMain" style="width: 360px; height: 335px" class=".dark:c-#fff!"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="eCharts-cjje .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="cjje-top">
|
||||
<div class="cjje-top-left .dark:c-#fff!">成交金额趋势</div>
|
||||
<div class="cjje-top-right">
|
||||
<el-radio-group v-model="tabPosition" style="margin-bottom: 30px">
|
||||
<el-radio-button
|
||||
v-for="(item, index) in cjjeTabList"
|
||||
:key="index"
|
||||
:value="item.label"
|
||||
@change="clickCjje(item.type)"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
</div>
|
||||
<div id="cjjeMain" style="width: 1400px; height: 300px"></div>
|
||||
</div>
|
||||
<div
|
||||
class="eCharts-cjje .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent"
|
||||
style="padding-top: 0"
|
||||
>
|
||||
<div class="cjje-top">
|
||||
<div class="cjje-top-left .dark:c-#fff!" style="height: 60px; line-height: 60px">
|
||||
成交金额趋势
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Table></Table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from 'echarts'
|
||||
import Table from './components/table.vue'
|
||||
import { getTableList, batchGetTableList } from '@/api/design/report'
|
||||
|
||||
defineOptions({ name: 'Home6' })
|
||||
|
||||
interface TopCardList {
|
||||
dictionary: string
|
||||
border: string
|
||||
tendency: string
|
||||
title: string
|
||||
unit: string
|
||||
type?: string
|
||||
num?: string
|
||||
percentage?: string
|
||||
}
|
||||
|
||||
interface JdtData {
|
||||
dictionary: string
|
||||
title: string
|
||||
dw: string
|
||||
jd?: number
|
||||
type: any
|
||||
leftNum?: number
|
||||
rightNum?: number
|
||||
}
|
||||
|
||||
interface OptionSeriesData {
|
||||
name: string
|
||||
value: number
|
||||
}
|
||||
|
||||
type Ktsj = [string, string | number, string | number]
|
||||
|
||||
let topCardList = ref<TopCardList[]>([
|
||||
{ title: '商户总数', dictionary: 'shzs', tendency: '环比上周', border: '', unit: '家' },
|
||||
{ title: '开拓中商户', dictionary: 'ktzsh', tendency: '环比上周', border: '', unit: '家' },
|
||||
{ title: '总访问量', dictionary: 'zfwl', tendency: '环比上周', border: '', unit: '' },
|
||||
{ title: '总交易额', dictionary: 'zjye', tendency: '环比上周', border: '', unit: '¥' },
|
||||
{ title: '总订单量', dictionary: 'zddl', tendency: '环比上周', border: '', unit: '' },
|
||||
{ title: '客单价', dictionary: 'kdj', tendency: '环比上周', border: '', unit: '¥' }
|
||||
])
|
||||
|
||||
const jdtData = ref<JdtData[]>([
|
||||
{ title: '已计划', dictionary: 'yjh', dw: '家', type: '' },
|
||||
{ title: '已完成', dictionary: 'ywc', dw: '家', type: 'exception' },
|
||||
{ title: '开拓中', dictionary: 'ktz', dw: '家', type: 'warning' },
|
||||
{ title: '洽谈中', dictionary: 'qtz', dw: '家', type: '' }
|
||||
])
|
||||
|
||||
//环形图
|
||||
let currentIndex = ref(0) // 当前高亮图形在饼图数据中的下标
|
||||
const highlightPie = (option, myChart) => {
|
||||
// 遍历饼图数据,取消所有图形的高亮效果
|
||||
for (var idx in option) {
|
||||
myChart.dispatchAction({
|
||||
type: 'downplay',
|
||||
seriesIndex: 0,
|
||||
dataIndex: idx
|
||||
})
|
||||
}
|
||||
// 高亮当前图形
|
||||
myChart.dispatchAction({
|
||||
type: 'highlight',
|
||||
seriesIndex: 0,
|
||||
dataIndex: currentIndex.value
|
||||
})
|
||||
|
||||
}
|
||||
// 饼图自动轮播
|
||||
const handleChartLoop = (option, myChart) => {
|
||||
if (!myChart) {
|
||||
return
|
||||
}
|
||||
highlightPie(option, myChart)
|
||||
// 用户鼠标悬浮到某一图形时,高亮鼠标悬浮的图形
|
||||
myChart.on('mouseover', (params) => {
|
||||
currentIndex.value = params.dataIndex
|
||||
highlightPie(option, myChart)
|
||||
})
|
||||
}
|
||||
let optionSeriesData = ref<OptionSeriesData[]>([])
|
||||
const option = reactive({
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
left: 'right',
|
||||
orient: 'vertical',
|
||||
align: 'left',
|
||||
top: 'center',
|
||||
icon: 'circle',
|
||||
itemGap: 25,
|
||||
// 图例文本格式化
|
||||
formatter: function (name) {
|
||||
// 在这里可以获取到对应数据项的值
|
||||
var data = optionSeriesData.value
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
if (data[i].name === name) {
|
||||
return name + ' ' + data[i].value
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
},
|
||||
color: ['#50b5ff', '#ffc542', '#ff7474', '#50b5ff', '#8167f5'],
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
formatter: '{d}%\n\n{b}',
|
||||
fontSize: 20
|
||||
},
|
||||
legendHoverLink: false,
|
||||
center: ['30%', '45%'],
|
||||
data: [],
|
||||
labelLine: {
|
||||
show: false // 关闭指示线
|
||||
},
|
||||
radius: ['48%', '70%'],
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//漏斗
|
||||
const ldOption = reactive({
|
||||
grid: {
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
containLabel: true
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
type: 'funnel',
|
||||
left: '10%',
|
||||
top: 20,
|
||||
bottom: 60,
|
||||
width: '75%',
|
||||
min: 0,
|
||||
max: 50000,
|
||||
minSize: '30%',
|
||||
maxSize: '70%',
|
||||
sort: 'descending',
|
||||
gap: 0,
|
||||
color: ['#5b8ff9', '#5ad8a6', '#5d7092', '#f6bd16'],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inside',
|
||||
formatter: '{b} : {c}'
|
||||
},
|
||||
itemStyle: {
|
||||
borderWidth: 0
|
||||
},
|
||||
data: []
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//日交易额
|
||||
let dailyTurnoverXAxis = ref<string[]>([])
|
||||
let dailyTurnoverSeries = ref<number[]>([])
|
||||
const zxtOption = reactive({
|
||||
grid: {
|
||||
top: '10%', // 调整顶部的空白间距,也可以使用像素值,例如 '50px'
|
||||
bottom: '20%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: dailyTurnoverXAxis.value,
|
||||
axisTick: {
|
||||
show: false // 设置X轴不显示刻度
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
offset: -7,
|
||||
max: '50000',
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
fontSize: 12 // 增大字体大小
|
||||
}
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: dailyTurnoverSeries.value,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
smooth: false, // 是否平滑曲线显示
|
||||
lineStyle: {
|
||||
color: '#51d351', // 折线颜色
|
||||
width: 2 // 折线宽度
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 周订单量
|
||||
let weeklyOrdersXAxis = ref<string[]>([])
|
||||
let weeklyOrdersSeries = ref<number[]>([])
|
||||
const zddlOption = reactive({
|
||||
grid: {
|
||||
top: '10%', // 调整顶部的空白间距,也可以使用像素值,例如 '50px'
|
||||
bottom: '20%'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: weeklyOrdersXAxis.value,
|
||||
axisTick: {
|
||||
show: false // 设置X轴不显示刻度
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: weeklyOrdersSeries.value,
|
||||
type: 'bar',
|
||||
barWidth: '35%',
|
||||
itemStyle: {
|
||||
// 设置柱形图的颜色
|
||||
color: '#409eff',
|
||||
borderRadius: [4, 4, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//开拓商家
|
||||
let expansionNumberDataset = ref<Ktsj[]>([['product', '目标开拓数', '实际开拓数']])
|
||||
const ktsjOption = reactive({
|
||||
theme: 'dark',
|
||||
grid: {
|
||||
top: '15%', // 调整顶部的空白间距,也可以使用像素值,例如 '50px'
|
||||
bottom: '20%'
|
||||
},
|
||||
legend: {
|
||||
icon: 'circle' // 设置图例标记为圆形
|
||||
},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: expansionNumberDataset.value
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisTick: {
|
||||
show: false // 设置X轴不显示刻度
|
||||
}
|
||||
},
|
||||
yAxis: {},
|
||||
// Declare several bar series, each will be mapped
|
||||
// to a column of dataset.source by default.
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '20%',
|
||||
itemStyle: {
|
||||
// 设置柱形图的颜色
|
||||
color: '#52c1f5',
|
||||
borderRadius: [4, 4, 0, 0]
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
barWidth: '20%',
|
||||
itemStyle: {
|
||||
// 设置柱形图的颜色
|
||||
color: '#ff7a8c',
|
||||
borderRadius: [5, 5, 0, 0]
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//成交金额趋势
|
||||
const tabPosition = ref('最近1周')
|
||||
const cjjeTabList = ref([
|
||||
{
|
||||
label: '最近1周',
|
||||
type: 1
|
||||
},
|
||||
{
|
||||
label: '最近30天',
|
||||
type: 2
|
||||
},
|
||||
{
|
||||
label: '最近半年',
|
||||
type: 3
|
||||
},
|
||||
{
|
||||
label: '最近1年',
|
||||
type: 4
|
||||
}
|
||||
])
|
||||
let transactionAmountXAxis = ref<string[]>([])
|
||||
let transactionAmountSeries1 = ref<string[]>([])
|
||||
let transactionAmountSeries2 = ref<string[]>([])
|
||||
const cjjeOption = ref({
|
||||
grid: {
|
||||
left: '4%',
|
||||
top: '5%', // 调整顶部的空白间距,也可以使用像素值,例如 '50px'
|
||||
bottom: '20%'
|
||||
},
|
||||
legend: {
|
||||
top: 'bottom',
|
||||
data: ['线上成交', '线下成交'],
|
||||
icon: 'rectangle'
|
||||
},
|
||||
xAxis: {
|
||||
data: transactionAmountXAxis.value
|
||||
},
|
||||
yAxis: {},
|
||||
series: [
|
||||
{
|
||||
name: '线上成交',
|
||||
data: transactionAmountSeries1.value,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
smooth: false,
|
||||
areaStyle: {
|
||||
color: '#b2e0ff',
|
||||
opacity: 0.8
|
||||
}
|
||||
// symbol: 'circle',
|
||||
},
|
||||
{
|
||||
name: '线下成交',
|
||||
data: transactionAmountSeries2.value,
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
smooth: false,
|
||||
areaStyle: {
|
||||
color: '#ffd7dc',
|
||||
opacity: 0.8
|
||||
}
|
||||
// symbol: 'circle',
|
||||
}
|
||||
]
|
||||
})
|
||||
const clickCjje = async (type) => {
|
||||
let res = await getTableList('example_trader_transaction_amount', { type: type })
|
||||
transactionAmountXAxis.value = []
|
||||
transactionAmountSeries1.value = []
|
||||
transactionAmountSeries2.value = []
|
||||
res.records.forEach((ele) => {
|
||||
transactionAmountXAxis.value.push(ele.sj)
|
||||
transactionAmountSeries1.value.push(ele.xscj)
|
||||
transactionAmountSeries2.value.push(ele.xxcj)
|
||||
})
|
||||
cjjeOption.value.xAxis.data = transactionAmountXAxis.value
|
||||
cjjeOption.value.series[0].data = transactionAmountSeries1.value
|
||||
cjjeOption.value.series[1].data = transactionAmountSeries2.value
|
||||
nextTick(() => {
|
||||
const cjjeChart = echarts.init(document.getElementById('cjjeMain'))
|
||||
cjjeChart.setOption(cjjeOption.value)
|
||||
})
|
||||
}
|
||||
|
||||
// 通用函数,用于初始化 ECharts 图表
|
||||
const initEcharts = (domElementId, option) => {
|
||||
const domElement = document.getElementById(domElementId)
|
||||
if (domElement) {
|
||||
const chart = echarts.init(domElement)
|
||||
domElement.removeAttribute('_echarts_instance_')
|
||||
chart.setOption(option)
|
||||
if (domElementId == 'main') {
|
||||
handleChartLoop(option.series[0].data, chart)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const echartFun = () => {
|
||||
initEcharts('ldMain', ldOption)
|
||||
initEcharts('zxtMain', zxtOption)
|
||||
initEcharts('zddlMain', zddlOption)
|
||||
initEcharts('ktsjMain', ktsjOption)
|
||||
initEcharts('main', option)
|
||||
initEcharts('cjjeMain', cjjeOption.value)
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList(
|
||||
'example_trader_count_data,example_trader_expansion,example_trader_merchant_distribution,example_trader_transaction_funneldiagram'
|
||||
)
|
||||
|
||||
topCardList.value = topCardList.value.map((item, index) => {
|
||||
const cardData = oneres.example_trader_count_data.records[0][item.dictionary]
|
||||
item = { ...item, ...cardData, border: 'border' + index }
|
||||
return item
|
||||
})
|
||||
jdtData.value = jdtData.value.map((item) => {
|
||||
const cardData = oneres.example_trader_expansion.records[0][item.dictionary]
|
||||
item = { ...item, ...cardData, jd: (cardData.leftNum / cardData.rightNum) * 100 }
|
||||
return item
|
||||
})
|
||||
option.series[0].data = oneres.example_trader_merchant_distribution.records
|
||||
optionSeriesData.value = oneres.example_trader_merchant_distribution.records
|
||||
ldOption.series[0].data = oneres.example_trader_transaction_funneldiagram?.records
|
||||
|
||||
let endres = await batchGetTableList(
|
||||
'example_trader_daily_turnover,example_trader_weekly_orders,example_trader_expansion_number,example_trader_transaction_amount'
|
||||
)
|
||||
|
||||
endres.example_trader_daily_turnover?.records.forEach((ele) => {
|
||||
dailyTurnoverXAxis.value.push(ele.sj)
|
||||
dailyTurnoverSeries.value.push(ele.data)
|
||||
})
|
||||
zxtOption.xAxis.data = dailyTurnoverXAxis.value
|
||||
zxtOption.series[0].data = dailyTurnoverSeries.value
|
||||
endres.example_trader_weekly_orders.records.forEach((ele) => {
|
||||
weeklyOrdersXAxis.value.push(ele.sj)
|
||||
weeklyOrdersSeries.value.push(ele.data)
|
||||
})
|
||||
zddlOption.xAxis.data = weeklyOrdersXAxis.value
|
||||
zddlOption.series[0].data = weeklyOrdersSeries.value
|
||||
expansionNumberDataset.value.push(
|
||||
...endres.example_trader_expansion_number.records.map((item) => [
|
||||
item.sj,
|
||||
item.mbkts,
|
||||
item.sjkts
|
||||
])
|
||||
)
|
||||
endres.example_trader_transaction_amount.records.forEach((ele) => {
|
||||
transactionAmountXAxis.value.push(ele.sj)
|
||||
transactionAmountSeries1.value.push(ele.xscj)
|
||||
transactionAmountSeries2.value.push(ele.xxcj)
|
||||
})
|
||||
cjjeOption.value.xAxis.data = transactionAmountXAxis.value
|
||||
cjjeOption.value.series[0].data = transactionAmountSeries1.value
|
||||
cjjeOption.value.series[1].data = transactionAmountSeries2.value
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await init()
|
||||
echartFun()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.real-time-data {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #999;
|
||||
align-items: flex-end;
|
||||
|
||||
.title {
|
||||
// color: #666666;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.top-box {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.top-card {
|
||||
flex-basis: calc(16.6% - 12px);
|
||||
flex-shrink: 1;
|
||||
min-width: 168px;
|
||||
padding: 15px;
|
||||
// border-radius: 10px;
|
||||
box-shadow: var(--el-box-shadow-light);
|
||||
box-sizing: border-box;
|
||||
|
||||
.card-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.title {
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 32px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.tendency {
|
||||
width: 24px;
|
||||
height: 17px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 100%;
|
||||
}
|
||||
|
||||
.text-ts {
|
||||
margin: 0 3px;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-left: 1px;
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 24px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.text-value {
|
||||
font-family: 'Montserrat Bold', Montserrat, sans-serif;
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
font-weight: bold;
|
||||
line-height: 32px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.card-box.top {
|
||||
.text {
|
||||
color: rgb(7 183 138);
|
||||
}
|
||||
|
||||
.ascent {
|
||||
background-image: url('@/assets/svgs/top.svg');
|
||||
}
|
||||
}
|
||||
|
||||
.card-box.bottom {
|
||||
.text {
|
||||
color: rgb(250 80 135);
|
||||
}
|
||||
|
||||
.descent {
|
||||
background-image: url('@/assets/svgs/bottom.svg');
|
||||
}
|
||||
}
|
||||
|
||||
.text-dw {
|
||||
margin-left: 8px;
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
padding: 10px 30px 0;
|
||||
margin-top: 20px;
|
||||
background: #fff;
|
||||
justify-content: space-between;
|
||||
|
||||
p {
|
||||
height: 60px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 60px;
|
||||
}
|
||||
|
||||
.content-title {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
color: #666;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.content-left {
|
||||
width: 30%;
|
||||
|
||||
.jdt {
|
||||
margin-top: 20px;
|
||||
|
||||
.jdt-top {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
|
||||
.jdt-top-text {
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.num {
|
||||
font-family: 'Montserrat Bold', Montserrat, sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.acitive {
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
// background: red;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.jdt-bottom {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.content-center {
|
||||
width: 30%;
|
||||
}
|
||||
|
||||
.content-right {
|
||||
width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
.eCharts {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
justify-content: space-between;
|
||||
|
||||
.eCharts-title {
|
||||
display: flex;
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
color: #666;
|
||||
text-align: left;
|
||||
justify-content: space-between;
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.eCharts-left {
|
||||
width: 27.5%;
|
||||
padding: 10px 30px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.eCharts-center {
|
||||
width: 27.5%;
|
||||
padding: 10px 30px 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.eCharts-right {
|
||||
width: 27.5%;
|
||||
padding: 10px 30px 0;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.eCharts-cjje {
|
||||
padding: 10px 30px 30px;
|
||||
margin-top: 20px;
|
||||
background: #fff;
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.cjje-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
.cjje-top-left {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 28px;
|
||||
color: #686a6d;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.border0 {
|
||||
border-left: 5px solid #fb6260;
|
||||
}
|
||||
|
||||
.border1 {
|
||||
border-left: 5px solid #09f;
|
||||
}
|
||||
|
||||
.border2 {
|
||||
border-left: 5px solid #8167f5;
|
||||
}
|
||||
|
||||
.border3 {
|
||||
border-left: 5px solid #51d351;
|
||||
}
|
||||
|
||||
.border4 {
|
||||
border-left: 5px solid #ff7a8c;
|
||||
}
|
||||
|
||||
.border5 {
|
||||
border-left: 5px solid #ffa94c;
|
||||
}
|
||||
|
||||
.text-zeng {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.text-jian {
|
||||
color: #19be6b;
|
||||
}
|
||||
|
||||
.demo-progress .el-progress--line {
|
||||
max-width: 600px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.bj0 {
|
||||
background: #409eff;
|
||||
}
|
||||
|
||||
.bj1 {
|
||||
background: #f56c6c;
|
||||
}
|
||||
|
||||
.bj2 {
|
||||
background: #e6a23c;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-top: 7px;
|
||||
}
|
||||
|
||||
.icons {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.font {
|
||||
font-family: 'Montserrat Bold', Montserrat, sans-serif !important;
|
||||
}
|
||||
|
||||
.fontFamily {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif !important;
|
||||
}
|
||||
|
||||
::v-deep .el-progress-bar__innerText {
|
||||
margin-top: -8px !important;
|
||||
line-height: 12px !important;
|
||||
}
|
||||
|
||||
::v-deep .style {
|
||||
top: -50px !important;
|
||||
}
|
||||
</style>
|
||||
799
src/views/Home/Index7.vue
Normal file
799
src/views/Home/Index7.vue
Normal file
@@ -0,0 +1,799 @@
|
||||
<template>
|
||||
<div class="w-100%">
|
||||
<div class="box">
|
||||
<div class="box-left">
|
||||
<div class="top .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<p class="title .dark:c-#fff!">我的待办</p>
|
||||
<div class="top-content">
|
||||
<div class="top-content-box" v-for="(item, index) in data" :key="index">
|
||||
<img :src="item.img" alt="" />
|
||||
<div style="margin-left: 15px">
|
||||
<p class="text .dark:c-#fff!" style="font-size: 28px">{{ item.num }}</p>
|
||||
<p class="text font .dark:c-#ccc!">{{ item.title }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="center .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<p class="title .dark:c-#fff!">常用功能</p>
|
||||
<div class="center-box">
|
||||
<div class="content-box" v-for="(item, index) in cygnData" :key="index">
|
||||
<div class="img" :class="'bj' + index">
|
||||
<img :src="item.src" alt="" />
|
||||
</div>
|
||||
<div class="font .dark:c-#fff!" style="margin-top: 15px">{{ item.title }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bottom .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="bottom-top">
|
||||
<p class="bottom-top-title .dark:c-#fff!">业务处理</p>
|
||||
<el-menu
|
||||
:default-active="cwclType"
|
||||
:ellipsis="false"
|
||||
mode="horizontal"
|
||||
@select="handleSelect"
|
||||
style="padding: 0 !important; margin: 0 !important"
|
||||
>
|
||||
<el-menu-item v-for="item in cwclTypeList" :key="item.type" :index="item.type">{{
|
||||
item.name
|
||||
}}</el-menu-item>
|
||||
</el-menu>
|
||||
</div>
|
||||
<el-table
|
||||
class="custom-row-gap"
|
||||
:data="cwclTableData"
|
||||
style="width: 100%"
|
||||
:header-cell-style="{
|
||||
height: '50px',
|
||||
fontFamily: `'微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif !important`,
|
||||
fontWeight: ' 700 !important',
|
||||
color: '#666666 !important'
|
||||
}"
|
||||
:cell-style="{
|
||||
height: '44.2px',
|
||||
fontFamily: `'微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif !important`,
|
||||
fontWeight: ' 400 !important',
|
||||
color: '#666666 !important'
|
||||
}"
|
||||
>
|
||||
<el-table-column prop="tjsj" label="提交时间" width="170" />
|
||||
<el-table-column prop="bxlx" label="报销类型" width="140" />
|
||||
<el-table-column prop="spdh" label="审批单号" width="140" />
|
||||
<el-table-column prop="bxje" label="报销金额" width="140" />
|
||||
<el-table-column prop="spdx" label="审批对象" width="140" />
|
||||
<el-table-column fixed="right" label="操作" min-width="120" align="center">
|
||||
<template #default>
|
||||
<el-button link type="primary" size="small" @click="handleClick">
|
||||
<Icon
|
||||
icon="icon-park-solid:right-c"
|
||||
width="12"
|
||||
height="12"
|
||||
style="color: #2391ff"
|
||||
/>
|
||||
<span style="margin-left: 5px; font-size: 14px">查看详情</span>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-right">
|
||||
<div class="box-right-top .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="title .dark:c-#fff!">预警信息</div>
|
||||
<div class="list" v-for="(item, index) in yjxxdata" :key="index">
|
||||
<span class="list-left .dark:c-#ccc!">{{ item.name }}</span>
|
||||
<span class="list-right" :class="index % 2 == 0 ? 'text-color' : ''">{{
|
||||
item.num
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-right-center .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div class="title .dark:c-#fff!"> 年度经营目标</div>
|
||||
<div class="title" style="font-size: 24px; color: #279df5">
|
||||
<span class="fontFamily .dark:c-#fff!">{{ annualIndicators1?.ndjymb }}</span>
|
||||
<span style="font-size: 14px; color: #666" class=".dark:c-#ccc!"> 万 </span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ndmb">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="annualIndicators1?.wcl"
|
||||
:stroke-width="16"
|
||||
:width="166"
|
||||
>
|
||||
<template #default>
|
||||
<span class="percentage-label .dark:c-#ccc!" style="color: #20a0ff"> 完成率 </span>
|
||||
<span class="percentage-value" style="color: #20a0ff">
|
||||
{{ annualIndicators1?.wcl }}%
|
||||
</span>
|
||||
</template>
|
||||
</el-progress>
|
||||
</div>
|
||||
<div class="text .dark:c-#ccc!">
|
||||
已完成目标:
|
||||
<span class="fontFamily" style="font-size: 24px; font-weight: 700; color: #fbaf4f">
|
||||
{{ annualIndicators1?.ywcmb }}
|
||||
</span>
|
||||
万
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-right-center .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div style="display: flex; justify-content: space-between">
|
||||
<div class="title .dark:c-#fff!">年度回款目标</div>
|
||||
<div class="title" style="font-size: 24px; color: #279df5">
|
||||
<span class="fontFamily .dark:c-#fff!">{{ annualIndicators2?.ndhkmb }}</span>
|
||||
<span style="font-size: 14px; color: #666" class=".dark:c-#ccc!"> 万</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ndmb">
|
||||
<el-progress
|
||||
type="circle"
|
||||
:percentage="annualIndicators2?.wcl"
|
||||
:stroke-width="16"
|
||||
status="success"
|
||||
:width="166"
|
||||
>
|
||||
<template #default>
|
||||
<span class="percentage-label .dark:c-#ccc!">完成率</span>
|
||||
<span class="percentage-value">{{ annualIndicators2?.wcl }}%</span>
|
||||
</template>
|
||||
</el-progress>
|
||||
</div>
|
||||
<div class="text .dark:c-#ccc!">
|
||||
已完成目标
|
||||
<span class="fontFamily" style="font-size: 24px; font-weight: 700; color: #fbaf4f">
|
||||
{{ annualIndicators2?.ywcmb }}
|
||||
</span>
|
||||
万
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100% eCharts">
|
||||
<div class="eCharts-left .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="eCharts-left-top">
|
||||
<div class="title .dark:c-#fff!">账户余额</div>
|
||||
<div class="font .dark:c-#ccc!">
|
||||
<span>合计:</span>
|
||||
<span
|
||||
class="fontFamily .dark:c-#fff!"
|
||||
style="font-size: 20px; font-weight: 700; color: #2b9ef7"
|
||||
>{{ zhyeNum }}</span
|
||||
>
|
||||
<span style="margin-left: 5px">万</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
style="display: flex; align-items: center; line-height: 50px"
|
||||
v-for="(item, index) in zhyedata"
|
||||
:key="index"
|
||||
>
|
||||
<div class="font-title .dark:c-#ccc!" style="width: 17%">{{ item.name }}</div>
|
||||
<div style="width: 79%">
|
||||
<el-progress :percentage="item.jdt" :stroke-width="10">
|
||||
<span
|
||||
style="
|
||||
margin-left: 30px;
|
||||
font-family: ArialMT, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
"
|
||||
>{{ item.num }}</span
|
||||
>
|
||||
</el-progress>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="eCharts-right .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="eCharts-right-top">
|
||||
<div class="title .dark:c-#fff!">收支预测</div>
|
||||
</div>
|
||||
<div id="szycMain" style="width: 600px; height: 300px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100% eCharts">
|
||||
<div class="eCharts-left .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="eCharts-left-top">
|
||||
<div class="title .dark:c-#fff!">费用结构</div>
|
||||
</div>
|
||||
<div id="fyjgMain" style="width: 600px; height: 300px"></div>
|
||||
</div>
|
||||
<div class="eCharts-right .dark:b-#2A2B2C b-solid .dark:bg-#1D1E1F! b-1px b-transparent">
|
||||
<div class="eCharts-right-top">
|
||||
<div class="title .dark:c-#fff!">收入结构</div>
|
||||
</div>
|
||||
<div id="srjgMain" style="width: 600px; height: 300px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from 'echarts'
|
||||
import { getTableList, batchGetTableList } from '@/api/design/report'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
interface Data {
|
||||
dictionary: string
|
||||
img: string
|
||||
title: string
|
||||
num?: string
|
||||
}
|
||||
interface CwclTableData {
|
||||
tjsj: string
|
||||
bxlx: string
|
||||
spdh: string
|
||||
bxje: string
|
||||
spdx: string
|
||||
}
|
||||
|
||||
interface Yjxxdata {
|
||||
dictionary: string
|
||||
name: string
|
||||
num?: string
|
||||
}
|
||||
interface CircularProgress {
|
||||
ndjymb: number
|
||||
wcl: number
|
||||
ywcmb: number
|
||||
ndhkmb: number
|
||||
}
|
||||
interface Zhyedata {
|
||||
name: string
|
||||
num: number
|
||||
jdt: number
|
||||
}
|
||||
type Szyc = [[string, string | number, string | number]]
|
||||
|
||||
//我的待办
|
||||
let data = ref<Data[]>([
|
||||
{ dictionary: 'dclgd', img: '/img/img1.svg', title: '待处理工单' },
|
||||
{ dictionary: 'dbxmx', img: '/img/img2.svg', title: '待报销明细' },
|
||||
{ dictionary: 'dtjhb', img: '/img/img3.svg', title: '待提交汇报' },
|
||||
{ dictionary: 'dtjbb', img: '/img/img4.svg', title: '待提交报表' }
|
||||
])
|
||||
|
||||
//常用功能
|
||||
const cygnData = reactive([
|
||||
{ src: '/img/tb1.svg', title: '资金收支报表' },
|
||||
{ src: '/img/tb2.svg', title: '资产负债报表' },
|
||||
{ src: '/img/tb3.svg', title: '企业利润报表' },
|
||||
{ src: '/img/tb4.svg', title: '现金流量报表' },
|
||||
{ src: '/img/tb5.svg', title: '项目报告列表' },
|
||||
{ src: '/img/tb6.svg', title: '责任中心报告' }
|
||||
])
|
||||
|
||||
//预警信息
|
||||
let yjxxdata = ref<Yjxxdata[]>([
|
||||
{
|
||||
dictionary: 'dqysk',
|
||||
name: '到期应收款'
|
||||
},
|
||||
{
|
||||
dictionary: 'yqysk',
|
||||
name: '逾期应收款'
|
||||
},
|
||||
{
|
||||
dictionary: 'dqyfk',
|
||||
name: '到期应付款'
|
||||
},
|
||||
{
|
||||
dictionary: 'yqyfk',
|
||||
name: '逾期应付款'
|
||||
}
|
||||
])
|
||||
|
||||
// 年度经营目标
|
||||
const annualIndicators1 = ref<CircularProgress>()
|
||||
|
||||
// 年度回款目标
|
||||
const annualIndicators2 = ref<CircularProgress>()
|
||||
|
||||
//账户余额
|
||||
const zhyeNum = ref('')
|
||||
let zhyedata = ref<Zhyedata[]>()
|
||||
|
||||
//收支预测
|
||||
const szycDataset = ref<Szyc>([['product', '预计收入', '预计支出']])
|
||||
const szycOption = reactive({
|
||||
legend: {
|
||||
// data: ['系列1', '系列2'],
|
||||
orient: 'horizontal',
|
||||
x: 'center', // 可以是 'center'、'left'、'right' 等
|
||||
y: 'bottom' // 可以是 'top'、'center'、'bottom' 等,或者是具体的像素值
|
||||
},
|
||||
tooltip: {},
|
||||
dataset: {
|
||||
source: szycDataset.value
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
axisTick: {
|
||||
show: false // 设置X轴不显示刻度
|
||||
}
|
||||
},
|
||||
yAxis: {},
|
||||
// Declare several bar series, each will be mapped
|
||||
// to a column of dataset.source by default.
|
||||
series: [
|
||||
{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
// 设置柱形图的颜色
|
||||
color: '#2c9ef7'
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
itemStyle: {
|
||||
// 设置柱形图的颜色
|
||||
color: '#0dd78d'
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//费用结构
|
||||
const fyjgOption = reactive({
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 'bottom',
|
||||
icon: 'circle'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: '58%',
|
||||
center: ['50%', '40%'],
|
||||
color: ['#2c9ef7', '#aa89fe', '#fdad4e', '#0dd78d'],
|
||||
data: [],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
formatter: '{b}\n\n¥{c}',
|
||||
textStyle: {
|
||||
color: '#999999',
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
//收入结构
|
||||
const srjgOption = reactive({
|
||||
tooltip: {
|
||||
trigger: 'item'
|
||||
},
|
||||
legend: {
|
||||
orient: 'horizontal',
|
||||
left: 'center',
|
||||
top: 'bottom',
|
||||
icon: 'circle'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
center: ['50%', '40%'],
|
||||
color: ['#2c9ef7', '#5cb9ff', '#abdbff', '#d0ebff'],
|
||||
data: [],
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||
}
|
||||
},
|
||||
label: {
|
||||
normal: {
|
||||
formatter: '{b}\n \n ¥{c}',
|
||||
textStyle: {
|
||||
color: '#999999',
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 业务处理
|
||||
const cwclType = ref('1')
|
||||
const cwclTableData = ref<CwclTableData[]>()
|
||||
const cwclTypeList = ref([
|
||||
{ name: '待我审批', type: '1' },
|
||||
{ name: '超期待审', type: '2' },
|
||||
{ name: '我提交的', type: '3' },
|
||||
{ name: '被退回的', type: '4' }
|
||||
])
|
||||
|
||||
const handleSelect = async (key: string, keyPath: string[]) => {
|
||||
let res = await getTableList('example_systemmonitor_business_processing', { type: key })
|
||||
cwclTableData.value = res.records
|
||||
}
|
||||
const handleClick = () => {
|
||||
ElMessage({
|
||||
message: '查看详情',
|
||||
type: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
// 通用函数,用于初始化 ECharts 图表
|
||||
const initEcharts = (domElementId, option) => {
|
||||
const domElement = document.getElementById(domElementId)
|
||||
if (domElement) {
|
||||
const chart = echarts.init(domElement)
|
||||
domElement.removeAttribute('_echarts_instance_')
|
||||
chart.setOption(option)
|
||||
}
|
||||
}
|
||||
|
||||
const echartFun = () => {
|
||||
initEcharts('szycMain', szycOption)
|
||||
initEcharts('fyjgMain', fyjgOption)
|
||||
initEcharts('srjgMain', srjgOption)
|
||||
}
|
||||
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList(
|
||||
'example_signagetwo_pending,example_systemmonitor_business_processing,example_systemmonitor_warning_messages,example_systemmonitor_business_target'
|
||||
)
|
||||
let signagetwoPending = oneres.example_signagetwo_pending.records[0]
|
||||
let businessProcessing = oneres.example_systemmonitor_business_processing.records
|
||||
let warningMessages = oneres.example_systemmonitor_warning_messages.records[0]
|
||||
let businessTarget = oneres.example_systemmonitor_business_target.records[0]
|
||||
data.value = data.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
num: signagetwoPending[item.dictionary]
|
||||
})
|
||||
})
|
||||
cwclTableData.value = businessProcessing
|
||||
yjxxdata.value = yjxxdata.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
num: warningMessages[item.dictionary]
|
||||
})
|
||||
})
|
||||
annualIndicators1.value = businessTarget
|
||||
|
||||
let endres = await batchGetTableList(
|
||||
'example_systemmonitor_payback_target,example_systemmonitor_account_balance,example_systemmonitor_Income_expenditure_forecasts,example_systemmonitor_fee_structure,example_systemmonitor_Income_structure'
|
||||
)
|
||||
|
||||
let paybackTarget = endres.example_systemmonitor_payback_target.records[0]
|
||||
let accountBalance = endres.example_systemmonitor_account_balance.records
|
||||
let expenditureForecasts = endres.example_systemmonitor_Income_expenditure_forecasts.records
|
||||
let feeStructure = endres.example_systemmonitor_fee_structure.records
|
||||
let incomestructure = endres.example_systemmonitor_Income_structure.records
|
||||
annualIndicators2.value = paybackTarget
|
||||
zhyedata.value = accountBalance
|
||||
zhyeNum.value = accountBalance.reduce((a, b) => {
|
||||
return a + b.num
|
||||
}, 0)
|
||||
expenditureForecasts.forEach((ele) => {
|
||||
szycDataset.value.push([ele.sj, ele.yjsr, ele.yjzc])
|
||||
})
|
||||
szycOption.dataset.source = szycDataset.value
|
||||
fyjgOption.series[0].data = feeStructure
|
||||
srjgOption.series[0].data = incomestructure
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await init()
|
||||
echartFun()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
||||
p {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.box-left {
|
||||
width: 72.3%;
|
||||
// height: 300px;
|
||||
// background: red;
|
||||
|
||||
.title {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 60px;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.top {
|
||||
padding: 0 20px 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.text {
|
||||
font-family: 'Montserrat Bold', 'Montserrat Regular', Montserrat, sans-serif;
|
||||
font-weight: 700;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.top-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 25px;
|
||||
|
||||
.top-content-box {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
padding: 0 20px 10px;
|
||||
margin-top: 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.center-box {
|
||||
display: flex;
|
||||
padding-bottom: 20px;
|
||||
margin-top: 10px;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.content-box {
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
// background: red;
|
||||
|
||||
.img {
|
||||
display: flex;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
margin: 0 auto;
|
||||
border-radius: 50%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom {
|
||||
padding: 0 20px;
|
||||
padding-bottom: 35px;
|
||||
margin-top: 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.bottom-top {
|
||||
display: flex;
|
||||
margin-bottom: 8px;
|
||||
justify-content: space-between;
|
||||
|
||||
.bottom-top-title {
|
||||
height: 40px;
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 52px;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box-right {
|
||||
width: 26.3%;
|
||||
// height: 300px;
|
||||
// background: blue;
|
||||
|
||||
.title {
|
||||
// margin-bottom: 20px;
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 60px;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.box-right-top {
|
||||
padding: 0 20px 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.list {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
// margin-bottom: 15px;
|
||||
line-height: 40px;
|
||||
|
||||
.list-left {
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.list-right {
|
||||
font-family: 'Montserrat Bold', 'Montserrat Regular', Montserrat, sans-serif;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
color: #0fd1b6;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box-right-center {
|
||||
padding: 0 20px 20px;
|
||||
margin-top: 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.ndmb {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-top: 20px;
|
||||
font-family: '微软雅黑', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 40px;
|
||||
color: #797979;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.eCharts {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
justify-content: space-between;
|
||||
|
||||
.title {
|
||||
font-family: '微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: 60px;
|
||||
color: #333;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.eCharts-left {
|
||||
width: 46.1%;
|
||||
padding: 0 20px 20px;
|
||||
line-height: 60px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
|
||||
.eCharts-left-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.eCharts-right-top {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.eCharts-right {
|
||||
width: 46.1%;
|
||||
padding: 0 20px;
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.percentage-value {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
font-family: Arial-BoldMT, 'Arial Bold', Arial, sans-serif;
|
||||
font-size: 28px;
|
||||
font-weight: 700;
|
||||
color: #13ce66;
|
||||
}
|
||||
|
||||
.percentage-label {
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
font-family: ArialMT, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.el-menu--horizontal.el-menu {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
.bj0 {
|
||||
background: #2c9ef7;
|
||||
}
|
||||
|
||||
.bj1 {
|
||||
background: #b591f5;
|
||||
}
|
||||
|
||||
.bj2 {
|
||||
background: #11d88f;
|
||||
}
|
||||
|
||||
.bj3 {
|
||||
background: #ffad52;
|
||||
}
|
||||
|
||||
.bj4 {
|
||||
background: #10d1b7;
|
||||
}
|
||||
|
||||
.bj5 {
|
||||
background: #f67263;
|
||||
}
|
||||
|
||||
.text-color {
|
||||
color: #f6716e !important;
|
||||
}
|
||||
|
||||
.font {
|
||||
font-family: '微软雅黑', sans-serif !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 400 !important;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.fontFamily {
|
||||
font-family: 'Montserrat Bold', 'Montserrat Regular', Montserrat, sans-serif !important;
|
||||
}
|
||||
|
||||
.font-title {
|
||||
font-family: MicrosoftYaHei, '微软雅黑 Regular', '微软雅黑', sans-serif !important;
|
||||
font-size: 14px !important;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
::v-deep .el-table--default .el-table__cell {
|
||||
padding: 0 !important; /* 根据需要调整这个值来增加或减少行间距 */
|
||||
}
|
||||
</style>
|
||||
432
src/views/Home/Index8.vue
Normal file
432
src/views/Home/Index8.vue
Normal file
@@ -0,0 +1,432 @@
|
||||
<template>
|
||||
<div class="w-100%">
|
||||
<div class="w-100% flex gap-y-20px home-top">
|
||||
<div class="el-card top-card flex items-center" v-for="(item, index) in tabList" :key="index">
|
||||
<div class="left">
|
||||
<span class="text-value">
|
||||
<avue-count-up :end="item.countUp"></avue-count-up>
|
||||
</span>
|
||||
<div class="text mt-10px">
|
||||
<span class="mr-5px">{{ item.title }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<el-image :src="item.imgUrl" fit="contain"></el-image>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100% flex gap-x-20px mt-30px ml-10px mr-10px">
|
||||
<div class="w-35%">
|
||||
<el-calendar v-model="value">
|
||||
<template #header>
|
||||
<span>{{ calendarDate }}</span>
|
||||
</template>
|
||||
</el-calendar>
|
||||
</div>
|
||||
<div class="echart-util bold bg-white .dark:bg-#1D1E1F">
|
||||
<Echart :options="visitor_option" width="100%" height="314px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="w-100% flex gap-x-20px mt-30px ml-10px mr-10px">
|
||||
<div class="echart-util bold bg-white .dark:bg-#1D1E1F">
|
||||
<Echart :options="salesVolume_option" width="100%" height="314px" />
|
||||
</div>
|
||||
<div class="echart-util reverse bg-white .dark:bg-#1D1E1F">
|
||||
<Echart :options="cyclic_annular_option" width="100%" height="314px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import { CACHE_KEY, useCache } from '@/hooks/web/useCache'
|
||||
import { useAppStore } from '@/store/modules/app'
|
||||
import { batchGetTableList } from '@/api/design/report'
|
||||
|
||||
defineOptions({ name: 'Home8' })
|
||||
|
||||
interface CyclicAnnular {
|
||||
name: string
|
||||
dictionary: string
|
||||
value?: number
|
||||
}
|
||||
|
||||
const tabList = ref([
|
||||
{ countUp: 0, title: '今日访客数(人)', imgUrl: '/img/sjhy1.png', dictionary: 'today_visitors' },
|
||||
{
|
||||
countUp: 0,
|
||||
title: '今日会员访问数(人)',
|
||||
imgUrl: '/img/sjhy2.png',
|
||||
dictionary: 'today_member_visitors'
|
||||
},
|
||||
{
|
||||
countUp: 0,
|
||||
title: '今日会员付费数(人)',
|
||||
imgUrl: '/img/sjhy3.png',
|
||||
dictionary: 'today_paid_member'
|
||||
},
|
||||
{ countUp: 0, title: '新增会员数(人)', imgUrl: '/img/sjhy4.png', dictionary: 'today_new_member' }
|
||||
])
|
||||
|
||||
const value = ref(new Date())
|
||||
const calendarDate = formatDate(new Date(), 'YYYY-MM-DD')
|
||||
|
||||
// 实时访客量
|
||||
const visitorXAxis = ref<string[]>([])
|
||||
const visitorSeries = ref<number[]>([])
|
||||
const visitor_option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
title: {
|
||||
text: '实时访客量',
|
||||
textStyle: {
|
||||
fontSize: 20,
|
||||
color: 'black'
|
||||
},
|
||||
left: 25
|
||||
},
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#EDE8FE' // 0% 处的颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#F8F7FC' // 100% 处的颜色
|
||||
}
|
||||
],
|
||||
global: false // 缺省为 false
|
||||
},
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: 20,
|
||||
top: '16%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
data: visitorXAxis.value,
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#EBEBEB'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
color: 'black',
|
||||
fontSize: 12,
|
||||
padding: [10, 0, 0, 0],
|
||||
align: 'center'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
color: '#6071A9',
|
||||
fontSize: 12
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#EBEBEB',
|
||||
type: 'solid'
|
||||
}
|
||||
},
|
||||
offset: 10
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '访客量',
|
||||
type: 'line',
|
||||
data: visitorSeries.value,
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 5,
|
||||
color: '#5D77FF'
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 0.7
|
||||
},
|
||||
emphasis: { disabled: true },
|
||||
symbol: 'none'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 销售额
|
||||
const salesVolumeXAxis = ref<string[]>([])
|
||||
const salesVolumeSeries = ref<number[]>([])
|
||||
const salesVolume_option = ref({
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
title: {
|
||||
text: '销售额(元)',
|
||||
textStyle: {
|
||||
fontSize: 20,
|
||||
color: 'black'
|
||||
},
|
||||
left: 25
|
||||
},
|
||||
color: ['#6F7EFD'],
|
||||
grid: {
|
||||
left: '4%',
|
||||
right: '4%',
|
||||
bottom: 20,
|
||||
top: '16%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
data: salesVolumeXAxis.value,
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
axisLine: {
|
||||
symbol: 'none',
|
||||
lineStyle: {
|
||||
color: '#EBEBEB'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
interval: 0,
|
||||
color: 'black',
|
||||
fontSize: 12,
|
||||
padding: [10, 0, 0, 0],
|
||||
align: 'center'
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLabel: {
|
||||
color: '#6071A9',
|
||||
fontSize: 12
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
width: 0
|
||||
}
|
||||
},
|
||||
offset: 10
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
data: salesVolumeSeries.value,
|
||||
smooth: true,
|
||||
lineStyle: {
|
||||
width: 0
|
||||
},
|
||||
areaStyle: {
|
||||
opacity: 1
|
||||
},
|
||||
emphasis: { disabled: true },
|
||||
symbol: 'none'
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
// 环状图
|
||||
const cyclic_annular_option_data = ref<CyclicAnnular[]>([
|
||||
{ name: '男装', dictionary: 'nz' },
|
||||
{ name: '鞋包', dictionary: 'xb' },
|
||||
{ name: '母婴', dictionary: 'my' },
|
||||
{ name: '数码', dictionary: 'sm' }
|
||||
])
|
||||
|
||||
const cyclic_annular_option = ref({
|
||||
title: {
|
||||
text: '',
|
||||
left: 'center',
|
||||
top: 'center',
|
||||
textStyle: {
|
||||
fontSize: 24,
|
||||
fontWeight: 'bold',
|
||||
color: '#5E78FD'
|
||||
},
|
||||
subtext: '',
|
||||
subtextStyle: {
|
||||
color: '#999999',
|
||||
fontWeight: '600'
|
||||
},
|
||||
itemGap: 0
|
||||
},
|
||||
color: ['#5E78FD', '#6E86FD', '#8DA0FF', '#AEBBFF'],
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['35%', '55%'],
|
||||
label: {
|
||||
formatter: (parms) => {
|
||||
return [`{str|${parms.percent}% ${parms.data.name}}`].join('\n')
|
||||
},
|
||||
rich: {
|
||||
str: {
|
||||
fontWeight: 'bold',
|
||||
align: 'center'
|
||||
}
|
||||
}
|
||||
},
|
||||
data: cyclic_annular_option_data.value
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
const appStore = useAppStore()
|
||||
watch(
|
||||
() => appStore.isDark,
|
||||
(val) => {
|
||||
if (val) {
|
||||
visitor_option.value.title.textStyle.color = 'white'
|
||||
salesVolume_option.value.title.textStyle.color = 'white'
|
||||
} else {
|
||||
visitor_option.value.title.textStyle.color = 'black'
|
||||
salesVolume_option.value.title.textStyle.color = 'black'
|
||||
}
|
||||
}
|
||||
)
|
||||
const init = async () => {
|
||||
let oneres = await batchGetTableList('example_member_count_data,example_member_realtime_visits')
|
||||
|
||||
let countData = oneres.example_member_count_data.records[0]
|
||||
let realtimeVisits = oneres.example_member_realtime_visits.records
|
||||
tabList.value = tabList.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
countUp: countData[item.dictionary]
|
||||
})
|
||||
})
|
||||
realtimeVisits.forEach((ele) => {
|
||||
visitorXAxis.value?.push(ele.sj)
|
||||
visitorSeries.value?.push(ele.ssfkl)
|
||||
})
|
||||
|
||||
let endres = await batchGetTableList('example_member_sale,example_member_product_percentage')
|
||||
|
||||
let sale = endres.example_member_sale.records
|
||||
let productPercentage = endres.example_member_product_percentage.records[0]
|
||||
sale.forEach((ele) => {
|
||||
salesVolumeXAxis.value?.push(ele.sj)
|
||||
salesVolumeSeries.value?.push(ele.xse)
|
||||
})
|
||||
cyclic_annular_option_data.value = cyclic_annular_option_data.value.map((item) => {
|
||||
return (item = {
|
||||
...item,
|
||||
value: productPercentage[item.dictionary]
|
||||
})
|
||||
})
|
||||
cyclic_annular_option.value.series[0].data = cyclic_annular_option_data.value
|
||||
cyclic_annular_option.value.title.text = '¥' + productPercentage.je
|
||||
cyclic_annular_option.value.title.subtext = productPercentage.sj
|
||||
}
|
||||
onMounted(async () => {
|
||||
// 判断是否为暗色模式
|
||||
const { wsCache } = useCache()
|
||||
if (wsCache.get(CACHE_KEY.IS_DARK)) {
|
||||
visitor_option.value.title.textStyle.color = 'white'
|
||||
salesVolume_option.value.title.textStyle.color = 'white'
|
||||
}
|
||||
await init()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home-top {
|
||||
flex-wrap: wrap;
|
||||
|
||||
.top-card {
|
||||
width: calc(25% - 50px);
|
||||
height: 85px;
|
||||
padding: 15px;
|
||||
margin: 0 10px;
|
||||
margin-top: 0 !important;
|
||||
border: none;
|
||||
border-radius: inherit;
|
||||
flex-shrink: 0;
|
||||
justify-content: space-around;
|
||||
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
|
||||
|
||||
.left {
|
||||
font-weight: bold;
|
||||
|
||||
.text-value {
|
||||
margin-bottom: 45px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.echart-util {
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
|
||||
}
|
||||
|
||||
.echart-util.bold {
|
||||
width: calc(65% - 80px);
|
||||
}
|
||||
|
||||
.echart-util.reverse {
|
||||
width: calc(35% - 40px);
|
||||
}
|
||||
|
||||
::v-deep(.el-calendar) {
|
||||
box-shadow: 0 0 20px rgb(204 204 204 / 34.9%);
|
||||
|
||||
.el-calendar__header {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.el-calendar__body {
|
||||
th {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.el-calendar-table__row {
|
||||
.is-selected {
|
||||
background-color: rgb(0 255 255 / 0%);
|
||||
}
|
||||
|
||||
.current,
|
||||
.next,
|
||||
.prev {
|
||||
border: none;
|
||||
|
||||
.el-calendar-day {
|
||||
display: flex;
|
||||
height: 43px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
// border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1016
src/views/Home/Index9.vue
Normal file
1016
src/views/Home/Index9.vue
Normal file
File diff suppressed because it is too large
Load Diff
123
src/views/Home/components/table.vue
Normal file
123
src/views/Home/components/table.vue
Normal file
@@ -0,0 +1,123 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-table
|
||||
:data="tableData"
|
||||
stripe
|
||||
style="width: 100%"
|
||||
:header-cell-style="{
|
||||
height: '50px',
|
||||
fontFamily: `'微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif !important`,
|
||||
fontWeight: ' 700 !important',
|
||||
color: '#666666 !important'
|
||||
}"
|
||||
:cell-style="{
|
||||
height: '50px',
|
||||
fontFamily: `'微软雅黑 Bold', '微软雅黑 Regular', '微软雅黑', sans-serif !important`,
|
||||
fontWeight: ' 400 !important',
|
||||
color: '#666666 !important'
|
||||
}"
|
||||
>
|
||||
<el-table-column prop="ranking" label="排名" width="180" />
|
||||
<el-table-column prop="name" label="商户名称" />
|
||||
<el-table-column prop="visit" label="访问量" />
|
||||
<el-table-column prop="quantity" label="订单量" />
|
||||
<el-table-column prop="cancel" label="取消量" />
|
||||
<el-table-column label="综合评分">
|
||||
<template #default="scope">
|
||||
<el-rate
|
||||
v-model="scope.row.pj"
|
||||
disabled
|
||||
allow-half
|
||||
show-score
|
||||
size="large"
|
||||
:score-template="scope.row.score"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成交金额(元)">
|
||||
<template #default="scope">
|
||||
<div v-if="scope.row.zeng" style="display: flex; align-items: center; height: 12px">
|
||||
<span>{{ scope.row.money }}</span>
|
||||
<span class="icon"
|
||||
><Icon icon="ep:top" width="12" height="12" style="color: #f56c6c"
|
||||
/></span>
|
||||
<span style="color: #f7716f !important">{{ scope.row.zeng }}%</span>
|
||||
</div>
|
||||
<div v-else-if="scope.row.jian" style="display: flex; align-items: center; height: 12px">
|
||||
<span>{{ scope.row.money }}</span>
|
||||
<span class="icon"
|
||||
><Icon icon="ep:bottom" width="12" height="12" style="color: #19be6b"
|
||||
/></span>
|
||||
<span style="color: #73c883 !important">{{ scope.row.jian }}%</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span>{{ scope.row.money }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="page">
|
||||
<el-pagination background layout="prev, pager, next" :total="tableDataTotal" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as TableApi from '@/api/design/table'
|
||||
|
||||
interface TableData {
|
||||
cancel: string
|
||||
ranking: string
|
||||
name: string
|
||||
visit: string
|
||||
quantity: string
|
||||
pj: string
|
||||
score: string
|
||||
money: string
|
||||
zeng: string
|
||||
jian: string
|
||||
}
|
||||
|
||||
const tableData = ref<TableData[]>()
|
||||
const tableDataTotal = ref(0)
|
||||
|
||||
onMounted(async () => {
|
||||
let { records } = await TableApi.getTableList(
|
||||
'1847537155101040642',
|
||||
{ pageNo: 1, pageSize: 10 },
|
||||
false
|
||||
)
|
||||
tableData.value = records.map((item) => {
|
||||
item.pj = Number(item.pj || 0)
|
||||
return item
|
||||
})
|
||||
tableDataTotal.value = records.length
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* 将默认的星星颜色改为蓝色 */
|
||||
::v-deep .el-rate .el-rate__icon.is-active {
|
||||
color: #f56c6c !important;
|
||||
}
|
||||
|
||||
::v-deep .custom-rate .el-rate__item.active {
|
||||
color: #f56c6c; /* 选中的颜色 */
|
||||
}
|
||||
|
||||
::v-deep .el-rate .el-rate__item {
|
||||
color: #ccc;
|
||||
}
|
||||
</style>
|
||||
308
src/views/Home/echarts-data.ts
Normal file
308
src/views/Home/echarts-data.ts
Normal file
@@ -0,0 +1,308 @@
|
||||
import { EChartsOption } from 'echarts'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
export const lineOptions: EChartsOption = {
|
||||
title: {
|
||||
text: t('analysis.monthlySales'),
|
||||
left: 'center'
|
||||
},
|
||||
xAxis: {
|
||||
data: [
|
||||
t('analysis.january'),
|
||||
t('analysis.february'),
|
||||
t('analysis.march'),
|
||||
t('analysis.april'),
|
||||
t('analysis.may'),
|
||||
t('analysis.june'),
|
||||
t('analysis.july'),
|
||||
t('analysis.august'),
|
||||
t('analysis.september'),
|
||||
t('analysis.october'),
|
||||
t('analysis.november'),
|
||||
t('analysis.december')
|
||||
],
|
||||
boundaryGap: false,
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: 20,
|
||||
right: 20,
|
||||
bottom: 20,
|
||||
top: 80,
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross'
|
||||
},
|
||||
padding: [5, 10]
|
||||
},
|
||||
yAxis: {
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: [t('analysis.estimate'), t('analysis.actual')],
|
||||
top: 50
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: t('analysis.estimate'),
|
||||
smooth: true,
|
||||
type: 'line',
|
||||
data: [100, 120, 161, 134, 105, 160, 165, 114, 163, 185, 118, 123],
|
||||
animationDuration: 2800,
|
||||
animationEasing: 'cubicInOut'
|
||||
},
|
||||
{
|
||||
name: t('analysis.actual'),
|
||||
smooth: true,
|
||||
type: 'line',
|
||||
itemStyle: {},
|
||||
data: [120, 82, 91, 154, 162, 140, 145, 250, 134, 56, 99, 123],
|
||||
animationDuration: 2800,
|
||||
animationEasing: 'quadraticOut'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const pieOptions: EChartsOption = {
|
||||
title: {
|
||||
text: t('analysis.userAccessSource'),
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} ({d}%)'
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: [
|
||||
t('analysis.directAccess'),
|
||||
t('analysis.mailMarketing'),
|
||||
t('analysis.allianceAdvertising'),
|
||||
t('analysis.videoAdvertising'),
|
||||
t('analysis.searchEngines')
|
||||
]
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: t('analysis.userAccessSource'),
|
||||
type: 'pie',
|
||||
radius: '55%',
|
||||
center: ['50%', '60%'],
|
||||
data: [
|
||||
{ value: 335, name: t('analysis.directAccess') },
|
||||
{ value: 310, name: t('analysis.mailMarketing') },
|
||||
{ value: 234, name: t('analysis.allianceAdvertising') },
|
||||
{ value: 135, name: t('analysis.videoAdvertising') },
|
||||
{ value: 1548, name: t('analysis.searchEngines') }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const barOptions: EChartsOption = {
|
||||
title: {
|
||||
text: t('analysis.weeklyUserActivity'),
|
||||
left: 'center'
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: 50,
|
||||
right: 20,
|
||||
bottom: 20
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: [
|
||||
t('analysis.monday'),
|
||||
t('analysis.tuesday'),
|
||||
t('analysis.wednesday'),
|
||||
t('analysis.thursday'),
|
||||
t('analysis.friday'),
|
||||
t('analysis.saturday'),
|
||||
t('analysis.sunday')
|
||||
],
|
||||
axisTick: {
|
||||
alignWithLabel: true
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value'
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: t('analysis.activeQuantity'),
|
||||
data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
|
||||
type: 'bar'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const radarOption: EChartsOption = {
|
||||
legend: {
|
||||
data: [t('workplace.personal'), t('workplace.team')]
|
||||
},
|
||||
radar: {
|
||||
// shape: 'circle',
|
||||
indicator: [
|
||||
{ name: t('workplace.quote'), max: 65 },
|
||||
{ name: t('workplace.contribution'), max: 160 },
|
||||
{ name: t('workplace.hot'), max: 300 },
|
||||
{ name: t('workplace.yield'), max: 130 },
|
||||
{ name: t('workplace.follow'), max: 100 }
|
||||
]
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: `xxx${t('workplace.index')}`,
|
||||
type: 'radar',
|
||||
data: [
|
||||
{
|
||||
value: [42, 30, 20, 35, 80],
|
||||
name: t('workplace.personal')
|
||||
},
|
||||
{
|
||||
value: [50, 140, 290, 100, 90],
|
||||
name: t('workplace.team')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const wordOptions = {
|
||||
series: [
|
||||
{
|
||||
type: 'wordCloud',
|
||||
gridSize: 2,
|
||||
sizeRange: [12, 50],
|
||||
rotationRange: [-90, 90],
|
||||
shape: 'pentagon',
|
||||
width: 600,
|
||||
height: 400,
|
||||
drawOutOfBound: true,
|
||||
textStyle: {
|
||||
color: function () {
|
||||
return (
|
||||
'rgb(' +
|
||||
[
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160),
|
||||
Math.round(Math.random() * 160)
|
||||
].join(',') +
|
||||
')'
|
||||
)
|
||||
}
|
||||
},
|
||||
emphasis: {
|
||||
textStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowColor: '#333'
|
||||
}
|
||||
},
|
||||
data: [
|
||||
{
|
||||
name: 'Sam S Club',
|
||||
value: 10000,
|
||||
textStyle: {
|
||||
color: 'black'
|
||||
},
|
||||
emphasis: {
|
||||
textStyle: {
|
||||
color: 'red'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'Macys',
|
||||
value: 6181
|
||||
},
|
||||
{
|
||||
name: 'Amy Schumer',
|
||||
value: 4386
|
||||
},
|
||||
{
|
||||
name: 'Jurassic World',
|
||||
value: 4055
|
||||
},
|
||||
{
|
||||
name: 'Charter Communications',
|
||||
value: 2467
|
||||
},
|
||||
{
|
||||
name: 'Chick Fil A',
|
||||
value: 2244
|
||||
},
|
||||
{
|
||||
name: 'Planet Fitness',
|
||||
value: 1898
|
||||
},
|
||||
{
|
||||
name: 'Pitch Perfect',
|
||||
value: 1484
|
||||
},
|
||||
{
|
||||
name: 'Express',
|
||||
value: 1112
|
||||
},
|
||||
{
|
||||
name: 'Home',
|
||||
value: 965
|
||||
},
|
||||
{
|
||||
name: 'Johnny Depp',
|
||||
value: 847
|
||||
},
|
||||
{
|
||||
name: 'Lena Dunham',
|
||||
value: 582
|
||||
},
|
||||
{
|
||||
name: 'Lewis Hamilton',
|
||||
value: 555
|
||||
},
|
||||
{
|
||||
name: 'KXAN',
|
||||
value: 550
|
||||
},
|
||||
{
|
||||
name: 'Mary Ellen Mark',
|
||||
value: 462
|
||||
},
|
||||
{
|
||||
name: 'Farrah Abraham',
|
||||
value: 366
|
||||
},
|
||||
{
|
||||
name: 'Rita Ora',
|
||||
value: 360
|
||||
},
|
||||
{
|
||||
name: 'Serena Williams',
|
||||
value: 282
|
||||
},
|
||||
{
|
||||
name: 'NCAA baseball tournament',
|
||||
value: 273
|
||||
},
|
||||
{
|
||||
name: 'Point Break',
|
||||
value: 265
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
55
src/views/Home/types.ts
Normal file
55
src/views/Home/types.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
export type WorkplaceTotal = {
|
||||
project: number
|
||||
access: number
|
||||
todo: number
|
||||
}
|
||||
|
||||
export type Project = {
|
||||
name: string
|
||||
icon: string
|
||||
message: string
|
||||
personal: string
|
||||
time: Date | number | string
|
||||
}
|
||||
|
||||
export type Notice = {
|
||||
title: string
|
||||
type: string
|
||||
keys: string[]
|
||||
date: Date | number | string
|
||||
}
|
||||
|
||||
export type Shortcut = {
|
||||
name: string
|
||||
icon: string
|
||||
url: string
|
||||
}
|
||||
|
||||
export type RadarData = {
|
||||
personal: number
|
||||
team: number
|
||||
max: number
|
||||
name: string
|
||||
}
|
||||
export type AnalysisTotalTypes = {
|
||||
users: number
|
||||
messages: number
|
||||
moneys: number
|
||||
shoppings: number
|
||||
}
|
||||
|
||||
export type UserAccessSource = {
|
||||
value: number
|
||||
name: string
|
||||
}
|
||||
|
||||
export type WeeklyUserActivity = {
|
||||
value: number
|
||||
name: string
|
||||
}
|
||||
|
||||
export type MonthlySales = {
|
||||
name: string
|
||||
estimate: number
|
||||
actual: number
|
||||
}
|
||||
Reference in New Issue
Block a user