Browse Source

Merge remote-tracking branch 'origin/master'

master
DX 3 weeks ago
parent
commit
e902345364
  1. 57
      src/api/home/index.ts
  2. 2
      src/layout/components/AppView.vue
  3. 2
      src/layout/components/BackOperation/src/index.vue
  4. 2
      src/layout/components/Screen/src/Screen.vue
  5. 3
      src/layout/components/ToolHeader.vue
  6. 6
      src/layout/components/UserInfo/src/UserInfo.vue
  7. 2
      src/router/modules/remaining.ts
  8. 2
      src/store/modules/app.ts
  9. 8
      src/store/modules/user.ts
  10. 2
      src/styles/var.css
  11. 2
      src/utils/dict.ts
  12. 778
      src/views/Home/Index.vue
  13. 148
      src/views/Home/echarts-data.ts
  14. 50
      src/views/Home/types.ts
  15. 88
      src/views/Login/components/QrCodeForm.vue

57
src/api/home/index.ts

@ -0,0 +1,57 @@
import request from '@/config/axios'
export const HomeApi = {
/**
*
*/
getArea: () => {
return request.get({
url: `/system/home/getUserArea`
})
},
/**
*
*/
getListData: params => {
return request.get({
url: '/system/home/appCount2',
params
})
},
/**
*
*/
getPieData: (params) => {
return request.get({
url: '/system/home/appCount1',
params
})
},
/**
* 6
*/
getTaskNumDoing:params=>{
return request.get({
url: '/system/home/taskNumDoing',
params
})
},
/**
*
*/
getExecCorrection:params=>{
return request.get({
url: '/system/home/execCorrectionCount',
params
})
},
/**
*
*/
getNewTask:params=> {
return request.get({
url: 'system/task-info/appPage',
params
})
}
}

2
src/layout/components/AppView.vue

