From 38f0a9145a29f570331f11505968f90bd1c08646 Mon Sep 17 00:00:00 2001 From: batman <978517621@qq.com> Date: 星期一, 06 三月 2023 13:22:33 +0800 Subject: [PATCH] 新修改添加页面 --- src/views/intellectInspect/inspectIndex2/components/inspectList.vue | 411 +++++++ src/views/system/video/index.vue | 250 ++++ src/views/specialWorkSystem/specialIndex/index.vue | 1144 +++++++++++++++++++ src/router/route.ts | 16 src/views/intellectInspect/inspectIndex2/components/unusualList.vue | 404 ++++++ src/api/systemManage/video/index.ts | 37 package.json | 2 src/views/system/video/component/videoDialog.vue | 158 ++ src/views/system/user/component/userDialog.vue | 11 src/views/intellectInspect/inspectIndex2/index.vue | 1003 +++++++++++----- 10 files changed, 3,082 insertions(+), 354 deletions(-) diff --git a/package.json b/package.json index 8b2ab23..c9b6baa 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@element-plus/icons-vue": "^2.0.6", - "@kjgl77/datav-vue3": "^1.2.1", + "@kjgl77/datav-vue3": "^1.4.1", "@wangeditor/editor": "^5.1.14", "axios": "^0.27.2", "countup.js": "^2.2.0", diff --git a/src/api/systemManage/video/index.ts b/src/api/systemManage/video/index.ts new file mode 100644 index 0000000..21aa37b --- /dev/null +++ b/src/api/systemManage/video/index.ts @@ -0,0 +1,37 @@ +import request from '/@/utils/request'; + +export function videoApi() { + return { + // v1 + getVideoList: (data: any) => { + return request({ + url: import.meta.env.VITE_API_URL + `/sysAdmin/camera/find/byCondition`, + method: 'post', + data: data + }); + }, + + addVideo: (data: any) => { + return request({ + url: import.meta.env.VITE_API_URL + `/sysAdmin/camera/add`, + method: 'post', + data: data + }); + }, + + modVideo: (data: any) => { + return request({ + url: import.meta.env.VITE_API_URL + `/sysAdmin/camera/mod`, + method: 'post', + data: data + }); + }, + + delVideo: (cameraId: number | null) => { + return request({ + url: import.meta.env.VITE_API_URL + `/sysAdmin/camera/del?cameraId=${cameraId == null ? null : cameraId}`, + method: 'get' + }); + } + }; +} diff --git a/src/router/route.ts b/src/router/route.ts index 3a95b31..0b49e22 100644 --- a/src/router/route.ts +++ b/src/router/route.ts @@ -112,4 +112,20 @@ title: '巡检首页' } }, + { + path: '/video', + name: 'video', + component: () => import('/@/views/system/video/index.vue'), + meta: { + title: '视频设备管理' + } + }, + { + path: '/specialIndex', + name: 'specialIndex', + component: () => import('/@/views/specialWorkSystem/specialIndex/index.vue'), + meta: { + title: '特殊作业首页' + } + } ]; diff --git a/src/views/intellectInspect/inspectIndex2/components/inspectList.vue b/src/views/intellectInspect/inspectIndex2/components/inspectList.vue new file mode 100644 index 0000000..b8e06d9 --- /dev/null +++ b/src/views/intellectInspect/inspectIndex2/components/inspectList.vue @@ -0,0 +1,411 @@ +<template> + <el-dialog v-model="inspectListDialog" title="当前巡检任务" width="80%" center> + <div class="main-card"> + <el-table :data="tableData" style="width: 100%" stripe border :header-cell-style="{ background: '#fafafa' }"> + <el-table-column label="任务信息" align="center"> + <template #default="scope"> + <div class="left-info"> + <span>{{ scope.row.taskName }},</span> + <p v-if="scope.row.execUserName == null">该任务暂无人认领</p> + <p v-else> + <span class="time">{{ scope.row.taskStatus == 2 ? scope.row.startTime : scope.row.endTime }}</span>由<span class="name">{{ scope.row.execUserName }}</span>进行的巡检任务 + </p> + </div> + </template> + </el-table-column> + <el-table-column prop="taskStatus" label="任务状态" align="center" width="180"> + <template #default="scope"> + <span :style="{color: scope.row.taskStatus == 1 ? '#999' : scope.row.taskStatus == 2 ? '#44b100' : scope.row.taskStatus == 3 ? '#409eff' : 'red'}">{{ scope.row.taskStatus == 1 ? '待巡检' : scope.row.taskStatus == 2 ? '巡检中' : scope.row.taskStatus == 3 ? '已巡检' : '超期未巡检' }}</span> + </template> + </el-table-column> + <el-table-column label="操作" align="center" width="180"> + <template #default="scope"> + <el-button type="text" size="small" v-if="scope.row.taskStatus == 2" @click="toLine(scope.row)">查看实时巡检</el-button> + <el-button type="text" size="small" v-else @click="toDetails('查看', scope.row)">查看巡检记录</el-button> + </template> + </el-table-column> + </el-table> + </div> + <template #footer> + <span class="dialog-footer" style="display: flex;justify-content: right"> + <el-pagination v-model:currentPage="pageIndex" v-model:page-size="pageSize" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> + </span> + </template> + <inspect-record-dialog ref="inspectRecordDialogRef" @refreshInspectRecord="getInspectRecord"></inspect-record-dialog> + </el-dialog> +</template> + +<script lang="ts"> +import { toRefs, reactive, ref, onMounted } from 'vue'; +import { storeToRefs } from 'pinia'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; +import { useUserInfo } from '/@/stores/userInfo'; +import { Session } from '/@/utils/storage'; +import { Edit, View, Plus, Delete, Refresh, Search, Download } from '@element-plus/icons-vue'; +import { ElTable } from 'element-plus'; +import { FormInstance, FormRules, ElMessage } from 'element-plus'; +import { inspectRecordApi } from '/@/api/intellectInspectSystem/inspectRecord'; +import { useRouter } from 'vue-router'; +import inspectRecordDialog from './inspectRecordDialog.vue'; +import { departmentApi } from '/@/api/systemManage/department'; +// 定义接口来定义对象的类型 +interface stateType { + tableData: Array<string>; + unchecked: null | number; + unusual: null | number; + uncheckedList: []; + abnormalList: []; + pageIndex: number; + pageSize: number; + totalSize: number; + workTypeList: Array<type>; + timeType: Array<type>; + classGroupList: Array<classGroup>; + quotaList: []; + departmentList: []; + inspectPointAllList: []; + inspectListDialog: boolean +} +interface type { + id: number; + name: string; +} +interface classGroup { + id: number; + groupName: string; +} +export default { + name: 'inspectList', + components: { inspectRecordDialog }, + setup() { + const router = useRouter(); + const state = reactive<stateType>({ + inspectListDialog: false, + pageIndex: 1, + pageSize: 10, + totalSize: 0, + tableData: [], + unchecked: null, + unusual: null, + departmentList: [], + uncheckedList: [], + abnormalList: [], + workTypeList: [ + { id: 1, name: '日常任务' }, + { id: 2, name: '周期任务' } + ], + timeType: [ + { id: 1, name: '分' }, + { id: 2, name: '小时' }, + { id: 3, name: '日' }, + { id: 4, name: '月' }, + { id: 5, name: '年' } + ], + classGroupList: [], + quotaList: [], + inspectPointAllList: [] + }); + const inspectRecordDialogRef = ref(); + interface User { + name: string; + startTime: string; + endTime: string; + info: string; + } + + // 页面载入时执行方法 + onMounted(() => { + getInspectRecord(); + }); + + const showInspectList = ()=>{ + state.inspectListDialog = true + getInspectRecord(); + } + // 分页获取工作时段列表 + const getInspectRecord = async () => { + const data = { pageSize: state.pageSize, pageIndex: state.pageIndex }; + let res = await inspectRecordApi().getInspectRecordByIndex(data); + if (res.data.code === '200') { + state.tableData = res.data.data.records; + state.totalSize = res.data.data.total; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + const handleSizeChange = (val: number) => { + state.pageSize = val; + getInspectRecord(); + }; + const handleCurrentChange = (val: number) => { + state.pageIndex = val; + getInspectRecord(); + }; + + const toLine = (item) => { + console.log(item,'item') + let id = item.id; + console.log(id,'id') + router.push({ + path: 'intelligentLine', + query: { + id: id + } + }); + }; + + const toOverTime = (id) => { + console.log(state.uncheckedList, 'list'); + router.push({ + path: 'inspectRecord', + query: { + id: id, + } + }); + }; + const toDetails = (type: string, item) => { + inspectRecordDialogRef.value.showInspectRecordDialog(type, item, state.workTypeList, state.departmentList, state.timeType, state.classGroupList, state.quotaList, state.inspectPointAllList); + }; + return { + View, + Edit, + Delete, + Refresh, + Plus, + router, + inspectRecordDialogRef, + showInspectList, + toLine, + toOverTime, + toDetails, + handleSizeChange, + handleCurrentChange, + ...toRefs(state) + }; + } +}; +</script> + +<style scoped lang="scss"> +$homeNavLengh: 8; +@media screen and (min-width: 1366px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 16px; + align-items: center; + padding: 10px 15px; + background: #ffeb87; + border-radius: 8px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 22px; + color: #f3001e; + margin: 0 4px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 16px; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} +@media screen and (min-width: 1200px) and (max-width: 1366px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 14px; + align-items: center; + padding: 6px 10px; + background: #ffeb87; + border-radius: 4px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 18px; + color: #f3001e; + margin: 0 2px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 15px; + color: #333; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} +@media screen and (max-width: 1200px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 14px; + align-items: center; + padding: 2px 6px; + background: #ffeb87; + border-radius: 4px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 16px; + color: #f3001e; + margin: 0 1px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 12px; + color: #333; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} + +.home-container { + height: calc(100vh - 144px); + box-sizing: border-box; + overflow: hidden; + .homeCard { + width: 100%; + padding: 20px; + box-sizing: border-box; + background: #fff; + border-radius: 4px; + + .title { + font-size: 20px; + font-weight: bolder; + } + .main-card { + width: 100%; + height: 100%; + } + &:last-of-type { + position: relative; + padding-top: 0; + height: calc(100% - 60px); + } + } + .el-row { + display: flex; + align-items: center; + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + .grid-content { + align-items: center; + min-height: 36px; + } + } +} +.el-input { + width: 100% !important; +} +.el-date-editor::v-deep { + width: 100%; +} +.el-select { + width: 100%; +} +:deep(.el-textarea.is-disabled .el-textarea__inner) { + background-color: var(--el-card-bg-color); + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__inner) { + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__wrapper) { + background-color: var(--el-card-bg-color); +} +</style> diff --git a/src/views/intellectInspect/inspectIndex2/components/unusualList.vue b/src/views/intellectInspect/inspectIndex2/components/unusualList.vue new file mode 100644 index 0000000..c9059d3 --- /dev/null +++ b/src/views/intellectInspect/inspectIndex2/components/unusualList.vue @@ -0,0 +1,404 @@ +<template> + <el-dialog v-model="unusualListDialog" title="当前巡检任务" width="90%" center> + <div class="main-card"> + <el-table :data="tableData" style="width: 100%" stripe border :header-cell-style="{ background: '#fafafa' }"> + <el-table-column label="工单编号" align="center"/> + <el-table-column label="异常巡检点" align="center"/> + <el-table-column label="巡检(发现)时间" align="center"/> + <el-table-column label="所属巡检任务" align="center"/> + <el-table-column label="设备/区域名称" align="center"/> + <el-table-column label="正常参考值" align="center"/> + <el-table-column label="实际巡检值" align="center"/> + <el-table-column label="隐患处置人" align="center"/> + <el-table-column label="电话" align="center"/> + <el-table-column prop="taskStatus" label="处置状态" align="center" width="180"> + <template #default="scope"> + <span :style="{color: scope.row.taskStatus == 1 ? '#999' : scope.row.taskStatus == 2 ? '#44b100' : scope.row.taskStatus == 3 ? '#409eff' : 'red'}"> + {{ scope.row.taskStatus == 1 ? '待巡检' : scope.row.taskStatus == 2 ? '巡检中' : scope.row.taskStatus == 3 ? '已巡检' : '超期未巡检' }} + </span> + </template> + </el-table-column> + <el-table-column label="处置描述反馈" align="center"/> + <el-table-column label="操作" align="center" width="190" fixed="right"> + <template #default="scope"> + <el-button type="text" size="small">验收</el-button> + <el-button type="text" size="small">查看现场照片</el-button> + </template> + </el-table-column> + </el-table> + </div> + <template #footer> + <span class="dialog-footer" style="display: flex;justify-content: right"> + <el-pagination v-model:currentPage="pageIndex" v-model:page-size="pageSize" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> + </span> + </template> + <inspect-record-dialog ref="inspectRecordDialogRef" @refreshInspectRecord="getInspectRecord"></inspect-record-dialog> + </el-dialog> +</template> + +<script lang="ts"> +import { toRefs, reactive, ref, onMounted } from 'vue'; +import { storeToRefs } from 'pinia'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; +import { useUserInfo } from '/@/stores/userInfo'; +import { Session } from '/@/utils/storage'; +import { Edit, View, Plus, Delete, Refresh, Search, Download } from '@element-plus/icons-vue'; +import { ElTable } from 'element-plus'; +import { FormInstance, FormRules, ElMessage } from 'element-plus'; +import { inspectRecordApi } from '/@/api/intellectInspectSystem/inspectRecord'; +import { useRouter } from 'vue-router'; +import inspectRecordDialog from './inspectRecordDialog.vue'; +import { departmentApi } from '/@/api/systemManage/department'; +// 定义接口来定义对象的类型 +interface stateType { + tableData: Array<string>; + unchecked: null | number; + unusual: null | number; + uncheckedList: []; + abnormalList: []; + pageIndex: number; + pageSize: number; + totalSize: number; + workTypeList: Array<type>; + classGroupList: Array<classGroup>; + quotaList: []; + departmentList: []; + inspectPointAllList: []; + unusualListDialog: boolean +} +interface type { + id: number; + name: string; +} +interface classGroup { + id: number; + groupName: string; +} +export default { + name: 'inspectList', + components: { inspectRecordDialog }, + setup() { + const router = useRouter(); + const state = reactive<stateType>({ + unusualListDialog: false, + pageIndex: 1, + pageSize: 10, + totalSize: 0, + tableData: [], + unchecked: null, + unusual: null, + departmentList: [], + uncheckedList: [], + abnormalList: [], + workTypeList: [ + { id: 1, name: '日常任务' }, + { id: 2, name: '周期任务' } + ], + classGroupList: [], + quotaList: [], + inspectPointAllList: [] + }); + const inspectRecordDialogRef = ref(); + interface User { + name: string; + startTime: string; + endTime: string; + info: string; + } + + // 页面载入时执行方法 + onMounted(() => { + + }); + + const showUnusualList = ()=>{ + state.unusualListDialog = true + getInspectRecord(); + } + // 分页获取工作时段列表 + const getInspectRecord = async () => { + const data = { pageSize: state.pageSize, pageIndex: state.pageIndex }; + let res = await inspectRecordApi().getInspectRecordByIndex(data); + if (res.data.code === '200') { + state.tableData = res.data.data.records; + state.totalSize = res.data.data.total; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + const handleSizeChange = (val: number) => { + state.pageSize = val; + getInspectRecord(); + }; + const handleCurrentChange = (val: number) => { + state.pageIndex = val; + getInspectRecord(); + }; + + const toLine = (item) => { + console.log(item,'item') + let id = item.id; + console.log(id,'id') + router.push({ + path: 'intelligentLine', + query: { + id: id + } + }); + }; + + const toOverTime = (id) => { + console.log(state.uncheckedList, 'list'); + router.push({ + path: 'inspectRecord', + query: { + id: id, + } + }); + }; + const toDetails = (type: string, item: object) => { + + }; + return { + View, + Edit, + Delete, + Refresh, + Plus, + router, + inspectRecordDialogRef, + showUnusualList, + toLine, + toOverTime, + toDetails, + handleSizeChange, + handleCurrentChange, + ...toRefs(state) + }; + } +}; +</script> + +<style scoped lang="scss"> +$homeNavLengh: 8; +@media screen and (min-width: 1366px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 16px; + align-items: center; + padding: 10px 15px; + background: #ffeb87; + border-radius: 8px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 22px; + color: #f3001e; + margin: 0 4px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 16px; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} +@media screen and (min-width: 1200px) and (max-width: 1366px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 14px; + align-items: center; + padding: 6px 10px; + background: #ffeb87; + border-radius: 4px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 18px; + color: #f3001e; + margin: 0 2px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 15px; + color: #333; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} +@media screen and (max-width: 1200px) { + .topCard { + display: flex; + align-items: center; + justify-content: space-between; + font-weight: bolder; + + .top-info { + display: flex; + font-size: 14px; + align-items: center; + padding: 2px 6px; + background: #ffeb87; + border-radius: 4px; + border: 1px solid #ffae00; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 16px; + color: #f3001e; + margin: 0 1px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .left-info { + width: 70%; + display: flex; + align-items: center; + justify-content: left; + font-size: 12px; + color: #333; + overflow-x: auto; + & > span { + white-space: nowrap; + } + p { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + & > span { + white-space: nowrap; + } + } + } +} + +.home-container { + height: calc(100vh - 144px); + box-sizing: border-box; + overflow: hidden; + .homeCard { + width: 100%; + padding: 20px; + box-sizing: border-box; + background: #fff; + border-radius: 4px; + + .title { + font-size: 20px; + font-weight: bolder; + } + .main-card { + width: 100%; + height: 100%; + } + &:last-of-type { + position: relative; + padding-top: 0; + height: calc(100% - 60px); + } + } + .el-row { + display: flex; + align-items: center; + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + .grid-content { + align-items: center; + min-height: 36px; + } + } +} +.el-input { + width: 100% !important; +} +.el-date-editor::v-deep { + width: 100%; +} +.el-select { + width: 100%; +} +:deep(.el-textarea.is-disabled .el-textarea__inner) { + background-color: var(--el-card-bg-color); + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__inner) { + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__wrapper) { + background-color: var(--el-card-bg-color); +} +</style> diff --git a/src/views/intellectInspect/inspectIndex2/index.vue b/src/views/intellectInspect/inspectIndex2/index.vue index 2e64240..c530dfd 100644 --- a/src/views/intellectInspect/inspectIndex2/index.vue +++ b/src/views/intellectInspect/inspectIndex2/index.vue @@ -1,62 +1,174 @@ <template> <div class="home-container"> <div style="height: 100%"> - <div class="homeCard topCard"> - <div class="title">当前巡检任务</div> - <div class="top-info" v-if="unchecked != 0 || unusual != 0"> - <el-icon :size="18" color="#F3001E" style="margin-right: 4px"><BellFilled /></el-icon> - 预警消息: - <div v-if="unchecked != 0"> + <div class="topChart"> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">年度巡检异常趋势</span> + </div> + <div class="chart" :id="xjLine"></div> + </div> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">异常区域设备统计</span> + <el-switch + v-model="chartStatus" + class="ml-2" + inline-prompt + style="--el-switch-on-color: #13ce66; --el-switch-off-color: #13ce66" + active-text="区域" + inactive-text="设备" + /> + </div> + <dv-active-ring-chart :config="conf" class="chart"/> + <el-radio-group v-model="period" label="size control" size="small" height="250px" style="display: flex;justify-content: center;margin-top: 10px"> + <el-radio-button label="week">近7天</el-radio-button> + <el-radio-button label="month">近30天</el-radio-button> + <el-radio-button label="season">近90天</el-radio-button> + <el-radio-button label="year">近一年</el-radio-button> + </el-radio-group> + </div> + </div> + <div class="midChart"> + <div class="chart-item"> + <div class="chart-tit"> + <div style="display: flex;align-items: center"> + <span class="tit">当前巡检任务</span> + <div class="top-info" v-if="unchecked != 0 || unusual != 0"> + <el-icon :size="18" color="#F3001E" style="margin-right: 4px"><BellFilled /></el-icon> + <div>预警消息:</div> + <div v-if="unchecked != 0"> 当日超期未巡检任务<el-tooltip - class="box-item" - effect="light" - content="查看相关记录" - placement="bottom-start" - ><span @click="toOverTime(4)">{{ unchecked }}</span></el-tooltip>个 - </div> - <span v-if="unchecked != 0 && unusual != 0">,</span> - <div v-if="unusual != 0"> + class="box-item" + effect="light" + content="查看相关记录" + placement="bottom-start" + ><span @click="toOverTime(4)">{{ unchecked }}</span></el-tooltip>个 + </div> + <span v-if="unchecked != 0 && unusual != 0">,</span> + <div v-if="unusual != 0"> 存在异常任务<el-tooltip - class="box-item" - effect="light" - content="查看相关记录" - placement="bottom-start" - ><span @click="toOverTime(5)">{{ unusual }}</span - ></el-tooltip>个 + class="box-item" + effect="light" + content="查看相关记录" + placement="bottom-start" + ><span @click="toOverTime(5)">{{ unusual }}</span + ></el-tooltip>个 + </div> + 。 </div> - 。 + </div> + <div class="checkAll" @click="checkAllRecord()"> + 全部记录>> + </div> </div> - </div> - <div class="homeCard"> - <div class="main-card"> - <div class="list"> - <div class="cardTop" v-for="(item, index) in tableData" :key="index"> - <div class="left-info"> - <span class="num">{{ pageSize * (pageIndex - 1) + index + 1 }}、</span> - <span class="place">{{ item.taskName }},</span> - <p v-if="item.execUserName == null">该任务暂无人认领</p> - <p v-else> - <span class="time">{{ item.taskStatus == 2 ? item.startTime : item.endTime }}</span - >由<span class="name">{{ item.execUserName }}</span - >进行的巡检任务 - </p> - </div> - <div class="mid-info"> - 任务状态:<span :class="item.taskStatus == 1 ? 'grey' : item.taskStatus == 2 ? 'green' : item.taskStatus == 3 ? 'blue' : 'red'">{{ item.taskStatus == 1 ? '待巡检' : item.taskStatus == 2 ? '巡检中' : item.taskStatus == 3 ? '已巡检' : '超期未巡检' }}</span> - </div> - <div class="right-info"> - <div v-if="item.taskStatus == 2" @click="toLine(item)" class="checkBtn">查看实时巡检</div> - <div v-else class="reviewBtn" @click="toDetails('查看', item)">[查看巡检记录]</div> - </div> - </div> + <div class="chart"> +<!-- <el-table :data="tableData" style="width: 100%" stripe border>--> +<!-- <el-table-column label="任务信息" align="center">--> +<!-- <template #default="scope">--> +<!-- <div class="left-info">--> +<!-- <span>{{ scope.row.taskName }},</span>--> +<!-- <p v-if="scope.row.execUserName == null">该任务暂无人认领</p>--> +<!-- <p v-else>--> +<!-- <span class="time">{{ scope.row.taskStatus == 2 ? scope.row.startTime : scope.row.endTime }}</span>由<span class="name">{{ scope.row.execUserName }}</span>进行的巡检任务--> +<!-- </p>--> +<!-- </div>--> +<!-- </template>--> +<!-- </el-table-column>--> +<!-- <el-table-column prop="taskStatus" label="任务状态" align="center" width="180">--> +<!-- <template #default="scope">--> +<!-- <span :class="scope.row.taskStatus == 1 ? 'grey' : scope.row.taskStatus == 2 ? 'green' : scope.row.taskStatus == 3 ? 'blue' : 'red'">{{ scope.row.taskStatus == 1 ? '待巡检' : scope.row.taskStatus == 2 ? '巡检中' : scope.row.taskStatus == 3 ? '已巡检' : '超期未巡检' }}</span>--> +<!-- </template>--> +<!-- </el-table-column>--> +<!-- <el-table-column label="操作" align="center" width="180">--> +<!-- <template #default="scope">--> +<!-- <el-button type="text" v-if="scope.row.taskStatus == 2" @click="toLine(scope.row)" class="checkBtn">查看实时巡检</el-button>--> +<!-- <el-button type="text" v-else class="reviewBtn" @click="toDetails('查看', scope.row)">查看巡检记录</el-button>--> +<!-- </template>--> +<!-- </el-table-column>--> +<!-- </el-table>--> + <div class="list"> + <div class="list-tit"> + <span class="w60">任务信息</span> + <span class="w20">任务状态</span> + <span class="w20">操作</span> </div> - <div class="pageBtn"> - <el-pagination v-model:currentPage="pageIndex" v-model:page-size="pageSize" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" /> + <div class="cardTop" v-for="(item, index) in tableData" :key="index"> + <div class="l-info"> + <span class="place">{{ item.taskName }},</span> + <p v-if="item.execUserName == null">该任务暂无人认领</p> + <p v-else> + <span class="time">{{ item.taskStatus == 2 ? item.startTime : item.endTime }}</span>由<span class="name">{{ item.execUserName }}</span + >进行的巡检任务 + </p> + </div> + <div class="m-info"> + 任务状态:<span :class="item.taskStatus == 1 ? 'grey' : item.taskStatus == 2 ? 'green' : item.taskStatus == 3 ? 'blue' : 'red'">{{ item.taskStatus == 1 ? '待巡检' : item.taskStatus == 2 ? '巡检中' : item.taskStatus == 3 ? '已巡检' : '超期未巡检' }}</span> + </div> + <div class="r-info"> + <el-button type="text" v-if="item.taskStatus == 2" @click="toLine(item)" size="small">查看实时巡检</el-button> + <el-button type="text" v-else class="reviewBtn" @click="toDetails('查看', item)" size="small">查看巡检记录</el-button> + </div> </div> + </div> +<!-- <div class="pageBtn">--> +<!-- <el-pagination v-model:currentPage="pageIndex" v-model:page-size="pageSize" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />--> +<!-- </div>--> </div> + </div> </div> + <div class="midChart"> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">巡检异常清单</span> + <div class="checkAll" @click="checkAllList()"> + 全部记录>> + </div> + </div> + <div class="chart"> + <div class="list"> + <div class="list-tit"> + <span class="w10">工单编号</span> + <span class="w10">异常巡检点</span> + <span class="w10">巡检(发现)时间</span> + <span class="w10">所属巡检任务</span> + <span class="w10">设备/区域名称</span> + <span class="w10">正常参考值</span> + <span class="w10">实际巡检值</span> + <span class="w10">隐患处置人</span> + <span class="w10">电话</span> + <span class="w10">处置状态</span> + <span class="w10">处置描述反馈</span> + <span class="w15">操作</span> + </div> + <div class="cardTop" v-for="(item, index) in unusualData" :key="index"> + <span class="w10">{{item.num}}</span> + <span class="w10">{{item.spot}}</span> + <span class="w10">{{item.time}}</span> + <span class="w10">{{item.job}}</span> + <span class="w10">{{item.area}}</span> + <span class="w10">{{item.refer}}</span> + <span class="w10">{{item.real}}</span> + <span class="w10">{{item.name}}</span> + <span class="w10">{{item.phone}}</span> + <span class="w10">{{item.status}}</span> + <span class="w10">{{item.describe}}</span> + <span class="w15"> + <el-button type="text" @click="toLine(item)" size="small">验收</el-button> + <el-button type="text" @click="toPhotos('查看', item)" size="small">查看现场照片</el-button> + </span> + </div> + </div> +<!-- <div class="pageBtn">--> +<!-- <el-pagination v-model:currentPage="pageIndex" v-model:page-size="pageSize" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />--> +<!-- </div>--> + </div> + </div> + </div> </div> <inspect-record-dialog ref="inspectRecordDialogRef" @refreshInspectRecord="getInspectRecord"></inspect-record-dialog> + <inspect-list ref="inspectListRef"></inspect-list> + <unusual-list ref="unusualListRef"></unusual-list> </div> </template> @@ -71,11 +183,15 @@ import { FormInstance, FormRules, ElMessage } from 'element-plus'; import { inspectRecordApi } from '/@/api/intellectInspectSystem/inspectRecord'; import { useRouter } from 'vue-router'; +import * as echarts from 'echarts' import inspectRecordDialog from './components/inspectRecordDialog.vue'; +import inspectList from './components/inspectList.vue'; +import unusualList from './components/unusualList.vue'; import { departmentApi } from '/@/api/systemManage/department'; // 定义接口来定义对象的类型 interface stateType { tableData: Array<string>; + unusualData: Array<any>; unchecked: null | number; unusual: null | number; uncheckedList: []; @@ -89,6 +205,9 @@ classGroupList: Array<classGroup>; quotaList: []; inspectPointAllList: []; + conf:{}; + chartStatus:boolean; + period: string } interface type { id: number; @@ -100,16 +219,73 @@ } export default { name: 'workingHours', - components: { inspectRecordDialog }, + components: { inspectRecordDialog, inspectList, unusualList }, setup() { const router = useRouter(); + const xjLine = ref("eChartXjLine" + Date.now() + Math.random()) const state = reactive<stateType>({ pageIndex: 1, - pageSize: 10, + pageSize: 4, totalSize: 0, tableData: [], + unusualData: [ + { + num: '202302280001', + spot: '70736', + time: '2023-03-02 17:44:25', + job: '甲醇车间XXX巡检', + area: 'xxx设备', + refer: '8.9~10Mpa', + real: '15.6Mpa', + name: '黄公子', + phone: '15261806176', + status: '待验收', + describe: '更换法兰更换法兰更换法兰更换法兰更换法兰更换法兰' + }, + { + num: '202302280001', + spot: '70736', + time: '2023-03-02 17:44:25', + job: '甲醇车间XXX巡检', + area: 'xxx设备', + refer: '8.9~10Mpa', + real: '15.6Mpa', + name: '黄公子', + phone: '15261806176', + status: '待验收', + describe: '更换法兰更换法兰更换法兰更换法兰更换法兰更换法兰' + }, + { + num: '202302280001', + spot: '70736', + time: '2023-03-02 17:44:25', + job: '甲醇车间XXX巡检', + area: 'xxx设备', + refer: '8.9~10Mpa', + real: '15.6Mpa', + name: '黄公子', + phone: '15261806176', + status: '待验收', + describe: '更换法兰更换法兰更换法兰更换法兰更换法兰更换法兰' + }, + { + num: '202302280001', + spot: '70736', + time: '2023-03-02 17:44:25', + job: '甲醇车间XXX巡检', + area: 'xxx设备', + refer: '8.9~10Mpa', + real: '15.6Mpa', + name: '黄公子', + phone: '15261806176', + status: '待验收', + describe: '更换法兰更换法兰更换法兰更换法兰更换法兰更换法兰' + } + ], unchecked: null, unusual: null, + chartStatus: true, + period: 'month', uncheckedList: [], abnormalList: [], workTypeList: [ @@ -126,9 +302,43 @@ ], classGroupList: [], quotaList: [], - inspectPointAllList: [] + inspectPointAllList: [], + conf:{ + radius: '75%', + activeRadius: '80%', + lineWidth: 24, + digitalFlopStyle: { + fontSize: 25, + fill: '#000', + }, + textColor: '#000', + data: [ + { + name: '区域1', + value: 98, + }, + { + name: '区域2', + value: 150, + }, + { + name: '区域3', + value: 62, + }, + { + name: '区域4', + value: 54, + }, + { + name: '区域5', + value: 54, + } + ] + } }); const inspectRecordDialogRef = ref(); + const inspectListRef = ref(); + const unusualListRef = ref(); interface User { name: string; startTime: string; @@ -141,7 +351,102 @@ getInspectRecord(); getDayData(); getDepartmentData(); + initXjLine() }); + const checkAllRecord =()=>{ + inspectListRef.value.departmentList = state.departmentList + inspectListRef.value.showInspectList() + } + const checkAllList =()=>{ + unusualListRef.value.showUnusualList() + } + type EChartsOption = echarts.EChartsOption + const initXjLine =()=>{ + let dom = document.getElementById(xjLine.value); + let myChart = echarts.init(dom); + + let option: EChartsOption; + + option = { + tooltip: { + trigger: 'axis' + }, + legend: { + data: ['总趋势', '事业部'], + height: '15%', + top: 0, + bottom: 0, + padding:[1,1,1,0] + }, + grid: { + top: '15%', + left: '3%', + right: '3%', + bottom: 0, + containLabel: true + }, + toolbox: { + feature: { + // saveAsImage: {} + } + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: ['四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月', '一月', '二月', '三月'] + }, + yAxis: { + type: 'value' + }, + series: [ + { + name: '总趋势', + type: 'line', + stack: 'Total', + data: [120, 132, 101, 134, 90, 120, 132, 101, 134, 90, 230, 210], + label:{ + show: true, + color: '#95d475', + fontSize: 12 + }, + lineStyle:{ + width: 1, + color: '#95d475' + }, + itemStyle:{ + color: '#95d475', + borderColor: '#fff', + borderWidth: 2 + } + }, + { + name: '事业部', + type: 'line', + stack: 'Total', + data: [220, 182, 191, 234, 290, 220, 182, 191, 234, 290, 330, 310], + label:{ + show: true, + color: '#337ecc', + fontSize: 12 + }, + lineStyle:{ + width: 1, + color: '#337ecc' + }, + itemStyle:{ + color: '#337ecc', + borderColor: '#fff', + borderWidth: 2 + } + } + ] + } + + option && myChart.setOption(option); + window.addEventListener("resize",function (){ + myChart.resize(); + }); + } // 分页获取工作时段列表 const getInspectRecord = async () => { @@ -222,9 +527,14 @@ Edit, Delete, Refresh, + xjLine, Plus, router, inspectRecordDialogRef, + inspectListRef, + unusualListRef, + checkAllRecord, + checkAllList, toLine, toOverTime, toDetails, @@ -239,319 +549,328 @@ <style scoped lang="scss"> $homeNavLengh: 8; @media screen and (min-width: 1366px) { - .topCard { - display: flex; - align-items: center; - justify-content: space-between; - font-weight: bolder; - .top-info { - display: flex; - font-size: 16px; - align-items: center; - padding: 10px 15px; - background: #ffeb87; - border-radius: 8px; - border: 1px solid #ffae00; - - & > div { - vertical-align: middle; - white-space: nowrap; - span { - font-size: 22px; - color: #f3001e; - margin: 0 4px; - cursor: pointer; - - &:hover{ - text-decoration: underline; - } - } - } - } - } - .left-info { - width: 70%; - display: flex; - align-items: center; - justify-content: left; - font-size: 18px; - color: #333; - overflow-x: auto; - & > span { - white-space: nowrap; - } - p { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - & > span { - white-space: nowrap; - } - } - } - .mid-info { - width: 20%; - font-size: 18px; - color: #333; - } - .right-info { - width: 10%; - display: flex; - justify-content: right; - align-items: center; - font-size: 16px; - color: #fff; - - div { - white-space: nowrap; - } - } } @media screen and (min-width: 1200px) and (max-width: 1366px) { - .topCard { - display: flex; - align-items: center; - justify-content: space-between; - font-weight: bolder; - .top-info { - display: flex; - font-size: 14px; - align-items: center; - padding: 6px 10px; - background: #ffeb87; - border-radius: 4px; - border: 1px solid #ffae00; - - & > div { - vertical-align: middle; - white-space: nowrap; - span { - font-size: 18px; - color: #f3001e; - margin: 0 2px; - cursor: pointer; - - &:hover{ - text-decoration: underline; - } - } - } - } - } - .left-info { - width: 70%; - display: flex; - align-items: center; - justify-content: left; - font-size: 15px; - color: #333; - overflow-x: auto; - & > span { - white-space: nowrap; - } - p { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - & > span { - white-space: nowrap; - } - } - } - .mid-info { - width: 20%; - font-size: 15px; - color: #333; - } - .right-info { - width: 10%; - display: flex; - justify-content: right; - align-items: center; - font-size: 13px; - color: #fff; - div { - white-space: nowrap; - } - } } @media screen and (max-width: 1200px) { - .topCard { - display: flex; - align-items: center; - justify-content: space-between; - font-weight: bolder; - .top-info { - display: flex; - font-size: 14px; - align-items: center; - padding: 2px 6px; - background: #ffeb87; - border-radius: 4px; - border: 1px solid #ffae00; - - & > div { - vertical-align: middle; - white-space: nowrap; - span { - font-size: 16px; - color: #f3001e; - margin: 0 1px; - cursor: pointer; - - &:hover{ - text-decoration: underline; - } - } - } - } - } - .left-info { - width: 70%; - display: flex; - align-items: center; - justify-content: left; - font-size: 12px; - color: #333; - overflow-x: auto; - & > span { - white-space: nowrap; - } - p { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - & > span { - white-space: nowrap; - } - } - } - .mid-info { - width: 20%; - font-size: 12px; - color: #333; - } - .right-info { - width: 10%; - display: flex; - justify-content: right; - align-items: center; - font-size: 12px; - color: #fff; - div { - white-space: nowrap; - } - } } .home-container { height: calc(100vh - 144px); box-sizing: border-box; overflow: hidden; - .homeCard { - width: 100%; - padding: 20px; - box-sizing: border-box; - background: #fff; - border-radius: 4px; - .title { + .topChart{ + height: calc((100% - 40px) / 3); + width: 100%; + background: #fff; + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 20px; + padding: 20px 20px 90px; + + .chart-item{ + width: 70%; + height: 120%; + padding-right: 10px; + + &:last-of-type{ + width: 30%; + height: 100%; + padding-right: 0; + padding-left: 10px; + position: relative; + } + + .chart-tit{ + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + .tit{ font-size: 20px; font-weight: bolder; + } + :deep(.el-switch__core){ + width: 120px; + } } - .main-card { - width: 100%; - height: 100%; - .cardTop { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 10px; - background: #daf3ff; - padding: 10px 15px; - border-radius: 8px; - - .left-info { - .num { - font-weight: bolder; - margin-right: 10px; - } - .place { - font-weight: bolder; - } - .time { - font-weight: bolder; - margin-right: 5px; - } - .name { - font-weight: bolder; - margin: 0 5px; - font-weight: bolder; - } - } - .mid-info { - span { - font-weight: bolder; - } - - .grey { - color: #999; - } - .green { - color: #44b100; - } - .blue { - color: #409eff; - } - .red { - color: red; - } - } - .right-info { - .checkBtn { - padding: 10px 15px; - background: #409eff; - border-radius: 4px; - cursor: pointer; - } - - .reviewBtn { - margin: 10px 15px; - cursor: pointer; - color: #44b100; - } - } - } - .list { - height: calc(100% - 60px); - overflow-y: auto; - } - .pageBtn { - position: absolute; - bottom: 15px; - right: 20px; - height: 60px; - display: flex; - align-items: center; - justify-content: right; - - .demo-pagination-block + .demo-pagination-block { - margin-top: 10px; - } - .demo-pagination-block .demonstration { - margin-bottom: 16px; - } - } + .chart{ + width: 100%; + height: 100%; } - &:last-of-type { - position: relative; - padding-top: 0; - height: calc(100% - 60px); + .el-radio-group{ + width: 100%; + flex-wrap: nowrap; + position: absolute; + left: 50%; + transform: translateX(-50%); } + :deep(.active-ring-info){ + .active-ring-name{ + font-size: 1.5rem !important; + text-align: center; + } + } + } } + .midChart{ + height: calc((100% - 40px) / 3); + width: 100%; + background: #fff; + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 20px; + padding: 20px; + + .chart-item{ + width: 100%; + height: 100%; + padding: 0 0 20px; + + .chart-tit{ + width: 100%; + height: 15%; + display: flex; + align-items: center; + justify-content: space-between; + .tit{ + font-size: 20px; + font-weight: bolder; + } + :deep(.el-switch__core){ + width: 120px; + + } + .top-info { + display: flex; + font-size: 14px; + align-items: center; + background: #ffeb87; + padding: 4px 15px; + margin-left: 20px; + border-radius: 2px; + border: 1px solid #ffae00; + & > div { + vertical-align: middle; + white-space: nowrap; + height: 100%; + span { + color: #f3001e; + margin: 0 4px; + font-size: 18px; + cursor: pointer; + font-weight: bolder; + + &:hover{ + text-decoration: underline; + } + } + } + } + .checkAll{ + cursor: pointer; + &:hover{ + color: #409eff + } + } + } + .chart{ + width: 100%; + height: 85%; + margin-top: 10px; + + .el-table{ + height: 100% !important; + :deep(.el-table__inner-wrapper){ + height: 100% !important; + .el-table__header-wrapper{ + height: 20% !important; + } + .el-table__body-wrapper{ + height: 80% !important; + .el-scrollbar__view{ + height: 100% !important; + .el-table__body{ + height: 100% !important; + + .el-table__row{ + height: 20% !important; + } + } + } + } + } + } + .list { + height: 100%; + margin-top: 10px; + border: 1px solid #ebeef5; + + .list-tit{ + width: 100%; + height: 20%; + display: flex; + align-items: center; + border-bottom: 1px solid #ebeef5; + + span{ + text-align: center; + padding: 10px 0; + } + + .w60{ + width: 60%; + border-right: 1px solid #ebeef5; + } + .w20{ + width: 20%; + border-right: 1px solid #ebeef5; + + &:last-of-type{ + border-right: none; + } + } + .w15{ + width: 15%; + border-right: 1px solid #ebeef5; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .w10{ + width: 10%; + border-right: 1px solid #ebeef5; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + } + + .cardTop { + display: flex; + width: 100%; + height: 20%; + align-items: center; + border-bottom: 1px solid #ebeef5; + + &:last-of-type{ + border-bottom: none; + } + span{ + text-align: center; + padding: 10px 0; + } + .l-info{ + width: 60%; + height: 100%; + border-right: 1px solid #ebeef5; + display: flex; + align-items: center; + padding: 0 20px; + + .num { + font-weight: bolder; + margin-right: 10px; + } + .place { + font-weight: bolder; + } + .time { + font-weight: bolder; + margin-right: 5px; + } + .name { + font-weight: bolder; + margin: 0 5px; + font-weight: bolder; + } + } + .m-info{ + height: 100%; + width: 20%; + display: flex; + align-items: center; + border-right: 1px solid #ebeef5; + justify-content: center; + + span { + font-weight: bolder; + } + + .grey { + color: #999; + } + .green { + color: #44b100; + } + .blue { + color: #409eff; + } + .red { + color: red; + } + } + .r-info{ + width: 20%; + text-align: center; + + .reviewBtn { + color: #44b100; + } + } + .w10{ + width: 10%; + border-right: 1px solid #ebeef5; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + .w15{ + width: 15%; + border-right: 1px solid #ebeef5; + text-align: center; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + .el-button{ + margin-left: 0 !important; + padding: 12px 0; + &:last-of-type{ + margin-left: 12px !important; + } + } + } + } + } + .pageBtn { + position: absolute; + bottom: 15px; + right: 20px; + height: 60px; + display: flex; + align-items: center; + justify-content: right; + + .demo-pagination-block + .demo-pagination-block { + margin-top: 10px; + } + .demo-pagination-block .demonstration { + margin-bottom: 16px; + } + } + } + } + } + .el-row { display: flex; align-items: center; diff --git a/src/views/specialWorkSystem/specialIndex/index.vue b/src/views/specialWorkSystem/specialIndex/index.vue new file mode 100644 index 0000000..e7f696e --- /dev/null +++ b/src/views/specialWorkSystem/specialIndex/index.vue @@ -0,0 +1,1144 @@ +<template> + <div class="home-container"> + <div class="topChart"> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">八大作业各分类分布图</span> + <div class="filter-part filter-part2"> + <el-cascader v-model="chartSearch1.searchDep" :options="departmentList" :props="casProps" :show-all-levels="false" size="small"/> + </div> + </div> + <div class="chart" :id="zyfb"></div> + <el-radio-group v-model="chartSearch1.period" size="small"> + <el-radio label="week" border>近7天</el-radio> + <el-radio label="month" border>近30天</el-radio> + <el-radio label="season" border>近90天</el-radio> + <el-radio label="year" border>近一年</el-radio> + </el-radio-group> + </div> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">各事业部关联作业分析</span> + <div class="filter-part"> + <el-cascader v-model="chartSearch2.searchDep" :options="departmentList" :props="casProps" :show-all-levels="false" size="small"/> + <el-select v-model="chartSearch2.type" size="small"> + <el-option + v-for="item in workType1" + :key="item.id" + :label="item.name" + :value="item.id" + /> + </el-select> + </div> + </div> + <div class="chart" :id="slfx"></div> + </div> + </div> + <div class="topChart"> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">关联作业趋势图</span> + <div class="filter-part filter-part2"> + <el-cascader v-model="chartSearch3.searchDep" :options="departmentList" :props="casProps" :show-all-levels="false" size="small"/> + </div> + </div> + <div class="chart" :id="zyqs"></div> + </div> + <div class="chart-item"> + <div class="chart-tit"> + <span class="tit">异常警报关联人</span> + <div class="filter-part"> + <el-switch + v-model="chartSearch4.type" + class="ml-2" + inline-prompt + style="--el-switch-on-color: #13ce66; --el-switch-off-color: #13ce66" + active-text="作业人" + inactive-text="监护人" + /> + <el-select v-model="chartSearch4.period" size="small"> + <el-option label="近7天" value="week"/> + <el-option label="近30天" value="month"/> + <el-option label="近90天" value="season"/> + <el-option label="近1年" value="year"/> + </el-select> + <el-select v-model="chartSearch4.workType" size="small"> + <el-option + v-for="item in workType1" + :key="item.id" + :label="item.name" + :value="item.id" + /> + </el-select> + </div> + </div> + <div class="chart"> + <el-table ref="multipleTableRef" :data="warningData" style="width: 100%" :header-cell-style="{ background: '#fafafa' }"> + <el-table-column property="name" label="姓名" width="180" align="center"/> + <el-table-column property="depName" label="所属部门" align="center"/> + <el-table-column property="applyUname" label="异常报警次数" align="center"/> + <el-table-column property="operators" label="角色" align="center"/> + <el-table-column label="是否持证" align="center" width="180"> + <template #default="scope"> + <el-tag :type="scope.row.status==2?'success':(scope.row.status==8||scope.row.status==9)?'warning':'danger'">{{ scope.row.statusDesc }}</el-tag> + </template> + </el-table-column> + </el-table> + </div> +<!-- <div class="chart" :id="slfx"></div>--> + </div> + </div> + <div style="height: 100%"> + <div class="homeCard"> + <el-row> + <el-col :span="5" style="display:flex;align-items: center"> + <span style="white-space: nowrap">作业类型:</span> + <div class="grid-content topInfo"> + <el-select v-model="searchWord"> + <el-option + v-for="item in workType" + :key="item.id" + :label="item.name" + :value="item.id" + /> + </el-select> + </div> + </el-col> + <el-col :span="5" style="display:flex;align-items: center"> + <span style="white-space: nowrap">作业状态:</span> + <div class="grid-content topInfo"> + <el-select v-model="searchStatus"> + <el-option + v-for="item in workStatus" + :key="item.value" + :label="item.name" + :value="item.value" + /> + </el-select> + </div> + </el-col> + <el-col :span="5" style="display:flex;align-items: center"> + <span style="white-space: nowrap">作业部门:</span> + <div class="grid-content topInfo"> + <el-cascader v-model="searchDep" :options="departmentList" :props="casProps" :show-all-levels="false"/> + </div> + </el-col> + <el-col :span="6" style="display:flex;align-items: center;"> + <span style="white-space: nowrap;margin-left: 20px">申请时间:</span> + <div class="grid-content topInfo"> + <el-date-picker + v-model="searchDate" + type="daterange" + unlink-panels + range-separator="至" + start-placeholder="开始日期" + end-placeholder="结束日期" + format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" + /> + </div> + </el-col> + <el-button type="primary" style="margin-left: 20px" @click="searchRecord">查询</el-button> + <el-button plain @click="clearSearch">重置</el-button> + </el-row> + <div class="main-card"> + <el-row class="cardTop" style="justify-content: space-between"> + <el-col :span="2" class="mainCardBtn"> + <el-button type="primary" :icon="Plus" size="default" @click="toApply()">新作业申请</el-button> + </el-col> + <el-col :span="22" style="display: flex;justify-content: end;align-items: center"> + <div class="top-info"> + <el-icon :size="18" color="#F3001E" style="margin-right: 4px"><BellFilled /></el-icon> + 作业编号 + <div v-if="unchecked != 0"> + <el-tooltip + class="box-item" + effect="light" + content="查看预警详情" + placement="bottom-start" + ><span>123456</span></el-tooltip> + </div> + 可燃气体浓度超过18% + ,请及时处理! + </div> + <el-button type="primary" :icon="Refresh" size="default" @click="reLoadData()" /> + </el-col> + </el-row> + <el-table ref="multipleTableRef" :data="applyData" style="width: 100%" :header-cell-style="{ background: '#fafafa' }"> + <el-table-column property="workPermitNo" label="作业证编号" width="180" align="center"/> + <el-table-column property="depName" label="部门" align="center"/> + <el-table-column property="applyUname" label="申请人" align="center"/> + <el-table-column property="operators" label="作业人" align="center"/> + <el-table-column property="workTypeDesc" label="作业类型" align="center"/> + <el-table-column property="workLevelDesc" label="作业等级" align="center"/> + <el-table-column property="applyTime" label="申请时间" width="180" align="center"/> + <el-table-column property="startTime" label="作业开始时间" width="180" align="center"/> + <el-table-column property="endTime" label="作业结束时间" width="180" align="center"/> + <el-table-column label="作业状态" align="center" width="180"> + <template #default="scope"> + <el-tag :type="scope.row.status==2?'success':(scope.row.status==8||scope.row.status==9)?'warning':'danger'">{{ scope.row.statusDesc }}</el-tag> + </template> + </el-table-column> + <el-table-column property="stopReason" label="中止原因" align="center"/> + <el-table-column label="安全预警" align="center" width="180"> + <template #default="scope"> + <el-tag :type="scope.row.saftyWarning==0?'success':(scope.row.saftyWarning==1||scope.row.saftyWarning==2)?'warning':'danger'">{{ scope.row.saftyWarning==0?'正常':'报警' }}</el-tag> + </template> + </el-table-column> + <el-table-column fixed="right" label="操作" align="center" width="250"> + <template #default="scope"> + <el-button link type="primary" size="small" :icon="View" @click="viewRecord(scope.row)">查看</el-button> + <el-button link type="primary" size="small" :icon="FolderChecked" @click="handleReview(scope.row)">验收</el-button> + </template> + </el-table-column> + </el-table> + <div class="pageBtn"> + <el-pagination v-model:currentPage="pageIndex1" v-model:page-size="pageSize1" :page-sizes="[10, 15]" small="false" background layout="total, sizes, prev, pager, next, jumper" :total="totalSize1" @size-change="handleSizeChange1" @current-change="handleCurrentChange1" /> + </div> + </div> + </div> + </div> + <el-dialog v-model="dialogDetails" title="作业申请详情" center> + <fire v-if="dialogType == 1" :details = details></fire> + <space v-else-if="dialogType == 2" :details = details></space> + <hoist v-else-if="dialogType == 3" :details = details></hoist> + <ground v-else-if="dialogType == 4" :details = details></ground> + <broken v-else-if="dialogType == 5" :details = details></broken> + <height v-else-if="dialogType == 6" :details = details></height> + <power v-else-if="dialogType == 7" :details = details></power> + <plate v-else :details = details></plate> + <template #footer> + <span class="dialog-footer"> + <el-button type="primary" @click="dialogDetails = false" + >确认</el-button + > + </span> + </template> + </el-dialog> + <el-dialog v-model="dialogReview" title="填报验收意见" center> + <el-form ref="reviewFormRef" :model="reviewForm" :rules="reviewRules" label-width="120px"> + <el-form-item label="填报验收意见:" prop="advice"> + <el-input + v-model="reviewForm.advice" + :autosize="{ minRows: 4, maxRows: 10 }" + type="textarea" + placeholder="请填写验收意见" + /> + </el-form-item> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button type="primary" @click="submitReview(reviewFormRef)">提交验收</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import {toRefs, reactive, defineComponent, ref, onMounted, defineAsyncComponent} from 'vue'; +import { storeToRefs } from 'pinia'; +import { initBackEndControlRoutes } from '/@/router/backEnd'; +import { useUserInfo } from '/@/stores/userInfo'; +import { Session } from '/@/utils/storage'; +import { useRouter } from 'vue-router'; +import { Edit, View, Plus, Delete, Refresh, Search, Finished, Download, FolderChecked } from '@element-plus/icons-vue'; +import { ElTable, ElMessage } from 'element-plus'; +import { workApplyApi } from '/@/api/specialWorkSystem/workApply'; +import type { TabsPaneContext } from 'element-plus'; +import type { FormInstance, FormRules } from 'element-plus' +import {teamManageApi} from "/@/api/systemManage/basicDateManage/personShiftManage/teamManage"; +import Cookies from 'js-cookie'; +import axios from 'axios'; +import * as echarts from "echarts"; + +// 定义接口来定义对象的类型 +interface stateType { + applyData: Array<string>; + workTimeList: Array<string>; + multipleSelection: Array<any>; + casProps: {}; + approveInfo: Object; + dialogDetails: boolean; + dialogReview: boolean; + pageIndex1: number; + pageSize1: number; + chosenIndex: null | number; + searchWord: number | null; + searchStatus: number | null; + chartSearch1: object; + chartSearch2: object; + chartSearch3: object; + chartSearch4: object; + searchDep2: number | null; + searchDep: number | null; + searchDate: Array<any>, + totalSize1: number; + details: {}; + workType: Array<type>; + workType1: Array<type>; + dialogType: number | null; + departmentList: Array<any>; + departmentRecursionList: Array<DepartmentState>; + workStatus: Array<status>; + reviewForm: object; + reviewRules: object; +} +interface type { + id: number; + name: string; +} +interface status { + name: string + value: number +} +interface DepartmentState { + depId: number; + depName: string; +} +interface User { + name: string; + list: []; + info: string; +} +export default defineComponent({ + name: 'specialIndex', + components: { + fire: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/fireLog.vue')), + space: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/spaceLog.vue')), + hoist: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/hoistLog.vue')), + ground: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/groundLog.vue')), + broken: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/brokenLog.vue')), + height: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/heightLog.vue')), + power: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/powerLog.vue')), + plate: defineAsyncComponent(() => import('/@/views/specialWorkSystem/workTicket/wdsq/components/plateLog.vue')) + }, + setup() { + const userInfo = useUserInfo(); + const { userInfos } = storeToRefs(userInfo); + const router = useRouter(); + const reviewFormRef = ref<FormInstance>() + const zyfb = ref("eChartZyfb" + Date.now() + Math.random()) + const slfx = ref("eChartSlfx" + Date.now() + Math.random()) + const zyqs = ref("eChartZyqs" + Date.now() + Math.random()) + const state = reactive<stateType>({ + pageIndex1: 1, + pageSize1: 10, + totalSize1: 0, + dialogType: null, + dialogReview: false, + departmentList: [], + departmentRecursionList: [], + chosenIndex: null, + searchWord: null, + searchStatus: null, + chartSearch1: { + searchDep: null, + period: 'month' + }, + chartSearch2: { + searchDep: null, + type: 0 + }, + chartSearch3: { + searchDep: null + }, + chartSearch4: { + searchDep: null + }, + searchDep2: null, + searchDep: null, + searchDate: [], + applyData: [], + workTimeList: [], + multipleSelection: [], + approveInfo: { + approvalSteps: [], + operators: [] + }, + casProps: { + expandTrigger: 'hover', + emitPath: false, + value: 'depId', + label: 'depName', + checkStrictly: true + }, + dialogDetails: false, + details: {}, + workType1: [ + { id: 0, name: '所有作业' }, + { id: 1, name: '动火作业' }, + { id: 2, name: '受限空间作业' }, + { id: 3, name: '吊装作业' }, + { id: 4, name: '动土作业' }, + { id: 5, name: '断路作业' }, + { id: 6, name: '高处作业' }, + { id: 7, name: '临时用电作业' }, + { id: 8, name: '盲板抽堵作业' } + ], + workType: [ + { id: 1, name: '动火作业' }, + { id: 2, name: '受限空间作业' }, + { id: 3, name: '吊装作业' }, + { id: 4, name: '动土作业' }, + { id: 5, name: '断路作业' }, + { id: 6, name: '高处作业' }, + { id: 7, name: '临时用电作业' }, + { id: 8, name: '盲板抽堵作业' } + ], + workStatus: [ + { + name: '作业进行中', + value: 0 + }, + { + name: '作业终止', + value: 1 + }, + { + name: '作业结束待验收', + value: 2 + }, + { + name: '作业完成', + value: 3 + } + ], + reviewForm: { + advice: '' + }, + reviewRules:{ + advice: [{ required: true, message: '请填写验收意见', trigger: 'blur' }] + } + }); + // 页面载入时执行方法 + onMounted(() => { + getListByPage(); + getAllDepartment(); + initZyfb() + initSlfx() + initZyqs() + }); + + type EChartsOption = echarts.EChartsOption + const initZyfb =()=>{ + let dom = document.getElementById(zyfb.value); + let myChart = echarts.init(dom); + let option: EChartsOption; + option = { + tooltip: { + trigger: 'item' + }, + legend: { + orient: 'vertical', + left: 'left', + top: 'center' + }, + series: [ + { + name: 'Access From', + type: 'pie', + radius: ['40%', '70%'], + avoidLabelOverlap: false, + itemStyle: { + borderRadius: 1, + borderColor: '#fff', + borderWidth: 2 + }, + label: { + show: false, + position: 'center' + }, + emphasis: { + label: { + show: true, + fontSize: 40, + fontWeight: 'bold' + } + }, + labelLine: { + show: true + }, + data: [ + { value: 1048, name: '动火作业' }, + { value: 735, name: '受限空间作业' }, + { value: 580, name: '吊装作业' }, + { value: 484, name: '动土作业' }, + { value: 735, name: '断路作业' }, + { value: 580, name: '高处作业' }, + { value: 484, name: '临时用电作业' }, + { value: 300, name: '盲板抽堵作业' } + ] + } + ] + } + + option && myChart.setOption(option); + window.addEventListener("resize",function (){ + myChart.resize(); + }); + } + const initSlfx =()=>{ + let dom = document.getElementById(slfx.value); + let myChart = echarts.init(dom); + let option: EChartsOption; + option = { + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow' + } + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true + }, + xAxis: [ + { + type: 'category', + data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + axisTick: { + alignWithLabel: true + } + } + ], + yAxis: [ + { + type: 'value' + } + ], + series: [ + { + name: 'Direct', + type: 'bar', + barWidth: '60%', + data: [10, 52, 200, 334, 390, 330, 220] + } + ] + } + + option && myChart.setOption(option); + window.addEventListener("resize",function (){ + myChart.resize(); + }); + } + const initZyqs =()=>{ + let dom = document.getElementById(zyqs.value); + let myChart = echarts.init(dom); + let option: EChartsOption; + option = { + xAxis: { + type: 'category', + data: ['四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月', '一月', '二月', '三月'] + }, + yAxis: { + type: 'value' + }, + grid: { + top: '8%', + bottom: '8%' + }, + series: [ + { + data: [150, 230, 224, 218, 135, 147, 230, 224, 218, 135, 147, 260], + type: 'line' + } + ] + } + + option && myChart.setOption(option); + window.addEventListener("resize",function (){ + myChart.resize(); + }); + } + // 刷新 + const reLoadData = async () => { + getListByPage(); + }; + + // 填写表单 + const toApply = () => { + router.push({ + path: 'zysq' + }); + }; + + // 获取部门列表 + const getAllDepartment = async () => { + let res = await teamManageApi().getAllDepartment(); + if (res.data.code === '200') { + state.departmentList = JSON.parse(JSON.stringify(res.data.data)) + // recursion(state.departmentList); + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + // 分页获取列表 + const getListByPage = async () => { + const dateRange = JSON.parse(JSON.stringify(state.searchDate)) + if(dateRange[1]){dateRange[1] = dateRange[1].replace('00:00:00','23:59:59')} + const data = { pageSize: state.pageSize1, pageIndex: state.pageIndex1, searchParams: { workType: state.searchWord, applyDepId: state.searchDep,applyStartTime: dateRange[0],applyEndTime: dateRange[1]} }; + let res = await workApplyApi().getApplyList(data); + if (res.data.code === '200') { + state.applyData = JSON.parse(JSON.stringify(res.data.data)); + state.applyData = state.applyData.map((item) => { + if (item.operators == null || item.operators == []) { + item.operators = []; + } else { + item.operators = Array.from(item.operators, ({ operatorUname }) => operatorUname); + } + return item; + }); + state.totalSize1 = res.data.total; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + // 表格数据格式化 + const toNames = (row, column, cellValue, index) => { + if (row.list == []) { + return []; + } else { + const nameList = []; + for (let i = 0; i < row.list.length; i++) { + for (let t = 0; t < state.workTimeList.length; t++) { + if (row.list[i] == state.workTimeList[t].id) { + nameList.push(state.workTimeList[t].name); + } + } + } + return nameList.join(); + } + }; + + // 关键词查询记录 + const searchRecord = async () => { + if (state.searchWord == null && state.searchStatus == null && state.searchDep == null && state.searchDate == []) { + ElMessage({ + type: 'warning', + message: '请输入查询关键词' + }); + } else { + getListByPage(); + } + }; + // 重置搜索 + const clearSearch = async () => { + state.searchWord = null; + state.searchDep = null; + state.searchDate = [] + getListByPage(); + }; + + const handleSizeChange1 = (val: number) => { + state.pageSize1 = val; + getListByPage(); + }; + const handleCurrentChange1 = (val: number) => { + state.pageIndex1 = val; + getListByPage(); + }; + + // 查看记录 + const viewRecord = (row: any) => { + state.dialogType = row.workType + state.details = JSON.parse(JSON.stringify(row)); + if(state.details.workDetail.otherSpecialWork == '' || !state.details.workDetail.otherSpecialWork){ + state.details.workDetail.otherSpecialWork=[] + } + else { + const a = state.details.workDetail.otherSpecialWork + state.details.workDetail.otherSpecialWork = a.split(',').map((item) => { + return state.workType.find((i: { id: number }) => i.id === Number(item))?.name; + }); + } + if(state.details.workDetail.involvedDepIds == '' || !state.details.workDetail.involvedDepIds){ + state.details.workDetail.involvedDepIds=[] + } + else { + const a = state.details.workDetail.involvedDepIds + state.details.workDetail.involvedDepIds = a.split(',').map((item) => { + return state.departmentRecursionList.find((i: { depId: number }) => i.depId === Number(item))?.depName; + }); + } + if(state.details.workDetail.csDepId){ + state.details.workDetail.csDepId = state.departmentRecursionList.find((i: { depId: number }) => i.depId === Number(state.details.workDetail.csDepId))?.depName; + } + if(state.details.workDetail.operationDepId){ + state.details.workDetail.operationDepId = state.departmentRecursionList.find((i: { depId: number }) => i.depId === Number(state.details.workDetail.operationDepId))?.depName; + } + if(state.details.workDetail.gbPath){ + state.details.workDetail.gbPath = state.details.workDetail.gbPath.split(',') + } + if(state.details.workDetail.bcPath){ + state.details.workDetail.bcPath = state.details.workDetail.bcPath.split(',') + } + if(state.details.workDetail.bpLocationMapPath){ + state.details.workDetail.bpLocationMapPath = state.details.workDetail.bpLocationMapPath.split(',') + } + state.dialogDetails = true; + }; + + const handleReview = (row)=>{ + state.dialogReview = true + } + + const submitReview = async (formEl: FormInstance | undefined) => { + if (!formEl) return + await formEl.validate((valid, fields) => { + if (valid) { + console.log('submit!') + } else { + console.log('error submit!', fields) + } + }) + } + + // 折线图 + const renderMenu = async (value: string) => { + Session.set('projectId', value); + userInfos.value.projectId = value; + await initBackEndControlRoutes(); + }; + + return { + View, + Edit, + Delete, + Refresh, + Plus, + Finished, + Download, + FolderChecked, + reviewFormRef, + zyfb, + slfx, + zyqs, + handleReview, + submitReview, + reLoadData, + toApply, + toNames, + searchRecord, + clearSearch, + viewRecord, + getListByPage, + handleSizeChange1, + handleCurrentChange1, + ...toRefs(state) + }; + } +}); +</script> + +<style scoped lang="scss"> +$homeNavLengh: 8; +.home-container { + height: calc(100vh - 144px); + box-sizing: border-box; + overflow: hidden; + .demo-tabs { + width: 100%; + height: 100%; + + &::v-deep(.el-tabs__content) { + height: calc(100% - 60px); + } + + .el-tab-pane { + height: 100%; + } + } + .topChart{ + width: 100%; + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 20px; + height: 40%; + + .chart-item{ + width: calc(50% - 10px); + height: 100%; + margin-right: 10px; + position: relative; + background: #fff; + padding: 20px; + + &:last-of-type{ + margin-right: 0; + } + + .chart-tit{ + width: 100%; + display: flex; + align-items: flex-start; + justify-content: space-between; + .tit{ + font-size: 16px; + font-weight: bolder; + } + .filter-part{ + display: flex; + align-items: center; + justify-content: right; + :deep(.el-cascader){ + width: 35% !important; + } + .el-select{ + width: 35% !important; + margin-left: 10px; + } + .el-switch{ + width: 25% !important; + + :deep(.el-switch__core){ + width: 100% !important; + } + } + } + .filter-part2{ + :deep(.el-cascader){ + width: 100% !important; + } + } + + } + .chart{ + width: 100%; + height: 88%; + } + .el-radio-group{ + width: 20%; + display: flex; + flex-flow: column nowrap; + align-items: flex-start; + position: absolute; + right: 10px; + top: 50%; + transform: translateY(-30%); + + .el-radio{ + width: 100%; + margin-bottom: 4px; + } + } + :deep(.active-ring-info){ + .active-ring-name{ + font-size: 1.5rem !important; + text-align: center; + } + } + } + } + .homeCard { + width: 100%; + padding: 20px; + box-sizing: border-box; + background: #fff; + border-radius: 4px; + + .main-card { + width: 100%; + height: 100%; + .cardTop { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; + .mainCardBtn { + margin: 0; + } + + .top-info { + display: flex; + font-size: 16px; + font-weight: bolder; + align-items: center; + padding: 6px 10px; + background: #ffeb87; + border-radius: 4px; + border: 1px solid #ffae00; + margin-right: 20px; + + & > div { + vertical-align: middle; + white-space: nowrap; + span { + font-size: 22px; + color: #f3001e; + margin: 0 2px; + cursor: pointer; + + &:hover{ + text-decoration: underline; + } + } + } + } + } + .pageBtn { + height: 60px; + display: flex; + align-items: center; + justify-content: right; + + .demo-pagination-block + .demo-pagination-block { + margin-top: 10px; + } + .demo-pagination-block .demonstration { + margin-bottom: 16px; + } + } + } + } + .stepItem { + display: flex; + align-items: flex-start; + margin-top: 30px; + margin-left: 30px; + padding-bottom: 30px; + padding-left: 40px; + border-left: 1px solid #a0cfff; + position: relative; + &:first-of-type { + margin-top: 30px; + } + &:first-of-type { + margin-bottom: 0; + border-left: none; + } + .stepNum { + position: absolute; + width: 40px; + height: 40px; + border-radius: 20px; + box-sizing: border-box; + font-size: 18px; + color: #333; + border: 1px solid #a0cfff; + line-height: 38px; + text-align: center; + left: -20px; + top: -30px; + background: #d9ecff; + } + .stepCard { + width: 100%; + margin-top: -30px; + + .box-card { + width: 100%; + + .card-header { + display: flex; + justify-content: space-between; + align-items: center; + + span { + font-weight: bold; + margin-left: 10px; + } + } + + .text { + width: 100%; + font-size: 14px; + margin-bottom: 10px; + padding-left: 10px; + + span { + font-weight: bolder; + color: #409eff; + } + + &:last-of-type { + margin-bottom: 0; + } + } + .approveUnit { + width: 100%; + font-size: 14px; + margin-bottom: 20px; + padding: 10px 15px; + border: 1px solid #fff; + background: #ecf8ff; + border-radius: 6px; + .item-tit { + width: 100%; + display: flex; + color: #409eff; + align-items: flex-start; + justify-content: space-between; + padding-bottom: 10px; + border-bottom: 1px solid #a0cfff; + + & > span { + flex: 1; + &:last-of-type{ + text-align: center; + } + } + & > div { + flex: 1; + text-align: center; + } + } + .item-cont { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid #c6e2ff; + + & > span { + flex: 1; + &:last-of-type{ + text-align: center; + } + } + & > div { + flex: 1; + text-align: center; + + & > div { + text-align: left; + width: 100%; + display: flex; + justify-content: center; + align-items: center; + span { + width: 45%; + &:first-of-type { + width: 30%; + } + } + } + } + &:last-of-type { + border-bottom: 0; + } + } + } + .approveItem { + width: 100%; + font-size: 14px; + margin-bottom: 20px; + padding: 10px 15px; + background: #ecf8ff; + border: 1px solid #fff; + border-radius: 6px; + .item-tit { + width: 100%; + display: flex; + color: #409eff; + align-items: flex-start; + justify-content: space-between; + padding-bottom: 10px; + border-bottom: 1px solid #a0cfff; + + & > span { + flex: 1; + } + & > div { + flex: 2; + text-align: center; + } + } + .item-cont { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid #c6e2ff; + + & > span { + flex: 1; + } + & > div { + flex: 2; + text-align: center; + + & > div { + text-align: left; + width: 100%; + display: flex; + justify-content: center; + align-items: flex-start; + margin-bottom: 10px; + span { + width: 50%; + &:first-of-type { + width: 25%; + } + } + } + } + &:last-of-type { + border-bottom: 0; + } + } + } + } + } + &:hover .card-header { + color: #0098f5; + } + &:hover .stepNum { + border: 2px solid #0098f5; + color: #0098f5; + } + } + .el-row { + display: flex; + align-items: center; + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + .grid-content { + align-items: center; + min-height: 36px; + } + + .topInfo { + width: 100%; + display: flex; + align-items: center; + font-size: 16px; + font-weight: bold; + + & > div { + white-space: nowrap; + margin-right: 20px; + } + } + } +} +.el-card { + border: 0; +} +.el-input{ + width: 100% !important; +} +::v-deep(.el-date-editor){ + width: 100%; +} +.el-select{ + width: 100%; +} +:deep(.el-cascader){ + width: 100% !important; +} +</style> diff --git a/src/views/system/user/component/userDialog.vue b/src/views/system/user/component/userDialog.vue index 86cffbd..fae4942 100644 --- a/src/views/system/user/component/userDialog.vue +++ b/src/views/system/user/component/userDialog.vue @@ -99,7 +99,6 @@ interface roleData {} interface dutyData {} interface sexData {} -interface type {} interface UserState { title: string; disabled: boolean; @@ -113,7 +112,6 @@ phone: string; email: string; gender: number | null; - type: number | null; password: string; expireTime: string; status: number; @@ -126,7 +124,6 @@ roleData: Array<roleData>; dutyData: Array<dutyData>; sexList: Array<sexData>; - userTypeList: Array<type>; } export default defineComponent({ @@ -148,7 +145,6 @@ gender: null, // 性别 password: '', // 账户密码 positionId: null, // 岗位 - type: null, // 用户类型 expireTime: '', // 账户过期 status: 1 // 用户状态 }, @@ -159,7 +155,6 @@ depId: [{ required: true, message: '请选择部门', trigger: 'change' }], positionId: [{ required: true, message: '请选择职务', trigger: 'change' }], phone: [{ required: true, message: '请填写手机号', trigger: 'blur' }], - type: [{ required: true, message: '请填写用户类型', trigger: 'blur' }], gender: [{ required: true, message: '请选择性别', trigger: 'change' }], expireTime: [{ required: true, message: '请输入账户过期时间', trigger: 'blur' }], password: [{ required: true, message: '请输入账户密码', trigger: 'blur' }], @@ -170,11 +165,6 @@ sexList: [ { id: 1, name: '男' }, { id: 0, name: '女' } - ], - userTypeList: [ - { id: 1, name: '超级管理员' }, - { id: 2, name: '管理员' }, - { id: 3, name: '普通员工' } ] }); // 打开弹窗 @@ -196,7 +186,6 @@ identify: '', positionId: null, gender: null, - type: null, password: '', expireTime: '', status: 1 diff --git a/src/views/system/video/component/videoDialog.vue b/src/views/system/video/component/videoDialog.vue new file mode 100644 index 0000000..c6729c7 --- /dev/null +++ b/src/views/system/video/component/videoDialog.vue @@ -0,0 +1,158 @@ +<template> + <div class="system-add-user-container"> + <el-dialog :title="title" v-model="isShowVideoDialog" width="50%"> + <el-form :model="videoForm" size="default" ref="userRef" :rules="videoFormRules" label-width="120px"> + <el-row :gutter="35"> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="视频设备名称" prop="name"> + <el-input v-model.trim="videoForm.name" placeholder="请输入设备名称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="设备简称" prop="shortName"> + <el-input v-model.trim="videoForm.shortName" placeholder="请输入设备简称" clearable></el-input> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="所属部门" prop="bizDepId"> + <el-cascader v-model="videoForm.bizDepId" :options="departmentData" :props="{ emitPath: false, checkStrictly: true, value: 'depId', label: 'depName' }" placeholder="请选择部门" clearable class="w100"> </el-cascader> + </el-form-item> + </el-col> + <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20"> + <el-form-item label="设备号" prop="deviceNo"> + <el-input v-model.trim="videoForm.deviceNo" placeholder="请输入设备号" clearable></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <span class="dialog-footer"> + <el-button @click="isShowVideoDialog = !isShowVideoDialog" size="default">取 消</el-button> + <el-button type="primary" v-throttle @click="onSubmit" size="default">确 定</el-button> + </span> + </template> + </el-dialog> + </div> +</template> + +<script lang="ts"> +import { reactive, toRefs, onMounted, defineComponent, ref } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import { videoApi } from '/@/api/systemManage/video'; + +// 定义接口来定义对象的类型 +interface DeptData {} +interface sexData {} +interface UserState { + title: string; + isShowVideoDialog: boolean; + videoForm: { + name: string | null; + shortName: string | null; + deviceNo: string | null; + bizDepId: number | null; + }; + videoFormRules:{ + + }, + departmentData: Array<DeptData> +} + +export default defineComponent({ + name: 'videoDialog', + setup(props, context) { + const userRef = ref() + const state = reactive<UserState>({ + title: '', + isShowVideoDialog: false, + videoForm: { + name: '', // 账户名称 + shortName: '', // 用户昵称 + deviceNo: '', // 关联角色 + bizDepId: null + }, + videoFormRules:{ + name: [{ required: true, message: '请填写设备名称', trigger: 'blur' }], + shortName: [{ required: true, message: '请填写设备简称', trigger: 'blur' }], + deviceNo: [{ required: true, message: '请输入设备编号', trigger: 'change' }], + bizDepId: [{ required: true, message: '请选择部门', trigger: 'change' }] + }, + departmentData: [], // 部门数据 + }); + // 打开弹窗 + const openDialog = (type: string, value: any, departmentList: [], roleList: [], dutyList:[]) => { + state.isShowVideoDialog = true; + state.departmentData = departmentList; + if (type === '新增') { + state.title = '新增视频设备'; + state.videoForm = { + name: '', + shortName: '', + deviceNo: '', + bizDepId: null + }; + } else { + state.title = '修改视频设备'; + state.videoForm = JSON.parse(JSON.stringify(value)); + } + }; + + // 新增修改 + const onSubmit = async () => { + userRef.value.validate(async (valid:Boolean) => { + console.log(state.videoForm,'state.videoForm') + if(valid){ + if (state.title === '新增视频设备') { + let res = await videoApi().addVideo(state.videoForm); + if (res.data.code === '200') { + ElMessage({ + type: 'success', + message: '视频设备新增成功', + duration: 2000 + }); + state.isShowVideoDialog = false; + context.emit('getVideoList'); + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + } else { + let res = await videoApi().modVideo(state.videoForm); + if (res.data.code === '200') { + ElMessage({ + type: 'success', + message: '设备修改成功', + duration: 2000 + }); + state.isShowVideoDialog = false; + context.emit('getVideoList'); + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + } + }else{ + ElMessage({ + type:'warning', + message:'请完善基本信息' + }) + } + }) + + }; + + // 页面加载时 + onMounted(() => {}); + return { + userRef, + openDialog, + onSubmit, + ...toRefs(state) + }; + } +}); +</script> diff --git a/src/views/system/video/index.vue b/src/views/system/video/index.vue new file mode 100644 index 0000000..17757a7 --- /dev/null +++ b/src/views/system/video/index.vue @@ -0,0 +1,250 @@ +<template> + <div class="system-user-container"> + <el-card shadow="hover"> + <div class="system-user-search mb15"> + <el-cascader + v-model="listQuery.bizDepId" + :props="props" + :options="departmentList" + :show-all-levels="false" + placeholder="请选择部门(事业部级别)" + clearable + size="default" + ></el-cascader> + <el-input size="default" clearable v-model.trim="listQuery.name" placeholder="请输入设备名称" style="max-width: 180px;margin-left: 10px"> </el-input> + <el-button size="default" type="primary" class="ml10" @click="initVideoTableData"> + <el-icon> + <ele-Search /> + </el-icon> + 查询 + </el-button> + <el-button size="default" type="success" class="ml10" @click="onOpenVideoDialog('新增', '')"> + <el-icon> + <ele-FolderAdd /> + </el-icon> + 新增设备 + </el-button> + </div> + <el-table :data="videoTableData.data" style="width: 100%"> + <el-table-column type="index" label="序号" width="60" align="center"/> + <el-table-column prop="name" label="视频设备名称" align="center" show-overflow-tooltip></el-table-column> + <el-table-column prop="shortName" label="设备简称" align="center" show-overflow-tooltip></el-table-column> + <el-table-column prop="depName" label="所属部门" align="center" show-overflow-tooltip></el-table-column> + <el-table-column prop="deviceNo" label="设备号" align="center" show-overflow-tooltip></el-table-column> + <el-table-column label="操作" width="100" align="center"> + <template #default="scope"> + <el-button :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onOpenVideoDialog('修改', scope.row)">修改</el-button> + <el-button style="color: red" :disabled="scope.row.userName === 'admin'" size="small" text type="primary" @click="onRowDel(scope.row)">删除</el-button> + </template> + </el-table-column> + </el-table> + <br /> + <el-pagination @size-change="onHandleSizeChange" @current-change="onHandleCurrentChange" class="page-position" :pager-count="5" :page-sizes="[10, 20, 30]" v-model:current-page="listQuery.pageIndex" background v-model:page-size="listQuery.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="videoTableData.total"> </el-pagination> + <br /> + <br /> + </el-card> + <videoDialog ref="userRef" @getVideoList="initVideoTableData"/> + </div> +</template> + +<script lang="ts"> +import { toRefs, reactive, onMounted, ref, defineComponent } from 'vue'; +import { ElMessageBox, ElMessage } from 'element-plus'; +import videoDialog from '/@/views/system/video/component/videoDialog.vue'; +import { videoApi } from '/@/api/systemManage/video'; +import { dutyApi } from '/@/api/systemManage/duty'; +import { departmentApi } from '/@/api/systemManage/department'; +import { useRoleApi } from '/@/api/systemManage/role'; + +// 定义接口来定义对象的类型 +interface TableDataRow { + name: string; + userNickname: string; + roleSign: string; + department: string[]; + phone: string; + email: string; + sex: string; + password: string; + overdueTime: Date; + status: boolean; + describe: string; + createTime: string; +} +interface DepartmentDataRow {} +interface TableDataState { + videoTableData: { + data: Array<TableDataRow>; + total: number; + loading: boolean; + }; + listQuery: { + bizDepId: string | null; + name: string | null; + shortName: string | null; + pageIndex: number; + pageSize: number; + }; + departmentList: []; + roleList: []; + dutyList: []; + props:{} +} + +export default defineComponent({ + name: 'systemVideo', + components: { videoDialog }, + setup() { + const userRef = ref(); + const state = reactive<TableDataState>({ + videoTableData: { + data: [], + total: 0, + loading: false, + }, + listQuery: { + bizDepId: null, + name: '', + shortName: '', + pageIndex: 1, + pageSize: 10 + }, + departmentList: [], + roleList: [], + dutyList: [], + props: { + label: 'depName', + value: 'depId', + checkStrictly: true, + emitPath: false + } + }); + // 初始化表格数据 + const initVideoTableData = async () => { + let res = await videoApi().getVideoList(state.listQuery); + if (res.data.code === '200') { + state.videoTableData.data = res.data.data; + state.videoTableData.total = res.data.total; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + // 回显职务信息 + const parseNumber = (value: number) => { + return state.dutyList.find((i) => i.positionId === value)?.positionName; + }; + const getDepartmentData = async () => { + let res = await departmentApi().getDepartmentList(); + if (res.data.code === '200') { + state.departmentList = res.data.data; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + const getRoleData = async () => { + let res = await useRoleApi().getRoleList(); + if (res.data.code === '200') { + state.roleList = res.data.data; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + const getDutyData = async () => { + let res = await dutyApi().getAllList({positionName: '',positionCode: ''}); + if (res.data.code === '200') { + state.dutyList = res.data.data; + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }; + + // 打开新增修改用户弹窗 + const onOpenVideoDialog = (type: string, value: any) => { + userRef.value.openDialog(type, value, state.departmentList, state.roleList, state.dutyList); + }; + + // 删除用户 + const onRowDel = (row: TableDataRow) => { + ElMessageBox.confirm(`此操作将永久删除设备名称:“${row.name}”,是否继续?`, '提示', { + confirmButtonText: '确认', + cancelButtonText: '取消', + type: 'warning' + }) + .then(async () => { + let res = await videoApi().delVideo(row.id); + if (res.data.code === '200') { + ElMessage({ + type: 'success', + duration: 2000, + message: '删除成功' + }); + await initVideoTableData(); + } else { + ElMessage({ + type: 'warning', + message: res.data.msg + }); + } + }) + .catch(() => {}); + }; + // 分页改变 + const onHandleSizeChange = (val: number) => { + state.listQuery.pageSize = val; + initVideoTableData(); + }; + // 分页改变 + const onHandleCurrentChange = (val: number) => { + state.listQuery.pageIndex = val; + initVideoTableData(); + }; + // 页面加载时 + onMounted(() => { + let a = { name: 1, c: { name: 1 } }; + let b = Object.assign({}, a); + b.c.name = 2; + initVideoTableData(); + getDepartmentData(); + getRoleData(); + getDutyData() + }); + return { + userRef, + onOpenVideoDialog, + onRowDel, + parseNumber, + onHandleSizeChange, + initVideoTableData, + onHandleCurrentChange, + ...toRefs(state) + }; + } +}); +</script> +<style scoped> +:deep(.el-textarea.is-disabled .el-textarea__inner) { + background-color: var(--el-card-bg-color); + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__inner) { + color: var(--el-input-text-color, var(--el-text-color-regular)); +} +:deep(.el-input.is-disabled .el-input__wrapper) { + background-color: var(--el-card-bg-color); +} +</style> -- Gitblit v1.9.2