@ -36,7 +36,7 @@ provide('reload', reload)
<template> <template>
<section <section
:class="[ :class="[
'p-[var(--app-content-padding)] w-full bg-[var(--app-content-bg-color)] dark:bg-[var(--el-bg-color)]', 'p-[var(--app-content-padding)] w-full bg-[var(--app-content-bg-color)]',
{ {
'!min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] pb-0': '!min-h-[calc(100vh-var(--top-tool-height)-var(--tags-view-height)-var(--app-footer-height))] pb-0':
footer footer

2
src/layout/components/BackOperation/src/index.vue

@ -5,7 +5,7 @@ import { onBeforeRouteUpdate } from 'vue-router'
defineOptions({ name: 'BackOperation' }) defineOptions({ name: 'BackOperation' })
const router = useRouter() const router = useRouter()
const isBack = ref(false) const isBack:any = ref(false)
defineProps({ defineProps({
color: propTypes.string.def('') color: propTypes.string.def('')
}) })

2
src/layout/components/Screen/src/Screen.vue

@ -25,6 +25,6 @@ const screenView = () => {
<template> <template>
<div :class="prefixCls" @click="screenView"> <div :class="prefixCls" @click="screenView">
<Icon :color="color" icon="svg-icon:screen" :size="18" /> <Icon :color="color" icon="ep:monitor" :size="18" />
</div> </div>
</template> </template>

3
src/layout/components/ToolHeader.vue

@ -65,9 +65,6 @@ export default defineComponent({
color="var(--top-header-text-color)" color="var(--top-header-text-color)"
></LocaleDropdown> ></LocaleDropdown>
) : undefined} ) : undefined}
{message.value ? (
<Message class="custom-hover" color="var(--top-header-text-color)"></Message>
) : undefined}
<UserInfo></UserInfo> <UserInfo></UserInfo>
</div> </div>
</div> </div>

6
src/layout/components/UserInfo/src/UserInfo.vue

@ -24,8 +24,8 @@ const { getPrefixCls } = useDesign()
const prefixCls = getPrefixCls('user-info') const prefixCls = getPrefixCls('user-info')
const avatar = computed(() => userStore.user.avatar || avatarImg) const avatar = computed(() => userStore.user.avatar || avatarImg)
const userName = computed(() => userStore.user.nickname ?? 'Admin')
const realName = computed(() => userStore.user.realName ?? '管理员') const realName = computed(() => userStore.user.realName ?? '管理员')
const deptName = computed(() => userStore.user.deptName ?? '管理员')
// //
const lockStore = useLockStore() const lockStore = useLockStore()
const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false) const getIsLock = computed(() => lockStore.getLockInfo?.isLock ?? false)
@ -58,8 +58,8 @@ const toDocument = () => {
<ElDropdown class="custom-hover" :class="prefixCls" trigger="click"> <ElDropdown class="custom-hover" :class="prefixCls" trigger="click">
<div class="flex items-center gap-4px"> <div class="flex items-center gap-4px">
<ElAvatar :src="avatar" alt="" :size="32" class="rounded-[50%]" /> <ElAvatar :src="avatar" alt="" :size="32" class="rounded-[50%]" />
<span class="text-14px text-[var(--top-header-text-color)] <lg:hidden"> <span class="text-14px color-#303133 font-500 line-height-22px">
{{ realName }} {{ realName }} | {{ deptName }}
</span> </span>
</div> </div>
<template #dropdown> <template #dropdown>

2
src/router/modules/remaining.ts

@ -63,7 +63,7 @@ const remainingRouter: AppRouteRecordRaw[] = [
name: 'Index', name: 'Index',
meta: { meta: {
title: '驾驶舱', title: '驾驶舱',
icon: 'ep:home-filled', icon: 'ep:pie-chart',
noCache: false, noCache: false,
affix: true affix: true
} }

2
src/store/modules/app.ts

@ -62,7 +62,7 @@ export const useAppStore = defineStore('app', {
tagsViewIcon: false, // 是否显示标签图标 tagsViewIcon: false, // 是否显示标签图标
logo: true, // logo logo: true, // logo
fixedHeader: true, // 固定toolheader fixedHeader: true, // 固定toolheader
footer: true, // 显示页脚 footer: false, // 显示页脚
greyMode: false, // 是否开始灰色模式,用于特殊悼念日 greyMode: false, // 是否开始灰色模式,用于特殊悼念日
fixedMenu: wsCache.get('fixedMenu') || false, // 是否固定菜单 fixedMenu: wsCache.get('fixedMenu') || false, // 是否固定菜单
layout: wsCache.get(CACHE_KEY.LAYOUT) || 'classic', // layout布局 layout: wsCache.get(CACHE_KEY.LAYOUT) || 'classic', // layout布局

8
src/store/modules/user.ts

@ -11,7 +11,8 @@ interface UserVO {
avatar: string avatar: string
nickname: string nickname: string
deptId: number, deptId: number,
realName:string realName:string,
deptName:string,
} }
interface UserInfoVO { interface UserInfoVO {
@ -33,6 +34,7 @@ export const useUserStore = defineStore('admin-user', {
nickname: '', nickname: '',
deptId: 0, deptId: 0,
realName: '', realName: '',
deptName:''
} }
}), }),
getters: { getters: {
@ -58,7 +60,6 @@ export const useUserStore = defineStore('admin-user', {
let userInfo = wsCache.get(CACHE_KEY.USER) let userInfo = wsCache.get(CACHE_KEY.USER)
if (!userInfo) { if (!userInfo) {
userInfo = await getInfo() userInfo = await getInfo()
console.log(userInfo)
} }
this.permissions = userInfo.permissions this.permissions = userInfo.permissions
this.roles = userInfo.roles this.roles = userInfo.roles
@ -96,7 +97,8 @@ export const useUserStore = defineStore('admin-user', {
avatar: '', avatar: '',
nickname: '', nickname: '',
deptId: 0, deptId: 0,
realName:'' realName:'',
deptName:''
} }
} }
} }

2
src/styles/var.css

@ -47,7 +47,7 @@
--app-content-padding: 20px; --app-content-padding: 20px;
--app-content-bg-color: #f5f7f9; --app-content-bg-color: #f5f7fa;
--app-footer-height: 50px; --app-footer-height: 50px;

2
src/utils/dict.ts

@ -118,6 +118,8 @@ export enum DICT_TYPE {
ENTERPRISES_STATUS = 'enterprises_status', ENTERPRISES_STATUS = 'enterprises_status',
//========== 资质 ========== //========== 资质 ==========
ENTERPRISES_QUA = 'enterprise_qua', ENTERPRISES_QUA = 'enterprise_qua',
//========== 任务 ==========
SELECT_WEEK = 'select_week',
// ========== SYSTEM 模块 ========== // ========== SYSTEM 模块 ==========
SYSTEM_USER_SEX = 'system_user_sex', SYSTEM_USER_SEX = 'system_user_sex',

778
src/views/Home/Index.vue

@ -1,366 +1,600 @@
<template> <template>
<el-row :gutter="8" justify="space-between"> <el-row justify="space-between">
<el-col :span="14">
<el-form :model="queryParams" class="queryForm" inline>
<el-form-item label="按区域" prop="region">
<el-select
v-model="queryParams.region"
placeholder="请选择区域"
size="large"
@change="getData"
>
<el-option
v-for="option in area"
:key="option.value"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-form-item>
<el-form-item label="按周期" prop="selectWeek">
<el-select
v-model="queryParams.selectWeek"
placeholder="请选择周期"
clearable
size="large"
@select="getData"
@change="getData"
>
<el-option
v-for="option in getIntDictOptions(DICT_TYPE.SELECT_WEEK)"
:key="option.value"
:value="option.value"
:label="option.label"
/>
</el-select>
</el-form-item>
</el-form>
</el-col>
<section class="flex gap-20px">
<el-button type="primary" plain @click="getData">
<Icon icon="ep:search" />
查询
</el-button>
<el-button @click="reset">
<Icon icon="ep:refresh" />
重置
</el-button>
</section>
</el-row>
<el-row :gutter="20" justify="space-between">
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" :height="280"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" :height="280">
<el-card shadow="hover" class="mb-8px"> <el-card shadow="hover" class="mb-20px">
<template #header> <template #header> 任务进度 </template>
执法完成率
</template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<Echart :options="pieOptionsData" :height="280" /> <Echart :options="pieOptionsData" :height="338" />
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24">
<el-card shadow="hover" class="mb-8px"> <el-card shadow="hover">
<template #header> <template #header> 执法整改 </template>
执法与整改
</template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<Echart :options="barOptionsData" :height="280" /> <Echart :options="barOptionsData" :height="338" />
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24">
<el-card shadow="hover" class="mb-8px"> <el-card shadow="hover">
<template #header> <template #header>
任务与执法 <section class="flex justify-between">
<span>任务执法</span>
<span class="color-#A8ABB2 font-normal"> 近6个月走势 </span>
</section>
</template> </template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<Echart :options="lineOptions" :height="280" /> <Echart :options="lineOptionsData" :height="338" />
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="8" justify="space-between"> <el-row :gutter="20" justify="space-between">
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-20px">
<el-card ref="taskNewCard" shadow="never"> <el-card ref="taskNewCard" shadow="never">
<template #header> <template #header> 最新任务 </template>
最新任务
</template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<div v-for="(item, index) in tasks" :key="`dynamics-${index}`"> <section class="p-24px flex flex-col gap-24px block">
<div> <div
<div class="text-12px flex justify-between"> v-for="(item, index) in tasks"
<span>{{ item.title }}</span> :key="`dynamics-${index}`"
<span class="mr-10">{{ item.user }}</span> class="text-15px flex justify-between"
<span class="mr-10">{{ item.date }}</span> >
</div> <span class="color-#303133">{{ item.title }}</span>
<span class="color-#606266">{{ item.deptName }}</span>
</div> <span class="color-#909399">{{ formatDate(item.startDate, 'YYYY年M月D日') }}</span>
<el-divider height="10px" class="m-4 p-0" style="margin:8px 0" />
</div> </div>
<el-empty v-if="tasks.length == 0" />
</section>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24">
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header> 整改排名 </template>
逾期排行
</template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<div v-for="(item, index) in notice2" :key="`dynamics-${index}`"> <section class="p-24px flex flex-col gap-24px block">
<template v-if="item.type === '资质逾期'"> <div
<div> v-for="(item, index) in notice1"
<div class="text-12px flex justify-between"> :key="`dynamics-${index}`"
<span>{{ item.title }}</span> class="text-15px flex justify-between"
<span class="mr-10">{{ item.days }}</span> >
</div> <span class="color-#303133">{{ item.name }}</span>
<span class="color-#909399">{{ item.count }}</span>
</div>
<el-divider height="10px" class="m-4 p-0" style="margin:8px 0" />
</template>
</div> </div>
<el-empty v-if="notice1.length == 0" />
</section>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px"> <el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24">
<el-card shadow="never"> <el-card shadow="never">
<template #header> <template #header> 资质临期 </template>
整改排行
</template>
<el-skeleton :loading="loading" animated> <el-skeleton :loading="loading" animated>
<div v-for="(item, index) in notice2" :key="`dynamics-${index}`"> <section class="p-24px flex flex-col gap-24px block">
<template v-if="item.type === '整改次数'"> <div
v-for="(item, index) in notice2"
<div> :key="`dynamics-${index}`"
<div class="text-12px flex justify-between"> class="text-15px flex justify-between"
<span>{{ item.title }}</span> >
<span class="mr-10">{{ item.days }}</span> <span class="color-#303133">{{ item.name }}</span>
</div> <span class="color-#909399">{{ item.count }}</span>
</div>
<el-divider height="10px" class="m-4 p-0" style="margin:8px 0" />
</template>
</div> </div>
<el-empty v-if="notice2.length == 0" />
</section>
</el-skeleton> </el-skeleton>
</el-card> </el-card>
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { set } from 'lodash-es' import { HomeApi } from '@/api/home'
import { EChartsOption } from 'echarts' import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { pieOptions, barOptions,lineOptions } from './echarts-data' import { formatDate } from '@/utils/formatTime'
defineOptions({ name: 'Home' }) defineOptions({ name: 'Home' })
const { t } = useI18n()
const loading = ref(true) const loading = ref(true)
const pieOptionsData = reactive<EChartsOption>(pieOptions) as EChartsOption const pieOptionsData = ref({
title: {
text: '90%',
// subtext: '完成率',
const taskNewCard = ref() left: 'center',
top: 'center',
// 使ResizeObserver itemGap: 0,
onMounted(() => { textStyle: {
fontSize: 40,
lineHeight: 40,
padding: [0, 0, 0, 0],
fontWeight: 'bold'
},
subtextStyle: {
color: '#909399',
fontSize: 18,
lineHeight: 18,
padding: [0, 0, 0, 0]
}
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
series: {
name: '任务进度',
type: 'pie',
radius: ['60%', '80%'],
center: ['50%', '50%'],
itemStyle: {
borderColor: '#fff',
borderWidth: 2
},
label: {
formatter: (v) => {
if (v.name) {
return `{row|${v.name}} {v|${v.percent}%} \n{hr|}`
}
return ''
},
padding: [0, 0, 15, 0],
distanceToLabelLine: 0,
rich: {
row: {
padding: [0, 0, 4, 5]
},
v: {
color: '#409EFF',
padding: [0, 0, 4, 0]
},
hr: {
backgroundColor: '#409EFF',
width: '100%',
height: 1
}
}
},
labelLine: {
length2: 0,
lineStyle: {
color: '#409EFF'
}
},
roseType: 'radius',
data: [
{ value: 335, name: '执法一队' },
{ value: 310, name: '执法二队' },
{ value: 234, name: '执法三队' },
{ value: 135, name: '执法四队' },
{ value: 1548, name: '执法五队' }
]
}
}) })
const barOptionsData = ref({
tooltip: {
const tasks = reactive<any>([ trigger: 'axis',
{ axisPointer: {
title: '义县一公司环保信息', type: 'shadow'
date: '2023-01-01', }
user: '张三',
status: 1
}, },
{ grid: {
title: '锦州二公司安全检查', top: 42,
date: '2023-01-02', left: 16,
user: '李四', right: 16,
status: 2 bottom: 16,
containLabel: true
}, },
{ legend: {
title: '北镇三公司环评整改', show: true,
date: '2023-01-03', top: 16,
user: '王五', left: 'center',
status: 1 itemWidth: 10,
itemHeight: 10,
textStyle: {
color: '#333'
}
}, },
{ xAxis: {
title: '凌海四公司排污监测', type: 'category',
date: '2023-01-04', axisTick: {
user: '赵六', show: false
status: 3
}, },
{ axisLine: {
title: '黑山五公司设备巡检', show: false
date: '2023-01-05',
user: '孙七',
status: 2
}, },
{ splitLine: {
title: '义县六公司安全培训', show: true,
date: '2023-01-06', lineStyle: {
user: '周八', type: 'dashed',
status: 1 color: '#E5E7EB'
}
}, },
{ data: [],
title: '大石桥七公司隐患排查', axisLabel: {
date: '2023-01-07', show: true,
user: '吴九', color: '#333'
status: 3 }
}, },
{ yAxis: {
title: '盘锦八公司应急演练', type: 'value',
date: '2023-01-08', max: (v) => {
user: '郑十', return Math.floor(v.max * 1.2 + 1)
status: 2
}, },
{ axisLine: {
title: '营口九公司废水处理', show: false
date: '2023-01-09',
user: '钱十一',
status: 1
}, },
{ axisTick: {
title: '阜新十公司空气监测', show: false
date: '2023-01-10', },
user: '刘十二', splitLine: {
status: 2 lineStyle: {
type: 'dashed',
color: '#E5E7EB'
}
} }
])
const notice2 = reactive<any>([
{
type: '资质逾期',
title: '义县一公司环保信息',
date: '2023-01-01 12:00:00',
days: '逾期1天'
}, },
series: [
{ {
type: '整改次数', name: '执法记录',
title: '义县一公司环保信息', type: 'bar',
date: '2023-01-01 12:00:00', barWidth: 20,
days: '整改1次' stack: '执法记录',
barGap: '30%',
itemStyle: {
color: 'rgba(64, 158, 255, .6)'
}, },
{ data: [70, 35, 70, 60, 20]
type: '资质逾期',
title: '义县一公司环保信息',
date: '2023-01-01 12:00:00',
days: '逾期1天'
}, },
{ {
type: '整改次数', name: '整改次数',
title: '义县一公司环保信息', type: 'bar',
date: '2023-01-01 12:00:00', stack: '整改次数',
days: '整改1次' barWidth: 20,
itemStyle: {
color: 'rgba(103, 194, 58, .6)'
}, },
{ data: [90, 45, 80, 50, 70]
type: '资质逾期',
title: '义县一公司环保信息',
date: '2023-01-01 12:00:00',
days: '逾期1天'
}, },
{ {
type: '整改次数', name: '执法记录',
title: '义县一公司环保信息', type: 'bar',
date: '2023-01-01 12:00:00', barWidth: 20,
days: '整改1次' stack: '执法记录',
barGap: '30%',
itemStyle: {
color: 'rgba(64, 158, 255, 1)'
}, },
{ tooltip: {
type: '资质逾期', show: false
title: '锦州二公司安全检查',
date: '2023-01-02 12:00:00',
days: '逾期2天'
}, },
{ data: [1, 1, 1, 1, 1]
type: '整改次数',
title: '锦州二公司安全检查',
date: '2023-01-02 12:00:00',
days: '整改2次'
}, },
{ {
type: '资质逾期', name: '整改次数',
title: '北镇三公司环评整改', type: 'bar',
date: '2023-01-03 12:00:00', stack: '整改次数',
days: '逾期3天' barWidth: 20,
itemStyle: {
color: 'rgba(103, 194, 58, 1)'
}, },
{ tooltip: {
type: '整改次数', show: false
title: '北镇三公司环评整改',
date: '2023-01-03 12:00:00',
days: '整改3次'
}, },
{ data: [1, 1, 1, 1, 1]
type: '资质逾期', }
title: '凌海四公司排污监测', ]
date: '2023-01-04 12:00:00', })
days: '逾期4天' const lineOptionsData = ref({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
}, },
{ grid: {
type: '整改次数', top: 42,
title: '凌海四公司排污监测', left: 16,
date: '2023-01-04 12:00:00', right: 16,
days: '整改4次' bottom: 16,
containLabel: true
}, },
{ legend: {
type: '资质逾期', show: true,
title: '黑山五公司设备巡检', top: 16,
date: '2023-01-05 12:00:00', left: 'center',
days: '逾期5天' textStyle: {
color: '#333'
}
}, },
{ xAxis: {
type: '整改次数', type: 'category',
title: '黑山五公司设备巡检', data:[],
date: '2023-01-05 12:00:00', axisTick: {
days: '整改5次' show: false
}, },
{ axisLine: {
type: '资质逾期', show: false
title: '义县六公司安全培训',
date: '2023-01-06 12:00:00',
days: '逾期6天'
}, },
{ splitLine: {
type: '整改次数', show: true,
title: '义县六公司安全培训', lineStyle: {
date: '2023-01-06 12:00:00', type: 'dashed',
days: '整改6次' color: '#E5E7EB'
}
}, },
{ axisLabel: {
type: '资质逾期', show: false,
title: '大石桥七公司隐患排查', color: '#333'
date: '2023-01-07 12:00:00', }
days: '逾期7天'
}, },
{ yAxis: {
type: '整改次数', type: 'value',
title: '大石桥七公司隐患排查', axisLine: {
date: '2023-01-07 12:00:00', show: false
days: '整改7次' },
max: (v) => {
return Math.floor(v.max * 1.2 + 1)
},
axisTick: {
show: false
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#E5E7EB'
}
}
}, },
series: [
{ {
type: '资质逾期', name: '任务数',
title: '盘锦八公司应急演练', data: [13253, 34235, 26321, 12340, 24643],
date: '2023-01-08 12:00:00', type: 'line',
days: '逾期8天' smooth: true,
itemStyle: {
color: 'rgba(64, 158, 255, 1)'
},
lineStyle: {
color: 'rgba(64, 158, 255, 1)'
},
areaStyle: {
color: 'rgba(64, 158, 255, .3)'
}
}, },
{ {
type: '整改次数', name: '执法数',
title: '盘锦八公司应急演练', data: [15678, 28943, 31452, 19876, 22345],
date: '2023-01-08 12:00:00', type: 'line',
days: '整改8次' smooth: true,
itemStyle: {
color: 'rgba(103, 194, 58, 1)'
},
lineStyle: {
color: 'rgba(103, 194, 58, 1)'
},
areaStyle: {
color: 'rgba(103, 194, 58, .3)'
} }
]) }
]
})
const queryParams = reactive({
selectWeek: '',
region: ''
})
// const area = ref<any[]>([])
const getUserAccessSource = async () => {
const data = [ //
{ value: 335, name: '执法一队' }, const taskNewCard = ref()
{ value: 310, name: '执法二队' },
{ value: 234, name: '执法三队' }, const tasks = ref<any>([])
{ value: 135, name: '执法四队' },
{ value: 1548, name: '执法五队' } const notice1 = ref<any[]>([])
]
set( const notice2 = ref<any[]>([])
pieOptionsData,
'legend.data', //
data.map((v) => t(v.name)) const reset = () => {
) queryParams.selectWeek = ''
pieOptionsData!.series![0].data = data.map((v) => { queryParams.region = area.value[0].value
getData()
}
//
const getPieData = async () => {
const res = await HomeApi.getPieData(queryParams)
const data = res.completionRate
.sort((a, b) => b.value - a.value)
.map((item: any, index: number) => {
return { return {
name: t(v.name), value: item.pieValue,
value: v.value name: item.name,
itemStyle: {
color: getGradientColor(index, res.completionRate.length)
},
label: {
show: item.pieValue > 0
},
labelLine: {
show: item.pieValue > 0
}
}
})
if (res.taskCompletionRate != 100) {
data.push({
name: '',
value: 100 - Number(res.taskCompletionRate),
itemStyle: {
color: '#fff'
},
label: {
show: false
},
labelLine: {
show: false
} }
}) })
} }
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
// pieOptionsData.value.title.text = `${res.taskCompletionRate}%`
const getWeeklyUserActivity = async () => { pieOptionsData.value.series.data = data
const data = [
{ value: 325, name: '一月' },
{ value: 423, name: '二月' },
{ value: 632, name: '三月' },
{ value: 234, name: '四月' },
{ value: 464, name: '五月' },
{ value: 322, name: '六月' },
{ value: 324, name: '七月' }
]
set(
barOptionsData,
'xAxis.data',
data.map((v) => t(v.name))
)
set(barOptionsData, 'series', [
{
name: '任务数',
data: data.map((v) => v.value),
type: 'bar'
} }
])
// 6
const getS3Data = async () => {
const res = await HomeApi.getTaskNumDoing(queryParams)
let data1 = [] as any
let data2 = [] as any
res.forEach((item: any) => {
data1.push({ name: item.month, value: item.taskCount })
data2.push({ name: item.month, value: item.inspectionCount })
})
lineOptionsData.value.series[0].data = data1
lineOptionsData.value.series[1].data = data2
lineOptionsData.value.xAxis.data = res.map((i) => i.month)
} }
const getAllApi = async () => { //
await Promise.all([ const getS2Data = async () => {
getUserAccessSource(), const res = await HomeApi.getExecCorrection(queryParams)
getWeeklyUserActivity() const data1 = res.map((i) => {
]) return {
name: i.realName,
value: i.inspectionCount
}
})
const data2 = res.map((i) => {
return {
name: i.realName,
value: i.correctionCount
}
})
const axis = res.map((i) => i.realName)
const top = (res[0].inspectionCount % 10) / 10
barOptionsData.value.series[0].data = data1
barOptionsData.value.series[1].data = data2
barOptionsData.value.xAxis.data = axis
barOptionsData.value.series[2].data = new Array(axis.length).fill(top || 0.1)
barOptionsData.value.series[3].data = new Array(axis.length).fill(top || 0.1)
}
//
const getS4Data = async () => {
const res = await HomeApi.getNewTask({ ...queryParams, pageSize: 8, pageNo: 1 })
tasks.value = res.list
}
//
const getS5S6 = async () => {
notice2.value = await HomeApi.getListData({ ...queryParams, type: 1, size: 8 })
notice1.value = await HomeApi.getListData({ ...queryParams, type: 2, size: 8 })
}
//
const getArea = async () => {
area.value = await HomeApi.getArea()
queryParams.region = area.value[0].value
}
const init = async () => {
await getArea()
await getData()
}
//
const getData = async () => {
await Promise.all([getPieData(), getS2Data(), getS3Data(), getS4Data(), getS5S6()])
loading.value = false loading.value = false
} }
getAllApi() //
const getGradientColor = (index, total) => {
let opacity = 1 - index / total + 0.1
if (index == 0) opacity = 1
return `rgba(64, 158, 255, ${opacity > 1 ? 1 : opacity})`
}
init()
</script> </script>
<style scoped lang="scss">
::v-deep(.el-card__header) {
padding: 16px;
color: #303133;
font-size: 14px;
line-height: 24px;
font-weight: bold;
}
::v-deep(.el-card__body) {
padding: 0;
}
.block {
height: 376px;
}
.queryForm {
display: flex;
flex-flow: row nowrap;
.el-form-item--default {
margin-bottom: 20px;
}
.el-form-item {
width: 400px;
margin-right: 20px;
display: flex;
flex-flow: row nowrap;
align-items: center;
}
}
::v-deep(.el-button + .el-button) {
margin-left: 0 !important;
}
</style>

148
src/views/Home/echarts-data.ts

@ -1,148 +0,0 @@
import { EChartsOption } from 'echarts'
const { t } = useI18n()
export const pieOptions: EChartsOption = {
title: {
text: '完成率90%',
left: 'center',
top: '35%',
textStyle: {
fontSize: 16,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
orient: 'horizontal',
bottom: 10,
left: 'center',
data: [
'执法一队',
'执法二队',
'执法三队',
'执法四队',
'执法五队',
]
},
series: [
{
name: t('analysis.userAccessSource'),
type: 'pie',
radius: ['40%', '70%'],
center: ['50%', '40%'],
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
data: [
{ value: 335, name: '执法一队' },
{ value: 310, name: '执法二队' },
{ value: 234, name:'执法三队' },
{ value: 135, name: '执法四队' },
{ value: 1548, name: '执法五队' }
]
}
]
}
export const barOptions: EChartsOption = {
title: {
text: '月均执法任务数',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: 50,
right: 20,
bottom: 20
},
xAxis: {
type: 'category',
data: [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: t('analysis.activeQuantity'),
data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
type: 'bar'
}
]
}
export const lineOptions: EChartsOption = {
title: {
text: '月均执法任务数',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
grid: {
left: 50,
right: 20,
bottom: 20
},
xAxis: {
type: 'category',
data: [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
],
axisTick: {
alignWithLabel: true
}
},
yAxis: {
type: 'value'
},
series: [
{
name: '任务数',
data: [13253, 34235, 26321, 12340, 24643, 1322, 1324],
type: 'line'
},
{
name: '执法数',
data: [15678, 28943, 31452, 19876, 22345, 25678, 18234],
type: 'line'
}
]
}

50
src/views/Home/types.ts

@ -1,50 +0,0 @@
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 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
}

88
src/views/Login/components/QrCodeForm.vue

@ -3,15 +3,30 @@
<el-col :span="24" style="padding-right: 10px; padding-left: 10px"> <el-col :span="24" style="padding-right: 10px; padding-left: 10px">
<img class="topImg" src="@/assets/imgs/screen/login-top.png" alt="logo" /> <img class="topImg" src="@/assets/imgs/screen/login-top.png" alt="logo" />
</el-col> </el-col>
<el-col :span="24" style="padding-right: 10px; padding-left: 10px; margin-bottom:20px; text-align: center"> <el-col
:span="24"
style="padding-right: 10px; padding-left: 10px; margin-bottom: 20px; text-align: center"
>
<img width="320px" height="320px" :src="imageUrl" alt="Converted Image" v-if="imageUrl" /> <img width="320px" height="320px" :src="imageUrl" alt="Converted Image" v-if="imageUrl" />
</el-col> </el-col>
<el-col v-if="!refreshQR" :span="24" style="padding-right: 10px; padding-left: 10px; text-align: center"> <el-col
v-if="!refreshQR"
:span="24"
style="padding-right: 10px; padding-left: 10px; text-align: center"
>
<img class="bottomImg" src="@/assets/imgs/screen/login-bottom.png" alt="logo" /> <img class="bottomImg" src="@/assets/imgs/screen/login-bottom.png" alt="logo" />
</el-col> </el-col>
<el-col v-if="refreshQR" :span="24" style="padding-right: 10px; padding-left: 10px; text-align: center"> <el-col
<img class="bottomImg" src="@/assets/imgs/screen/qrsx.png" alt="logo" @click="handleRefresh" /> v-if="refreshQR"
:span="24"
style="padding-right: 10px; padding-left: 10px; text-align: center"
>
<img
class="bottomImg"
src="@/assets/imgs/screen/qrsx.png"
alt="logo"
@click="handleRefresh"
/>
</el-col> </el-col>
</el-row> </el-row>
</template> </template>
@ -24,7 +39,7 @@ import { LoginStateEnum, useLoginState } from './useLogin'
import router from '@/router' import router from '@/router'
defineOptions({ name: 'QrCodeForm' }) defineOptions({ name: 'QrCodeForm' })
const imageUrl = ref(''); const imageUrl = ref('')
const uuuid = ref('') const uuuid = ref('')
const refreshQR = ref(false) const refreshQR = ref(false)
@ -32,83 +47,84 @@ const { t } = useI18n()
const { handleBackLogin, getLoginState } = useLoginState() const { handleBackLogin, getLoginState } = useLoginState()
const getShow = computed(() => true) const getShow = computed(() => true)
// ID // ID
let intervalId = ref(); let intervalId = ref()
const handleRefresh = () => { const handleRefresh = () => {
window.location.reload() window.location.reload()
} }
const getimg = async () => { const getimg = async () => {
const array = new Uint32Array(4)
const array = new Uint32Array(4); crypto.getRandomValues(array)
crypto.getRandomValues(array); let result = ''
let result = '';
array.forEach((value) => { array.forEach((value) => {
result += value.toString(16).padStart(8, '0'); result += value.toString(16).padStart(8, '0')
}); })
uuuid.value = result; uuuid.value = result
var mockBinaryData = await LoginApi.getCodeWebPic({ var mockBinaryData = await LoginApi.getCodeWebPic({
scene: uuuid.value, scene: uuuid.value,
path: 'sub/common/waiting', path: 'sub/common/waiting',
checkPath: false checkPath: false
}); })
// Base64 // Base64
const binaryString = atob(mockBinaryData); const binaryString = atob(mockBinaryData)
const len = binaryString.length; const len = binaryString.length
const bytes = new Uint8Array(len); const bytes = new Uint8Array(len)
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i); bytes[i] = binaryString.charCodeAt(i)
} }
// Blob // Blob
const blob = new Blob([bytes], { type: 'image/png' }); const blob = new Blob([bytes], { type: 'image/png' })
// URL // URL
imageUrl.value = URL.createObjectURL(blob); imageUrl.value = URL.createObjectURL(blob)
// //
refaulst(); refaulst()
} }
// //
const startTime = Date.now(); const startTime = Date.now()
// 10 // 10
const tenMinutes = 10 *60 * 10000 ; const tenMinutes = 10 * 60 * 10000
// //
const refaulst = () => { const refaulst = () => {
refreshQR.value = false; refreshQR.value = false
// //
if (intervalId) { if (intervalId) {
clearInterval(intervalId.value); clearInterval(intervalId.value)
} }
// 5 // 5
intervalId.value = setInterval(async () => { intervalId.value = setInterval(async () => {
try { try {
// 10 // 10
if (Date.now() - startTime >= tenMinutes) { if (Date.now() - startTime >= tenMinutes) {
clearInterval(intervalId.value); clearInterval(intervalId.value)
console.log('定时器已停止,已过去 10 分钟。'); console.log('定时器已停止,已过去 10 分钟。')
refreshQR.value = true; refreshQR.value = true
return; return
} }
const res = await LoginApi.qrLoginCode({ code: uuuid.value }) const res = await LoginApi.qrLoginCode({ code: uuuid.value })
if (res) { if (res) {
clearInterval(intervalId.value); clearInterval(intervalId.value)
authUtil.setToken(res) authUtil.setToken(res)
router.push({ path: '/' }) router.push({ path: '/' })
} }
} catch (error) { } catch (error) {
console.error('获取扫码状态失败:', error); console.error('获取扫码状态失败:', error)
} }
}, 5000); }, 5000)
} }
onMounted(() => { onMounted(() => {
// getCookie() // getCookie()
getimg() getimg()
}) })
onUnmounted(() => {
//
clearInterval(intervalId.value)
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.expired-text { .expired-text {
@ -118,8 +134,6 @@ onMounted(() => {
} }
.bottomImg { .bottomImg {
width: 320px; width: 320px;
} }
.topImg { .topImg {
height: 200px; height: 200px;

Loading…
Cancel
Save