From 5672f352d0ba114e2ae96c8cefad6c74ae6d2934 Mon Sep 17 00:00:00 2001
From: unknown <280848880@qq.com>
Date: 星期一, 23 十月 2023 10:38:28 +0800
Subject: [PATCH] 苏州-web:智能安全帽提交
---
web/src/components/element/Table.vue | 300 +-
web/src/views/ProjectManage/SectionManage.vue | 1219 ++++++------
web/src/views/SecureManage/SmartHelmet/AlarmRecord.vue | 728 +++++++
web/src/assets/markerIcon.png | 0
web/src/plugins/public.js | 363 ++-
web/src/style/layout-main.scss | 959 +++++-----
/dev/null | 126 -
web/src/api/modules/safety.js | 517 +++--
web/src/components/element/Form.vue | 64
web/src/views/SecureManage/SmartHelmet/TrackBack.vue | 741 ++++++++
web/package.json | 2
web/src/views/SecureManage/SmartHelmet/SafeHat.vue | 132 +
web/src/views/SecureManage/SmartHelmet/PhoneManage.vue | 253 ++
web/package-lock.json | 10
14 files changed, 3,676 insertions(+), 1,738 deletions(-)
diff --git a/web/package-lock.json b/web/package-lock.json
index c1c1899..a2b3711 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -4,6 +4,11 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@amap/amap-jsapi-loader": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@amap/amap-jsapi-loader/-/amap-jsapi-loader-1.0.1.tgz",
+ "integrity": "sha512-nPyLKt7Ow/ThHLkSvn2etQlUzqxmTVgK7bIgwdBRTg2HK5668oN7xVxkaiRe3YZEzGzfV2XgH5Jmu2T73ljejw=="
+ },
"@ampproject/remapping": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.1.1.tgz",
@@ -4977,6 +4982,11 @@
}
}
},
+ "echarts-liquidfill": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/echarts-liquidfill/-/echarts-liquidfill-3.1.0.tgz",
+ "integrity": "sha512-5Dlqs/jTsdTUAsd+K5LPLLTgrbbNORUSBQyk8PSy1Mg2zgHDWm83FmvA4s0ooNepCJojFYRITTQ4GU1UUSKYLw=="
+ },
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz",
diff --git a/web/package.json b/web/package.json
index 472926c..1f87330 100644
--- a/web/package.json
+++ b/web/package.json
@@ -8,12 +8,14 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
+ "@amap/amap-jsapi-loader": "^1.0.1",
"@vue/composition-api": "^1.4.9",
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "^1.0.2",
"axios": "^0.26.0",
"core-js": "^3.6.5",
"echarts": "^5.4.2",
+ "echarts-liquidfill": "^3.1.0",
"element-ui": "^2.15.6",
"ezuikit-js": "^7.7.5",
"node-sass": "^4.14.1",
diff --git a/web/src/api/modules/safety.js b/web/src/api/modules/safety.js
index 637f94b..963b9c4 100644
--- a/web/src/api/modules/safety.js
+++ b/web/src/api/modules/safety.js
@@ -1,238 +1,281 @@
-/**
- * 安全管理模块
- */
- import axios from '../request';
- export default{
- /**
- * 安全公告模块
- */
- // 查询安全公告信息列表
- searchSafetyAfficheList: (params) =>
- axios({
- method: 'post',
- url: '/secure/secureNotice/findList',
- headers: {
- pageNum: params.pageNum,
- pageSize: params.pageSize
- },
- data: {
- noticeName: params.noticeName,
- startTime: params.startTime,
- endTime: params.endTime
- }
- }),
- // 添加 修改 安全公告信息
- insertSafetyAfficheInfo: (params) =>
- axios.post('/secure/secureNotice/addSecureNotice', params),
- // 删除安全公告信息
- deleteSafetyAfficheInfo: (params) =>
- axios.post('secure/secureNotice/delete', params),
- // 上架 下架安全公告信息
- upAndDownSafetyAfficheInfo: (params) =>
- axios.post('/secure/secureNotice/updown', params),
-
-
- /**
- * 劳务档案
- */
- //奖惩记录列表
- recordAwardsLists: (params) =>
- axios.post('/secure/encourage/encourageRecordWebList', params),
- //安全码列表
- codeSafeLists: (params) =>
- axios.post('/secure/encourage/encourageSecurityCode', params),
-
- /**
- * 安全考核模块
- */
- // 根据类型获取类型名称(安全培训和日常培训制定名称)
- getAllSecureTrainPull: (params) =>
- axios.post('/secure/secureTrain/secureTrainPull', params),
- // 查询安全考核信息
- searchSafetyExamineList: (params) =>
- axios({
- method: 'post',
- url: '/secure/exam/findList',
- headers: {
- pageNum: params.pageNum,
- pageSize: params.pageSize
- },
- data: {
- examName: params.examName,
- startDay: params.startDay,
- endDay: params.endDay
- }
- }),
- // 添加 修改 安全考核信息
- insertSafetyExamineInfo: (params) =>
- axios.post('/secure/exam/addExam', params),
- // 删除安全考核信息
- deleteSafetyExamineInfo: (params) =>
- axios.post('/secure/exam/delete', params),
- // 获取安全考核统计信息
- getExamRecordStatistical: (params) =>
- axios.post('/secure/examRecord/recordStat', params),
- // 查询安全考核记录
- searchSafetyCheckRecord: (params) =>
- axios({
- method: 'post',
- url: '/secure/examRecord/recordList',
- headers: {
- pageNum: params.pageNum,
- pageSize: params.pageSize
- },
- data: {
- examId: params.examId,
- examResult: params.examResult,
- departId: params.departId,
- groupId: params.groupId,
- startTime: params.startTime,
- endTime: params.endTime
- }
- }),
-
-
- // 安全考题信息列表
- searchSafetyTopicList: (params) =>
- axios({
- method: 'post',
- url: '/secure/question/findList',
- headers: {
- pageNum: params.pageNum,
- pageSize: params.pageSize
- },
- data: {
- trainName: params.trainName
- }
- }),
- // 新增 修改安全考题信息
- insertSafetyTopicInfo: (params) =>
- axios.post('/secure/question/addQuestion', params),
- // 删除安全考题信息
- deleteSafetyTopicInfo: (params) =>
- axios.post('/secure/question/delete', params),
- // 获取答案列表信息
- getAnswerlIstInfo: (params) =>
- axios.post('secure/question/answerList', params),
-
- /**
- * 消防器材模块
- */
- // 查询消防器材信息列表
- searchFireequipmentList: (params) =>
- axios({
- method: 'post',
- url: '/secure/secureGood/findList',
- headers: {
- pageNum: params.pageNum,
- pageSize: params.pageSize
- },
- data: {
- goodName: params.goodName,
- startTime: params.startTime,
- endTime: params.endTime
- }
- }),
- // 添加 修改 消防器材信息
- insertFireequipmentInfo: (params) =>
- axios.post('/secure/secureGood/addSecureGood', params),
- // 删除消防器材信息
- deleteFireequipmentInfo: (params) =>
- axios.post('secure/secureGood/delete', params),
- // 导出二维码
- getFireequipmentCode: (params) =>
- axios({
- method: 'get',
- url: '/secure/secureGood/viewcode',
- params: params,
- responseType: 'blob'
- }),
- // 获取消防器材图片列表
- getFireequipmentImageInfo: (params) =>
- axios.post('/secure/secureGood/fileList', params),
-
- /**
- * 安全培训和日常培训制定
- */
- // 列表信息
- searchEnactLists: params =>
- axios.post('/secure/secureTrain/secureTrainList', params),
- // 添加信息
- insertEnactInfo: params =>
- axios.post('/secure/secureTrain/secureTrainInsert', params),
- // 修改信息
- updateEnactInfo: params =>
- axios.post('/secure/secureTrain/secureTrainUpdate', params),
- // 信息详情
- detailsEnactInfo: params =>
- axios.post('/secure/secureTrain/secureTrainInfo', params),
- // 删除信息
- deleteEnactInfo: params =>
- axios.post('/secure/secureTrain/secureTrainDel', params),
- //查询记录
- getEnactRecords: params =>
- axios.post('/secure/secureTrain/secureTrainRecord', params),
-
- /**
- * 安全资料模块
- */
- // 列表信息
- searchDatumLists: params =>
- axios.post('/secure/material/materialList', params),
- // 添加信息
- insertDatumInfo: params =>
- axios.post('/secure/material/materialInsert', params),
- // 修改信息
- updateDatumInfo: params =>
- axios.post('/secure/material/materialUpdate', params),
- // 信息详情
- detailsDatumInfo: params =>
- axios.post('/secure/material/materialInfo', params),
-
- /**
- * 奖惩标准模块
- */
- // 列表信息
- searchPunishLists: params =>
- axios.post('/secure/encourage/encourageList', params),
- // 添加信息
- insertPunishInfo: params =>
- axios.post('/secure/encourage/encourageInsert', params),
- // 修改信息
- updatePunishInfo: params =>
- axios.post('/secure/encourage/encourageUpdate', params),
- // 信息详情
- detailsPunishInfo: params =>
- axios.post('/secure/encourage/encourageInfo', params),
- // 信息删除
- deletePunishInfo: params =>
- axios.post('/secure/encourage/encourageDel', params),
-
- /**
- * 风险分级管控
- */
- RiskGrad: {
- // 危险源告知
- warning : {
- getLists: params =>
- axios.post('/secure/regionHazardInform/findAll', params),
- insert: params =>
- axios.post('/secure/regionHazardInform/insert', params),
- update: params =>
- axios.post('/secure/regionHazardInform/update', params),
- delete: params =>
- axios.get('/secure/regionHazardInform/delete', { params }),
- },
- // 区域包保
- allocation : {
- getLists: params =>
- axios.post('/secure/tRegionWarranty/findAll', params),
- insert: params =>
- axios.post('/secure/tRegionWarranty/insert', params),
- update: params =>
- axios.post('/secure/tRegionWarranty/update', params),
- delete: params =>
- axios.get('/secure/tRegionWarranty/delete', { params }),
- }
- }
+/**
+ * 安全管理模块
+ */
+ import axios from '../request';
+ export default{
+ /**
+ * 安全公告模块
+ */
+ // 查询安全公告信息列表
+ searchSafetyAfficheList: (params) =>
+ axios({
+ method: 'post',
+ url: '/secure/secureNotice/findList',
+ headers: {
+ pageNum: params.pageNum,
+ pageSize: params.pageSize
+ },
+ data: {
+ noticeName: params.noticeName,
+ startTime: params.startTime,
+ endTime: params.endTime
+ }
+ }),
+ // 添加 修改 安全公告信息
+ insertSafetyAfficheInfo: (params) =>
+ axios.post('/secure/secureNotice/addSecureNotice', params),
+ // 删除安全公告信息
+ deleteSafetyAfficheInfo: (params) =>
+ axios.post('secure/secureNotice/delete', params),
+ // 上架 下架安全公告信息
+ upAndDownSafetyAfficheInfo: (params) =>
+ axios.post('/secure/secureNotice/updown', params),
+
+
+ /**
+ * 劳务档案
+ */
+ //奖惩记录列表
+ recordAwardsLists: (params) =>
+ axios.post('/secure/encourage/encourageRecordWebList', params),
+ //安全码列表
+ codeSafeLists: (params) =>
+ axios.post('/secure/encourage/encourageSecurityCode', params),
+
+ /**
+ * 安全考核模块
+ */
+ // 根据类型获取类型名称(安全培训和日常培训制定名称)
+ getAllSecureTrainPull: (params) =>
+ axios.post('/secure/secureTrain/secureTrainPull', params),
+ // 查询安全考核信息
+ searchSafetyExamineList: (params) =>
+ axios({
+ method: 'post',
+ url: '/secure/exam/findList',
+ headers: {
+ pageNum: params.pageNum,
+ pageSize: params.pageSize
+ },
+ data: {
+ examName: params.examName,
+ startDay: params.startDay,
+ endDay: params.endDay
+ }
+ }),
+ // 添加 修改 安全考核信息
+ insertSafetyExamineInfo: (params) =>
+ axios.post('/secure/exam/addExam', params),
+ // 删除安全考核信息
+ deleteSafetyExamineInfo: (params) =>
+ axios.post('/secure/exam/delete', params),
+ // 获取安全考核统计信息
+ getExamRecordStatistical: (params) =>
+ axios.post('/secure/examRecord/recordStat', params),
+ // 查询安全考核记录
+ searchSafetyCheckRecord: (params) =>
+ axios({
+ method: 'post',
+ url: '/secure/examRecord/recordList',
+ headers: {
+ pageNum: params.pageNum,
+ pageSize: params.pageSize
+ },
+ data: {
+ examId: params.examId,
+ examResult: params.examResult,
+ departId: params.departId,
+ groupId: params.groupId,
+ startTime: params.startTime,
+ endTime: params.endTime
+ }
+ }),
+
+
+ // 安全考题信息列表
+ searchSafetyTopicList: (params) =>
+ axios({
+ method: 'post',
+ url: '/secure/question/findList',
+ headers: {
+ pageNum: params.pageNum,
+ pageSize: params.pageSize
+ },
+ data: {
+ trainName: params.trainName
+ }
+ }),
+ // 新增 修改安全考题信息
+ insertSafetyTopicInfo: (params) =>
+ axios.post('/secure/question/addQuestion', params),
+ // 删除安全考题信息
+ deleteSafetyTopicInfo: (params) =>
+ axios.post('/secure/question/delete', params),
+ // 获取答案列表信息
+ getAnswerlIstInfo: (params) =>
+ axios.post('secure/question/answerList', params),
+
+ /**
+ * 消防器材模块
+ */
+ // 查询消防器材信息列表
+ searchFireequipmentList: (params) =>
+ axios({
+ method: 'post',
+ url: '/secure/secureGood/findList',
+ headers: {
+ pageNum: params.pageNum,
+ pageSize: params.pageSize
+ },
+ data: {
+ goodName: params.goodName,
+ startTime: params.startTime,
+ endTime: params.endTime
+ }
+ }),
+ // 添加 修改 消防器材信息
+ insertFireequipmentInfo: (params) =>
+ axios.post('/secure/secureGood/addSecureGood', params),
+ // 删除消防器材信息
+ deleteFireequipmentInfo: (params) =>
+ axios.post('secure/secureGood/delete', params),
+ // 导出二维码
+ getFireequipmentCode: (params) =>
+ axios({
+ method: 'get',
+ url: '/secure/secureGood/viewcode',
+ params: params,
+ responseType: 'blob'
+ }),
+ // 获取消防器材图片列表
+ getFireequipmentImageInfo: (params) =>
+ axios.post('/secure/secureGood/fileList', params),
+
+ /**
+ * 安全培训和日常培训制定
+ */
+ // 列表信息
+ searchEnactLists: params =>
+ axios.post('/secure/secureTrain/secureTrainList', params),
+ // 添加信息
+ insertEnactInfo: params =>
+ axios.post('/secure/secureTrain/secureTrainInsert', params),
+ // 修改信息
+ updateEnactInfo: params =>
+ axios.post('/secure/secureTrain/secureTrainUpdate', params),
+ // 信息详情
+ detailsEnactInfo: params =>
+ axios.post('/secure/secureTrain/secureTrainInfo', params),
+ // 删除信息
+ deleteEnactInfo: params =>
+ axios.post('/secure/secureTrain/secureTrainDel', params),
+ //查询记录
+ getEnactRecords: params =>
+ axios.post('/secure/secureTrain/secureTrainRecord', params),
+
+ /**
+ * 安全资料模块
+ */
+ // 列表信息
+ searchDatumLists: params =>
+ axios.post('/secure/material/materialList', params),
+ // 添加信息
+ insertDatumInfo: params =>
+ axios.post('/secure/material/materialInsert', params),
+ // 修改信息
+ updateDatumInfo: params =>
+ axios.post('/secure/material/materialUpdate', params),
+ // 信息详情
+ detailsDatumInfo: params =>
+ axios.post('/secure/material/materialInfo', params),
+
+ /**
+ * 奖惩标准模块
+ */
+ // 列表信息
+ searchPunishLists: params =>
+ axios.post('/secure/encourage/encourageList', params),
+ // 添加信息
+ insertPunishInfo: params =>
+ axios.post('/secure/encourage/encourageInsert', params),
+ // 修改信息
+ updatePunishInfo: params =>
+ axios.post('/secure/encourage/encourageUpdate', params),
+ // 信息详情
+ detailsPunishInfo: params =>
+ axios.post('/secure/encourage/encourageInfo', params),
+ // 信息删除
+ deletePunishInfo: params =>
+ axios.post('/secure/encourage/encourageDel', params),
+
+ /**
+ * 风险分级管控
+ */
+ RiskGrad: {
+ // 危险源告知
+ warning : {
+ getLists: params =>
+ axios.post('/secure/regionHazardInform/findAll', params),
+ insert: params =>
+ axios.post('/secure/regionHazardInform/insert', params),
+ update: params =>
+ axios.post('/secure/regionHazardInform/update', params),
+ delete: params =>
+ axios.get('/secure/regionHazardInform/delete', { params }),
+ },
+ // 区域包保
+ allocation : {
+ getLists: params =>
+ axios.post('/secure/tRegionWarranty/findAll', params),
+ insert: params =>
+ axios.post('/secure/tRegionWarranty/insert', params),
+ update: params =>
+ axios.post('/secure/tRegionWarranty/update', params),
+ delete: params =>
+ axios.get('/secure/tRegionWarranty/delete', { params }),
+ }
+ },
+ /**
+ * 智能安全帽
+ */
+ SmartHelmet: {
+ // 人员列表(智能安全帽下其他页面共用此接口)
+ getLists: params =>
+ axios.post('/materials/helmet/helmetList', params),
+ // ---轨迹回放---
+ trackBack: {
+ // 获取用户在线时长
+ getOnlineTime: params =>
+ axios.post('/materials/helmet/helmetTrajectoryList', params),
+ // 轨迹数据
+ getTrackLists: params =>
+ axios.post('/materials/helmet/helmetMotionList', params),
+ },
+ // ---照片管理---
+ pic: {
+ // 图片
+ getPics: params =>
+ axios.post('/materials/helmet/helmetPictureList', params),
+ },
+ // ---报警记录---
+ warning: {
+ // 报警数
+ getWarning: params =>
+ axios.post('/materials/helmet/helmetReportTotal', params),
+ // 报警详情
+ getDetailWarning: params =>
+ axios.post('/materials/helmet/helmetReportUser', params),
+ },
+ // 区域包保
+ allocation : {
+ getLists: params =>
+ axios.post('/secure/tRegionWarranty/findAll', params),
+ insert: params =>
+ axios.post('/secure/tRegionWarranty/insert', params),
+ update: params =>
+ axios.post('/secure/tRegionWarranty/update', params),
+ delete: params =>
+ axios.get('/secure/tRegionWarranty/delete', { params }),
+ }
+ }
}
\ No newline at end of file
diff --git a/web/src/assets/markerIcon.png b/web/src/assets/markerIcon.png
new file mode 100644
index 0000000..39347ed
--- /dev/null
+++ b/web/src/assets/markerIcon.png
Binary files differ
diff --git a/web/src/components/element/Form.vue b/web/src/components/element/Form.vue
new file mode 100644
index 0000000..a955305
--- /dev/null
+++ b/web/src/components/element/Form.vue
@@ -0,0 +1,64 @@
+<template>
+ <div class="role">
+ <!-- https://juejin.cn/post/7042597964618924069?searchId=202310071305486BA29870D97939288832#heading-8 -->
+ <!-- https://juejin.cn/post/7139110255748710436?searchId=2023092815420483B1983D44854DBE6608#comment -->
+ <el-form
+ ref="ruleForm"
+ class="rule-form"
+ :model="formConfig.formModels"
+ :rules="formConfig.formRules"
+ :label-width="formConfig.labelWidth || 'auto'">
+ <el-row>
+ <el-col v-for="item in formConfig.formItems" :key="item.label" :span="item.span || 24">
+ <el-form-item :label="item.label" :style="formConfig.itemStyle || null">
+
+ <template v-if="item.type === 'input' || item.type === 'password'">
+ <el-input :placeholder="item.placeholder || `请输入${item.label}`"
+ :show-password="item.type === 'password'"></el-input>
+ </template>
+
+ <template v-else-if="item.type === 'select'">
+ <el-select :placeholder="item.placeholder || `请选择${item.label}`">
+ <el-option v-for="option in item.options" :key="option.label" :label="option.label"
+ :value="option.value"></el-option>
+ </el-select>
+ </template>
+
+ <template v-else>
+ <el-date-picker v-bind="item.otherOptions"></el-date-picker>
+ </template>
+
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ </div>
+</template>
+<script>
+export default {
+ data() {
+ return {}
+ },
+ props: {
+ formConfig: {
+ type: Object,
+ default: () => ({})
+ }
+ }
+}
+</script>
+<style scoped lang="scss">
+.el-form {
+ padding-right: 15px;
+ max-height: 550px;
+ overflow-y: auto;
+}
+
+::v-deep .el-form-item__label {
+ color: #fff
+}
+
+.el-select {
+ width: 100%;
+}
+</style>
\ No newline at end of file
diff --git a/web/src/components/element/Table.vue b/web/src/components/element/Table.vue
index b266c54..e5d56bd 100644
--- a/web/src/components/element/Table.vue
+++ b/web/src/components/element/Table.vue
@@ -1,151 +1,151 @@
-<template>
- <div>
- <!-- elTable -->
- <el-table v-loading="tableLoading" :data="tableData" :ref="tableRef" :size="tableSize" @row-click="rowClick"
- @row-dblclick="rowDblClick" @selection-change="handleSelectionChange" border stripe>
- <template v-for="(col, index) in tableColumns">
- <!-- 选择框 -->
- <el-table-column v-if="col.selection" :key="`selection${index}`" width="50" type="selection" align="center">
- </el-table-column>
-
- <!-- 序号 -->
- <el-table-column v-else-if="col.index" :key="`index${index}`" width="50" :label="col.name || '序号'" type="index"
- align="center">
- </el-table-column>
-
- <!-- 操作 -->
- <el-table-column v-else-if="col.operation" :key="`operation${col.name}`" :width="col.width" :label="col.name"
- align="center">
- <template #default="{ row }">
- <el-button v-for="subCol in col.value" :key="subCol.name" :class="subCol.class || ''" :icon="subCol.icon || ''"
- v-permission="subCol.permission || ''" @click="subCol.handleRow ? subCol.handleRow(row) : emptyFn">
- {{ subCol.name }}
- </el-button>
- </template>
- </el-table-column>
-
- <!-- 常规col -->
- <el-table-column v-else :key="col.name" :width="col.width" :label="col.name" :prop="col.key"
- :show-overflow-tooltip="col.showOverflowTip || false" :align="col.align || 'center'">
- <template #default="{ row }">
- <!-- slotのcol -->
- <template v-if="col.slot">
- <slot :name="col.slot" :row="row"></slot>
- </template>
- <!-- 需处理数据のcol -->
- <template v-else-if="col.formatter">
- {{ col.formatter(row) }}
- </template>
- <!-- 普通のcol -->
- <template v-else>
- {{ row[col.key] }}
- </template>
- </template>
- </el-table-column>
- </template>
- </el-table>
- <!-- 分页组件 -->
- <cPagination :total="pageTotal" :page-num.sync="pageNum" :page-size.sync="pageSize" @change-page-num="changePageNum"
- @change-page-size="changePageSize" />
- </div>
-</template>
-<script>
-import cPagination from "./Pagination"
-export default {
- name: "cTable",
- data() {
- return {
- time: null,
- emptyFn: () => { }
- };
- },
- props: {
- tableData: {
- type: Array,
- default() {
- return [];
- }
- },
- tableHeight: {
- type: Number,
- default: null
- },
- tableLoading: {
- type: Boolean,
- default: false
- },
- tableRef: {
- type: String,
- default: "multipleTable"
- },
- tableSize: {
- type: String,
- default: "mini"
- },
- tableColumns: {
- type: Array,
- default() {
- return [];
- }
- },
- pageTotal: {
- type: Number
- },
- pageNum: {
- type: Number,
- default: 1
- },
- pageSize: {
- type: Number,
- default: 10
- },
- pageChange: {
- type: Function,
- default: () => { }
- },
- handleSelection: {
- type: Function,
- default: () => { }
- }
- },
- components: {
- cPagination
- },
- methods: {
- changePageNum(val) {
- // console.log(val)
- // this.pageNum = val
- this.$emit("update:pageNum", val);
- this.pageChange();
- },
- changePageSize(val) {
- this.$emit("update:pageSize", val);
- if (val * (this.pageNum - 1) <= this.pageTotal) {
- this.pageChange();
- }
- },
- // 单击
- rowClick() {
- // this.time && clearTimeout(this.time);
- // this.time = setTimeout(() => {
- // this.$refs[this.tableRef].toggleRowSelection(row);
- // }, 200);
- },
- // 双击
- rowDblClick() {
- // this.time && clearTimeout(this.time);
- },
- clearSelection() {
- this.$refs[this.tableRef].clearSelection();
- },
- handleSelectionChange(val) {
- this.handleSelection(val);
- }
- }
-};
-</script>
-<style lang="scss" scoped>
-.el-table {
- border: none;
-}
+<template>
+ <div class="box">
+ <!-- elTable -->
+ <el-table v-loading="tableLoading" :data="tableData" :ref="tableRef" :size="tableSize" @row-click="handleRowClick"
+ @row-dblclick="handleRowDblClick" @selection-change="handleSelectionChange" border stripe>
+ <template v-for="(col, index) in tableColumns">
+ <!-- 选择框 -->
+ <el-table-column v-if="col.selection" :key="`selection${index}`" width="50" type="selection" align="center">
+ </el-table-column>
+
+ <!-- 序号 -->
+ <el-table-column v-else-if="col.index" :key="`index${index}`" width="50" :label="col.name || '序号'" type="index"
+ align="center">
+ </el-table-column>
+
+ <!-- 操作 -->
+ <el-table-column v-else-if="col.operation" :key="`operation${col.name}`" :width="col.width" :label="col.name"
+ align="center">
+ <template #default="{ row }">
+ <el-button v-for="subCol in col.value" :key="subCol.name" :class="subCol.class || ''"
+ :icon="subCol.icon || ''" v-permission="subCol.permission || ''"
+ @click="subCol.handleRow ? subCol.handleRow(row) : emptyFn">
+ {{ subCol.name }}
+ </el-button>
+ </template>
+ </el-table-column>
+
+ <!-- 常规col -->
+ <el-table-column v-else :key="col.name" :width="col.width" :label="col.name" :prop="col.key"
+ :show-overflow-tooltip="col.showOverflowTip || false" :align="col.align || 'center'">
+ <template #default="{ row }">
+ <!-- slotのcol -->
+ <template v-if="col.slot">
+ <slot :name="col.slot" :row="row"></slot>
+ </template>
+ <!-- 需处理数据のcol -->
+ <template v-else-if="col.formatter">
+ {{ col.formatter(row) }}
+ </template>
+ <!-- 普通のcol -->
+ <template v-else>
+ {{ row[col.key] }}
+ </template>
+ </template>
+ </el-table-column>
+ </template>
+ </el-table>
+ <!-- 分页组件 -->
+ <cPagination v-if="pageTotal" :total="pageTotal" :page-num.sync="pageNum" :page-size.sync="pageSize"
+ @change-page-num="changePageNum" @change-page-size="changePageSize" />
+ </div>
+</template>
+<script>
+import cPagination from "./Pagination"
+export default {
+ name: "cTable",
+ data() {
+ return {
+ time: null,
+ emptyFn: () => { }
+ };
+ },
+ props: {
+ tableData: {
+ type: Array,
+ default() {
+ return [];
+ }
+ },
+ tableHeight: {
+ type: Number,
+ default: null
+ },
+ tableLoading: {
+ type: Boolean,
+ default: false
+ },
+ tableRef: {
+ type: String,
+ default: "multipleTable"
+ },
+ tableSize: {
+ type: String,
+ default: "mini"
+ },
+ tableColumns: {
+ type: Array,
+ default() {
+ return [];
+ }
+ },
+ pageTotal: {
+ type: Number
+ },
+ pageNum: {
+ type: Number,
+ default: 1
+ },
+ pageSize: {
+ type: Number,
+ default: 10
+ },
+ pageChange: {
+ type: Function,
+ default: () => { }
+ },
+ handleSelection: {
+ type: Function,
+ default: () => { }
+ },
+ rowClick: {
+ type: Function,
+ default: () => { }
+ },
+ },
+ components: {
+ cPagination
+ },
+ methods: {
+ changePageNum(val) {
+ this.$emit("update:pageNum", val)
+ this.pageChange()
+ },
+ changePageSize(val) {
+ this.$emit("update:pageSize", val)
+ if (val * (this.pageNum - 1) <= this.pageTotal) {
+ this.pageChange()
+ }
+ },
+ // 单击
+ handleRowClick(row) {
+ this.rowClick(row)
+ },
+ // 双击
+ handleRowDblClick() { },
+ handleSelectionChange(val) {
+ this.handleSelection(val)
+ }
+ }
+};
+</script>
+<style lang="scss" scoped>
+.box {
+ height: 100%;
+}
+
+.el-table {
+ border: none;
+ height: 100%;
+}
</style>
\ No newline at end of file
diff --git a/web/src/components/table/Pagination.vue b/web/src/components/table/Pagination.vue
deleted file mode 100644
index 46cfa39..0000000
--- a/web/src/components/table/Pagination.vue
+++ /dev/null
@@ -1,78 +0,0 @@
-<template>
- <div class="pagination-container">
- <el-pagination @current-change="handleCurrentChange" @size-change="handleSizeChange" :page-sizes="[10, 20, 30]"
- :total="total" :current-page="pageNum" :page-size="pageSize"
- layout="total, sizes, prev, pager, next, jumper"></el-pagination>
- </div>
-</template>
-<script>
-export default {
- name: "pagination",
- data() {
- return {};
- },
- props: {
- // 总页数
- total: {
- type: Number,
- },
- // 当前页
- pageNum: {
- type: Number,
- },
- // 每页显示条数
- pageSize: {
- type: Number,
- },
- },
- methods: {
- // 当前页码变化
- handleCurrentChange(val) {
- this.$emit("change-page-num", val);
- },
- // 每页查看条数变化
- handleSizeChange(val) {
- this.$emit("change-page-size", val);
- },
- },
- // watch: {
- // pageSize: {
- // // immediate: true,
- // handler(newValue, oldValue) {
- // this.page._pageSize = this.newValue;
- // console.log("pageSize", newValue, oldValue);
- // },
- // },
- // pageNum: {
- // // immediate: true,
- // handler(newValue, oldValue) {
- // this.page._currentPage = newValue;
- // console.log("pageNum", newValue, oldValue);
- // },
- // },
- // },
-};
-</script>
-<style lang="scss" scoped>
-// 主体底部样式
-::v-deep.el-pagination .btn-prev,
-::v-deep.el-pagination .btn-next,
-::v-deep.el-pagination .el-pager li {
- background-color: rgba(20, 25, 58, 0.4);
- border: 1px solid rgba(255, 255, 255, 0.12);
- font-weight: 400;
- color: #E2E4E9;
- border-radius: 4px;
-}
-
-::v-deep.el-pagination .el-pager li:not(.disabled).active {
- color: #fff;
- border: 1px solid #39B5FE;
- background-color: #0B3562;
- font-weight: 400;
-}
-
-.pagination-container {
- margin-top: 30px;
-}
-</style>
\ No newline at end of file
diff --git a/web/src/components/table/Table.vue b/web/src/components/table/Table.vue
deleted file mode 100644
index ce3e9a8..0000000
--- a/web/src/components/table/Table.vue
+++ /dev/null
@@ -1,126 +0,0 @@
-<template>
- <div>
- <el-table v-loading="tableLoading" :data="tableData" :ref="tableRef" :size="tableSize" @row-click="rowClick"
- @row-dblclick="rowDblClick" @selection-change="handleSelectionChange" border stripe>
- <template v-for="(col, index) in tableColumnsConfig">
- <!-- 选择框 -->
- <el-table-column v-if="col.selection" width="50" :key="`selection_${index}`" type="selection" align="center">
- </el-table-column>
- <!-- 序号 -->
- <el-table-column v-else-if="col.index" width="50" label="序号" :key="`index_${index}`" type="index" align="center">
- </el-table-column>
- <!-- 自定义 -->
- <slot v-else-if="col.slot" :name="col.slot" show-overflow-tooltip></slot>
- <!-- 常规col -->
- <el-table-column v-else :key="`col_${index}`" :width="col.width" :label="col.name" :prop="col.key"
- :show-overflow-tooltip="col.showOverflowTip || false" :align="col.align || 'center'">
- <template #default="{ row }">
- {{ row[col.key] }}
- </template>
- </el-table-column>
- </template>
- </el-table>
- <!-- 分页组件 -->
- <cPagination :total="pageTotal" :page-num.sync="pageNum" :page-size.sync="pageSize" @change-page-num="changePageNum"
- @change-page-size="changePageSize" />
- </div>
-</template>
-<script>
-import cPagination from "@/components/table/Pagination"
-export default {
- name: "cTable",
- data() {
- return {
- time: null
- };
- },
- props: {
- tableData: {
- type: Array,
- default() {
- return [];
- }
- },
- tableHeight: {
- type: Number,
- default: null
- },
- tableLoading: {
- type: Boolean,
- default: false
- },
- tableRef: {
- type: String,
- default: "multipleTable"
- },
- tableSize: {
- type: String,
- default: "mini"
- },
- tableColumnsConfig: {
- type: Array,
- default() {
- return [];
- }
- },
- pageTotal: {
- type: Number
- },
- pageNum: {
- type: Number,
- default: 1
- },
- pageSize: {
- type: Number,
- default: 10
- },
- pageChange: {
- type: Function,
- default: () => { }
- },
- handleSelection: {
- type: Function,
- default: () => { }
- }
- },
- components: {
- cPagination
- },
- methods: {
- changePageNum(val) {
- // console.log(val)
- // this.pageNum = val
- this.$emit("update:pageNum", val);
- this.pageChange();
- },
- changePageSize(val) {
- this.$emit("update:pageSize", val);
- if (val * (this.pageNum - 1) <= this.pageTotal) {
- this.pageChange();
- }
- },
- // 单击
- rowClick() {
- // this.time && clearTimeout(this.time);
- // this.time = setTimeout(() => {
- // this.$refs[this.tableRef].toggleRowSelection(row);
- // }, 200);
- },
- // 双击
- rowDblClick() {
- // this.time && clearTimeout(this.time);
- },
- clearSelection() {
- this.$refs[this.tableRef].clearSelection();
- },
- handleSelectionChange(val) {
- this.handleSelection(val);
- }
- }
-};
-</script>
-<style lang="scss" scoped>
-.el-table {
- border: none;
-}
-</style>
\ No newline at end of file
diff --git a/web/src/plugins/public.js b/web/src/plugins/public.js
index 10fb130..cd06262 100644
--- a/web/src/plugins/public.js
+++ b/web/src/plugins/public.js
@@ -1,167 +1,196 @@
-import axios from 'axios'
-import Vue from 'vue'
-/**
- * 防抖函数
- */
- export const debounce = (fun, time) => {
- let timer = null
- return function() {
- if(timer) {
- clearTimeout(timer)
- }
- let args = arguments
- timer = setTimeout(() => {
- fun.apply(this, args)
- }, time)
- }
-}
-
-/**
- * 节流函数
- */
-export const throttle = (fun, time) => {
- let strTime = 0
- return function() {
- let endTime = new Date()
- let args = arguments
- if(endTime - strTime > time) {
- strTime = endTime
- fun.apply(this, args)
- }
- }
-}
-
-/**
- * 动态切换组件尺寸
-*/
-export const changeSize = () => {
- // let size = ""
- // let viewWidth = document.documentElement.clientWidth
- // switch(true) {
- // case viewWidth <= 1024:
- // size = "mini"
- // break;
- // case viewWidth <= 1280:
- // size = "small"
- // break;
- // case viewWidth <= 1600:
- // size = "medium"
- // break;
- // default:
- // size = ""
- // }
- // return size
- return 'small'
-}
-
-/**
- * 存入/更新cookie信息
- * name: cookie 名称
- * values: cookie 值
- * times: 过期时间
-*/
-export const setCookie = (name, values, times) => {
- let date = new Date();
- let params = JSON.stringify(values)
- date.setTime(date.getTime() + (times * 24 * 60 * 60 * 1000));
- document.cookie = `${name}=${params};expires=${date.toGMTString()}`;
-}
-
-/**
- * 获取cookie信息
- * name: 存入的cookie名
-*/
-export const getCookie = (name) => {
- let data = "";
- let list = document.cookie.split(';');
- list.forEach(item => {
- item = item.split('=')
- if(item[0].replace(/^\s+|\s+$/g,"") === name) {
- data = JSON.parse(item[item.length - 1])
- }
- })
- return data
-}
-
-/**
- * 处理时间戳
-*/
-export const changeTime = (time) => {
- const date = new Date(time);
- console.log(date,'---');
- let year = date.getFullYear();
- let month = date.getMonth() + 1;
- month = month > 9 ? month : `0${month}`;
- let day = date.getDate() > 9 ? date.getDate() : `0${date.getDate()}`;
- let hours = date.getHours() > 9 ? date.getHours() : `0${date.getHours()}`;
- let min = date.getMinutes() > 9 ? date.getMinutes() : `0${date.getMinutes()}`;
- let sec = date.getSeconds() > 9 ? date.getSeconds() : `0${date.getSeconds()}`;
- return `${year}-${month}-${day} ${hours}:${min}:${sec}`
-}
-
-/**
- * 下载文件公共方法
-*/
-
-export const downLoadFile = (data, url) => {
- let link = document.createElement("a")
- link.style.display = "none";
- link.href = `${process.env.VUE_APP_BASE_URL}${url}?authcode=${data}`;
- document.body.appendChild(link)
- link.click();
- URL.revokeObjectURL(link.href) // 释放URL 对象
-}
-
-export const downFiles = (data, fileName = 'downLoad', fileType) => {
- let url = URL.createObjectURL(new Blob([data]))
- let link = document.createElement("a")
- link.style.display = "none";
- link.href = url;
- link.setAttribute("download", `${fileName}.${fileType}`)
- document.body.appendChild(link)
- link.click();
- URL.revokeObjectURL(link.href) // 释放URL 对象
-}
-
-/**
- * 转二维码(blob流转地址)
- */
-export const tranQr = (val) => {
- let imageUrl = '';
- Vue.prototype.$api.Print.getPrintPhone({num:val}).then(res=>{
- imageUrl = URL.createObjectURL(new Blob([res.data]));
- })
- return imageUrl
-}
-
-
-export const downLoadQR = (data, url) => {
- axios({
- method: 'get',
- url: `${process.env.VUE_APP_BASE_URL}${url}?num=${data}`,
- responseType: 'blob'
- }).then((res) => {
- downFiles(res.data, '二维码图片','png')
- })
- // let link = document.createElement("a")
- // link.style.display = "none";
- // link.href = ;
- // document.body.appendChild(link)
- // link.click();
- // URL.revokeObjectURL(link.href) // 释放URL 对象
-
- // link.href = `${process.env.VUE_APP_BASE_URL}${url}?num=${data}`;
- // link.setAttribute("download", '二维码图片.png')
- // document.body.appendChild(link)
- // link.click();
-}
-//通过扫描二维码跳转详情页面
-export const downLoadQRDetails = (data,id,typePage, url) => {
- axios({
- method: 'get',
- url: `${process.env.VUE_APP_BASE_URL}${url}?num=${data}&bigDeviceId=${id}&type=${typePage}`,
- responseType: 'blob'
- }).then((res) => {
- downFiles(res.data, '二维码图片','png')
- })
-}
\ No newline at end of file
+import axios from 'axios'
+import Vue from 'vue'
+/**
+ * 防抖函数
+ */
+ export const debounce = (fun, time) => {
+ let timer = null
+ return function() {
+ if(timer) {
+ clearTimeout(timer)
+ }
+ let args = arguments
+ timer = setTimeout(() => {
+ fun.apply(this, args)
+ }, time)
+ }
+}
+
+/**
+ * 节流函数
+ */
+export const throttle = (fun, time) => {
+ let strTime = 0
+ return function() {
+ let endTime = new Date()
+ let args = arguments
+ if(endTime - strTime > time) {
+ strTime = endTime
+ fun.apply(this, args)
+ }
+ }
+}
+
+/**
+ * 动态切换组件尺寸
+*/
+export const changeSize = () => {
+ // let size = ""
+ // let viewWidth = document.documentElement.clientWidth
+ // switch(true) {
+ // case viewWidth <= 1024:
+ // size = "mini"
+ // break;
+ // case viewWidth <= 1280:
+ // size = "small"
+ // break;
+ // case viewWidth <= 1600:
+ // size = "medium"
+ // break;
+ // default:
+ // size = ""
+ // }
+ // return size
+ return 'small'
+}
+
+/**
+ * 存入/更新cookie信息
+ * name: cookie 名称
+ * values: cookie 值
+ * times: 过期时间
+*/
+export const setCookie = (name, values, times) => {
+ let date = new Date();
+ let params = JSON.stringify(values)
+ date.setTime(date.getTime() + (times * 24 * 60 * 60 * 1000));
+ document.cookie = `${name}=${params};expires=${date.toGMTString()}`;
+}
+
+/**
+ * 获取cookie信息
+ * name: 存入的cookie名
+*/
+export const getCookie = (name) => {
+ let data = "";
+ let list = document.cookie.split(';');
+ list.forEach(item => {
+ item = item.split('=')
+ if(item[0].replace(/^\s+|\s+$/g,"") === name) {
+ data = JSON.parse(item[item.length - 1])
+ }
+ })
+ return data
+}
+
+/**
+ * 处理时间戳
+*/
+export const changeTime = (time) => {
+ const date = new Date(time);
+ console.log(date,'---');
+ let year = date.getFullYear();
+ let month = date.getMonth() + 1;
+ month = month > 9 ? month : `0${month}`;
+ let day = date.getDate() > 9 ? date.getDate() : `0${date.getDate()}`;
+ let hours = date.getHours() > 9 ? date.getHours() : `0${date.getHours()}`;
+ let min = date.getMinutes() > 9 ? date.getMinutes() : `0${date.getMinutes()}`;
+ let sec = date.getSeconds() > 9 ? date.getSeconds() : `0${date.getSeconds()}`;
+ return `${year}-${month}-${day} ${hours}:${min}:${sec}`
+}
+
+/**
+ * 下载文件公共方法
+*/
+
+export const downLoadFile = (data, url) => {
+ let link = document.createElement("a")
+ link.style.display = "none";
+ link.href = `${process.env.VUE_APP_BASE_URL}${url}?authcode=${data}`;
+ document.body.appendChild(link)
+ link.click();
+ URL.revokeObjectURL(link.href) // 释放URL 对象
+}
+
+export const downFiles = (data, fileName = 'downLoad', fileType) => {
+ let url = URL.createObjectURL(new Blob([data]))
+ let link = document.createElement("a")
+ link.style.display = "none";
+ link.href = url;
+ link.setAttribute("download", `${fileName}.${fileType}`)
+ document.body.appendChild(link)
+ link.click();
+ URL.revokeObjectURL(link.href) // 释放URL 对象
+}
+
+/**
+ * 转二维码(blob流转地址)
+ */
+export const tranQr = (val) => {
+ let imageUrl = '';
+ Vue.prototype.$api.Print.getPrintPhone({num:val}).then(res=>{
+ imageUrl = URL.createObjectURL(new Blob([res.data]));
+ })
+ return imageUrl
+}
+
+
+export const downLoadQR = (data, url) => {
+ axios({
+ method: 'get',
+ url: `${process.env.VUE_APP_BASE_URL}${url}?num=${data}`,
+ responseType: 'blob'
+ }).then((res) => {
+ downFiles(res.data, '二维码图片','png')
+ })
+ // let link = document.createElement("a")
+ // link.style.display = "none";
+ // link.href = ;
+ // document.body.appendChild(link)
+ // link.click();
+ // URL.revokeObjectURL(link.href) // 释放URL 对象
+
+ // link.href = `${process.env.VUE_APP_BASE_URL}${url}?num=${data}`;
+ // link.setAttribute("download", '二维码图片.png')
+ // document.body.appendChild(link)
+ // link.click();
+}
+//通过扫描二维码跳转详情页面
+export const downLoadQRDetails = (data,id,typePage, url) => {
+ axios({
+ method: 'get',
+ url: `${process.env.VUE_APP_BASE_URL}${url}?num=${data}&bigDeviceId=${id}&type=${typePage}`,
+ responseType: 'blob'
+ }).then((res) => {
+ downFiles(res.data, '二维码图片','png')
+ })
+}
+
+/* Date原型添加format方法 */
+Date.prototype.format = function (fmt) {
+ fmt = fmt || 'yyyy-MM-dd'
+ var o = {
+ 'M+': this.getMonth() + 1, //月份
+ 'd+': this.getDate(), //日
+ 'h+': this.getHours(), //小时
+ 'm+': this.getMinutes(), //分
+ 's+': this.getSeconds(), //秒
+ 'q+': Math.floor((this.getMonth() + 3) / 3), //季度
+ S: this.getMilliseconds() //毫秒
+ }
+ if (/(y+)/.test(fmt)) {
+ fmt = fmt.replace(
+ RegExp.$1,
+ (this.getFullYear() + '').substr(4 - RegExp.$1.length)
+ )
+ }
+ for (var k in o) {
+ if (new RegExp('(' + k + ')').test(fmt)) {
+ fmt = fmt.replace(
+ RegExp.$1,
+ RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length)
+ )
+ }
+ }
+ return fmt
+}
\ No newline at end of file
diff --git a/web/src/style/layout-main.scss b/web/src/style/layout-main.scss
index 3eb82ea..e6479f6 100644
--- a/web/src/style/layout-main.scss
+++ b/web/src/style/layout-main.scss
@@ -1,464 +1,497 @@
-// 页面主体样式
-.main {
- position: absolute;
- display: flex;
- flex-direction: column;
- width: calc(100% - 30px);
- height: calc(100% - 30px);
- border-radius: 4px;
- background: url('~@/assets/main-bg.png') no-repeat;
- background-size: 100% 100%;
- // background: linear-gradient(170deg, rgba(14, 54, 120, .3) 20%, #0E3678 35%, rgba(14, 54, 120, .3) 55%);
- box-shadow: 0 2px 12px 0 rgba(57, 181, 254, 0.6);
-
- //
- .main_tabs {
- padding: 20px 0 10px;
-
- /deep/ .el-tabs__nav-wrap {
- padding: 0 20px;
- font-size: 20px;
-
- &::after {
- height: 1px;
- background-color: #1B428F;
- }
- }
-
- /deep/ .el-tabs__active-bar {
- background-color: #39B5FE;
- }
- }
-
- // 主体头部样式
- .main_header {
- display: flex;
- margin: 9px 24px 24px;
- font-size: 1rem;
- flex-wrap: wrap;
-
- .header_item {
- display: flex;
- align-items: center;
- margin-right: 24px;
- margin-top: 15px;
- }
-
- .header_label {
- color: #EAEAEA;
- white-space: nowrap;
- text-align: right;
- // min-width: 100px;
- }
- }
-
- //
- .main_functional {
- display: flex;
- margin: 10px 10px 20px;
- }
-
- // 主体内容样式
- .main_content {
- position: relative;
- flex: 1;
- margin: 0 24px;
- overflow: hidden;
- }
-
- // 主体底部样式
- .main_footer {
- height: 50px;
- margin: 10px;
- text-align: right;
- margin-top: 35px;
- ::v-deep.el-input__inner{
- border:1px solid #294366;
- background-color: #102448;
- }
- ::v-deep .el-pagination__jump{
- color: #bfbfbf;
- }
- }
-
- ::v-deep .search_btn {
- border: 0 none;
- color: #fff;
- background: url('~@/assets/search_bg.png') no-repeat;
- background-size: 100% 100%;
- &:hover {
- color: #F69C42;
- }
- }
-
- ::v-deep .table_btn {
- border: 0 none;
- color: #39B5FE;
- background: url('~@/assets/table_btn.png') no-repeat;
- background-size: 100% 100%;
- &:hover {
- color: rgba($color: #39B5FE, $alpha: .7);
- }
- }
-
- ::v-deep .delete_btn {
- border: 0 none;
- color: #F94550;
- background: url('~@/assets/error_btn.png') no-repeat;
- background-size: 100% 100%;
- &:hover {
- color: rgba($color: #F94550, $alpha: .7);
- }
- }
-
- ::v-deep .el-tabs__item {
- color: #fff;
- }
- ::v-deep .el-loading-mask {
- background-color: rgba($color: #132a5c, $alpha: .8);
- }
- ::v-deep .el-tabs__item.is-active {
- color: #39B5FE;
- }
- ::v-deep .el-tabs__active-bar {
- background-color: #39B5FE;
- }
- ::v-deep .el-tabs__nav-wrap::after {
- background-color: #1c50ae;
- }
- ::v-deep .el-table {
- background: transparent
- }
- ::v-deep .el-input__inner {
- border: 1px solid #39B5FE;
- background-color: transparent;
- color: #fff;
- }
- ::v-deep .el-textarea__inner {
- color: #fff;
- background-color: transparent;
- border: 1px solid #39B5FE;
- }
- ::v-deep .el-dialog__body .el-input__inner {
- background-color: transparent;
- border: 1px solid rgba(57, 181, 254, 1);
- color: #fff;
- }
- ::v-deep .el-table tr {
- background: transparent;
- }
- ::v-deep .el-table__expand-icon {
- color: #22fffe;
- }
- ::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
- background: rgba($color: #34AFED, $alpha: .5);
- }
- ::v-deep .el-table .warning-row {
- background: transparent;
- }
- ::v-deep .el-table .success-row {
- background: #031a46;
- }
- ::v-deep .el-table__body .el-table__row.hover-row td {
- background-color: #0d3271;
- }
- ::v-deep .el-date-editor .el-range-input {
- background-color: #0b2f66;
- color: #fff;
- }
- ::v-deep .el-table tr {
- &:nth-of-type(even) {
- background: linear-gradient(
- 90deg,
- transparent 3%,
- rgba(57, 166, 254, 0.4) 55%,
- transparent 95%);
- }
- }
- ::v-deep .el-date-editor .el-range-separator {
- // color: #606266;
- color: #fff;
- }
- ::v-deep .el-upload--picture-card {
- background-color: #0b2c64;
- border-color: #39B5FE;
- }
- ::v-deep .el-radio {
- padding-bottom: 16px;
- color: #fff;
- }
- ::v-deep .el-radio__inner {
- border-color: #39B5FE;
- background-color: #061c48;
- }
- ::v-deep .el-input-group__append,
- .el-input-group__prepend {
- background-color: #0B2559;
- border-color: #39B5FE;
- color: #fff;
- padding: 0 10px;
- }
- /deep/.el-date-editor .el-range-input{
- background-color: transparent;
- }
-}
-
-// 列表按钮侧边竖线
-.line {
- position: relative;
-
- &::before {
- content: "";
- position: absolute;
- top: 50%;
- right: -6px;
- transform: translateY(-50%);
- width: 1px;
- height: 40%;
- background-color: #eaeaea;
- }
-}
-.preview_dialog{
- ::v-deep .el-dialog__headerbtn{
- font-size: 24px!important;
- }
-}
-
-.scan_dialog{
- ::v-deep .el-dialog{
- min-width: 200px!important;
- margin-top: 30vh!important;
- }
- ::v-deep .el-dialog__header{
- padding-bottom: 10px!important;
- }
- ::v-deep .el-dialog__body{
- padding: 10px 10px 26px!important;
- }
-}
-// 弹出框标题蓝线
-.prop_dialog {
- ::v-deep .el-dialog__header {
- position: relative;
- padding: 20px 20px 20px 24px;
- }
-
- ::v-deep .el-dialog__headerbtn .el-dialog__close {
- color: #BFBFBF;
- }
-
- ::v-deep .el-dialog__body {
- padding: 30px 10px 10px 24px;
- }
- ::v-deep .el-dialog__title {
- color: #39B5FE;
- font-weight: 600;
- }
- ::v-deep .el-dialog__footer {
- padding: 20px 20px 20px;
- }
- .submit_btn {
- border: 0 none;
- color: #39B5FE;
- background: url('~@/assets/submit_bg.png') no-repeat;
- background-size: 100% 100%;
- &:hover {
- color: #39B5FE;
- }
- }
-}
-
-// form表单样式
-.rule_form {
- padding-right: 15px;
- max-height: 550px;
- overflow-y: auto;
-
- ::v-deep .el-select {
- width: 100%;
- }
- ::v-deep .el-date-editor.el-input,
- .el-date-editor.el-input__inner {
- width: 100%;
- color: #fff;
- background-color: #102351;
- }
- ::v-deep.el-form-item__label-wrap .el-form-item__label {
- color: #fff;
- }
- .text_ranage {
- width: 210px;
- padding: 0px 15px;
- margin-left: 15px;
- background-color: #102351;
- color: #fff;
- }
- ::v-deep .el-form-item__label {
- color: #fff;
- }
- ::v-deep .el-form-item__content {
- display: flex;
- flex-direction: row;
- .marks_text {
- margin-left: 20px;
- padding: 0px 10px;
- width: 18rem;
- border: 1px solid #deeaff;
- background-color: #deeaff;
-
- .el-icon-time:before {
- color: #2c77ff;
- padding-right: 10px;
- }
- }
- .el-switch {
- padding-top: 15px;
- }
- }
- ::v-deep .el-textarea__inner {
- font-family: Avenir, Helvetica, Arial, sans-serif;
- background-color: #102351;
- }
-
- ::v-deep .el-cascader {
- width: 100%;
- }
- ::v-deep .el-input-number {
- width: 100%;
- }
- ::v-deep .el-input-number .el-input__inner {
- text-align: left;
- background-color: #102351;
- }
-}
-
-.tabs_main {
- margin: 0;
- width: 100%;
- height: 100%;
- box-shadow: none;
-}
-
-/deep/ .el-textarea__inner{
- background-color: transparent;
- border: 1px solid #39B5FE;
-}
-.inspection_content {
- display: flex;
- flex-direction: column;
- padding: 0 20px;
- height: 500px;
- overflow: auto;
-
- .inspection_content_item {
- display: flex;
- flex-direction: column;
- margin-bottom: 20px;
- width: 100%;
- color: #E1E3E9;
-
- .inspection_content_item--header {
- position: relative;
- display: flex;
- justify-content: space-between;
- padding: 0 0 5px 15px;
- border-bottom: 1px solid #39B5FE;
-
- &::after {
- content: "";
- position: absolute;
- top: 50%;
- left: 0;
- transform: translateY(-50%);
- width: 3px;
- height: 70%;
- background: #19F7F7;
- }
-
- .label {
- color: #19F7F7;
- }
- }
-
- .inspection_content_item--content {
- display: flex;
- flex-direction: column;
- padding: 10px 0;
-
- .info_image {
- margin: 10px 0;
- width: 150px;
- height: 140px;
- border: 1px solid #39B5FE;
- border-radius: 6px;
- cursor: pointer;
- }
- }
- }
-}
-
-.prop_image {
- padding: 0 15px 20px 0;
- width: 100%;
- height: 450px;
- background: transparent;
-}
-//预览按钮样式
-.preview_content{
- padding: 24px 20px;
- box-shadow: 2px 2px 12px 0 rgba(0, 0, 0, 0.06);
- .preview_titles{
- text-align: center;
- font-size: 28px;
- font-weight: 600;
- color: #39B5FE;
- }
- .preview_times{
- text-align: center;
- font-size: 14px;
- color: #999999;
- margin-top: 15px;
- padding-bottom: 15px;
- border-bottom: 1px dashed #eaeaea;
- }
- .preview_main{
- padding: 24px 20px 0px;
- overflow: auto;
- }
-}
-
-/deep/.el-dialog.is-fullscreen{
- overflow-x: hidden;
- overflow-y: auto;
- width: 64%;
- height: 92%;
- margin-top: 40px;
- background: #f6f6f6!important;
-}
-
-/deep/.el-input-number__decrease{
- border-right-color: #39B5FE;
- .el-icon-minus:before{
- color: #19F6F8;
- }
-}
-
-/deep/.el-input-number__increase{
- border-left-color: #39B5FE;
- .el-icon-plus:before{
- color: #19F6F8;
- }
-}
-
-/deep/.el-input-number__increase{
- background-color: transparent;
-}
-
-/deep/.el-input-number__decrease{
- background-color: transparent;
-}
-
-/deep/.el-textarea.is-disabled .el-textarea__inner{
- background-color: #0D2657;
- border-color: #39B5FE;
+// 页面主体样式
+.main {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ width: calc(100% - 30px);
+ height: calc(100% - 30px);
+ border-radius: 4px;
+ background: url('~@/assets/main-bg.png') no-repeat;
+ background-size: 100% 100%;
+ // background: linear-gradient(170deg, rgba(14, 54, 120, .3) 20%, #0E3678 35%, rgba(14, 54, 120, .3) 55%);
+ box-shadow: 0 2px 12px 0 rgba(57, 181, 254, 0.6);
+
+ //
+ .main_tabs {
+ padding: 20px 0 10px;
+
+ /deep/ .el-tabs__nav-wrap {
+ padding: 0 20px;
+ font-size: 20px;
+
+ &::after {
+ height: 1px;
+ background-color: #1B428F;
+ }
+ }
+
+ /deep/ .el-tabs__active-bar {
+ background-color: #39B5FE;
+ }
+ }
+
+ // 主体头部样式
+ .main_header {
+ display: flex;
+ margin: 9px 24px 24px;
+ font-size: 1rem;
+ flex-wrap: wrap;
+
+ .header_item {
+ display: flex;
+ align-items: center;
+ margin-right: 24px;
+ margin-top: 15px;
+ }
+
+ .header_label {
+ color: #EAEAEA;
+ white-space: nowrap;
+ text-align: right;
+ // min-width: 100px;
+ }
+ }
+
+ //
+ .main_functional {
+ display: flex;
+ margin: 10px 10px 20px;
+ }
+
+ // 主体内容样式
+ .main_content {
+ position: relative;
+ flex: 1;
+ margin: 0 24px;
+ overflow: hidden;
+ }
+
+ // 主体底部样式
+ .main_footer {
+ height: 50px;
+ margin: 10px;
+ text-align: right;
+ margin-top: 35px;
+ ::v-deep.el-input__inner{
+ border:1px solid #294366;
+ background-color: #102448;
+ }
+ ::v-deep .el-pagination__jump{
+ color: #bfbfbf;
+ }
+ }
+
+ ::v-deep .search_btn {
+ border: 0 none;
+ color: #fff;
+ background: url('~@/assets/search_bg.png') no-repeat;
+ background-size: 100% 100%;
+ &:hover {
+ color: #F69C42;
+ }
+ }
+
+ ::v-deep .table_btn {
+ border: 0 none;
+ color: #39B5FE;
+ background: url('~@/assets/table_btn.png') no-repeat;
+ background-size: 100% 100%;
+ &:hover {
+ color: rgba($color: #39B5FE, $alpha: .7);
+ }
+ }
+
+ ::v-deep .delete_btn {
+ border: 0 none;
+ color: #F94550;
+ background: url('~@/assets/error_btn.png') no-repeat;
+ background-size: 100% 100%;
+ &:hover {
+ color: rgba($color: #F94550, $alpha: .7);
+ }
+ }
+
+ ::v-deep .el-checkbox__inner {
+ border: 1px solid #3DC8FF;
+ background-color: transparent;
+ &::after{
+ border: 1px solid #3DC8FF;
+ border-left: 0;
+ border-top: 0;
+ }
+ }
+ ::v-deep .el-tabs__item {
+ color: #fff;
+ }
+ ::v-deep .el-loading-mask {
+ background-color: rgba($color: #132a5c, $alpha: .8);
+ }
+ ::v-deep .el-tabs__item.is-active {
+ color: #39B5FE;
+ }
+ ::v-deep .el-tabs__active-bar {
+ background-color: #39B5FE;
+ }
+ ::v-deep .el-tabs__nav-wrap::after {
+ background-color: #1c50ae;
+ }
+ ::v-deep .el-table {
+ background: transparent
+ }
+ ::v-deep .el-input__inner {
+ border: 1px solid #39B5FE;
+ background-color: transparent;
+ color: #fff;
+ }
+ ::v-deep .el-textarea__inner {
+ color: #fff;
+ background-color: transparent;
+ border: 1px solid #39B5FE;
+ }
+ ::v-deep .el-dialog__body .el-input__inner {
+ background-color: transparent;
+ border: 1px solid rgba(57, 181, 254, 1);
+ color: #fff;
+ }
+ ::v-deep .el-table tr {
+ background: transparent;
+ }
+ ::v-deep .el-table__expand-icon {
+ color: #22fffe;
+ }
+ ::v-deep .el-table--enable-row-hover .el-table__body tr:hover > td.el-table__cell {
+ background: rgba($color: #34AFED, $alpha: .5);
+ }
+ ::v-deep .el-table .warning-row {
+ background: transparent;
+ }
+ ::v-deep .el-table .success-row {
+ background: #031a46;
+ }
+ ::v-deep .el-table__body .el-table__row.hover-row td {
+ background-color: #0d3271;
+ }
+ ::v-deep .el-date-editor .el-range-input {
+ background-color: #0b2f66;
+ color: #fff;
+ }
+ ::v-deep .el-table tr {
+ &:nth-of-type(even) {
+ background: linear-gradient(
+ 90deg,
+ transparent 3%,
+ rgba(57, 166, 254, 0.4) 55%,
+ transparent 95%);
+ }
+ }
+ ::v-deep .el-date-editor .el-range-separator {
+ // color: #606266;
+ color: #fff;
+ }
+ ::v-deep .el-upload--picture-card {
+ background-color: #0b2c64;
+ border-color: #39B5FE;
+ }
+ ::v-deep .el-radio {
+ padding-bottom: 16px;
+ color: #fff;
+ }
+ ::v-deep .el-radio__inner {
+ border-color: #39B5FE;
+ background-color: #061c48;
+ }
+ ::v-deep .el-input-group__append,
+ .el-input-group__prepend {
+ background-color: #0B2559;
+ border-color: #39B5FE;
+ color: #fff;
+ padding: 0 10px;
+ }
+ /deep/.el-date-editor .el-range-input{
+ background-color: transparent;
+ }
+}
+
+// 列表按钮侧边竖线
+.line {
+ position: relative;
+
+ &::before {
+ content: "";
+ position: absolute;
+ top: 50%;
+ right: -6px;
+ transform: translateY(-50%);
+ width: 1px;
+ height: 40%;
+ background-color: #eaeaea;
+ }
+}
+.preview_dialog{
+ ::v-deep .el-dialog__headerbtn{
+ font-size: 24px!important;
+ }
+}
+
+.scan_dialog{
+ ::v-deep .el-dialog{
+ min-width: 200px!important;
+ margin-top: 30vh!important;
+ }
+ ::v-deep .el-dialog__header{
+ padding-bottom: 10px!important;
+ }
+ ::v-deep .el-dialog__body{
+ padding: 10px 10px 26px!important;
+ }
+}
+// 弹出框标题蓝线
+.prop_dialog {
+ ::v-deep .el-dialog__header {
+ position: relative;
+ padding: 20px 20px 20px 24px;
+ }
+
+ ::v-deep .el-dialog__headerbtn .el-dialog__close {
+ color: #BFBFBF;
+ }
+
+ ::v-deep .el-dialog__body {
+ padding: 30px 10px 10px 24px;
+ }
+ ::v-deep .el-dialog__title {
+ color: #39B5FE;
+ font-weight: 600;
+ }
+ ::v-deep .el-dialog__footer {
+ padding: 20px 20px 20px;
+ }
+ .submit_btn {
+ border: 0 none;
+ color: #39B5FE;
+ background: url('~@/assets/submit_bg.png') no-repeat;
+ background-size: 100% 100%;
+ &:hover {
+ color: #39B5FE;
+ }
+ }
+}
+
+// form表单样式
+.rule_form {
+ padding-right: 15px;
+ max-height: 550px;
+ overflow-y: auto;
+
+ ::v-deep .el-select {
+ width: 100%;
+ }
+ ::v-deep .el-date-editor.el-input,
+ .el-date-editor.el-input__inner {
+ width: 100%;
+ color: #fff;
+ background-color: #102351;
+ }
+ ::v-deep.el-form-item__label-wrap .el-form-item__label {
+ color: #fff;
+ }
+ .text_ranage {
+ width: 210px;
+ padding: 0px 15px;
+ margin-left: 15px;
+ background-color: #102351;
+ color: #fff;
+ }
+ ::v-deep .el-form-item__label {
+ color: #fff;
+ }
+ ::v-deep .el-form-item__content {
+ display: flex;
+ flex-direction: row;
+ .marks_text {
+ margin-left: 20px;
+ padding: 0px 10px;
+ width: 18rem;
+ border: 1px solid #deeaff;
+ background-color: #deeaff;
+
+ .el-icon-time:before {
+ color: #2c77ff;
+ padding-right: 10px;
+ }
+ }
+ .el-switch {
+ padding-top: 15px;
+ }
+ }
+ ::v-deep .el-textarea__inner {
+ font-family: Avenir, Helvetica, Arial, sans-serif;
+ background-color: #102351;
+ }
+
+ ::v-deep .el-cascader {
+ width: 100%;
+ }
+ ::v-deep .el-input-number {
+ width: 100%;
+ }
+ ::v-deep .el-input-number .el-input__inner {
+ text-align: left;
+ background-color: #102351;
+ }
+}
+
+.tabs_main {
+ margin: 0;
+ width: 100%;
+ height: 100%;
+ box-shadow: none;
+}
+
+/deep/ .el-textarea__inner{
+ background-color: transparent;
+ border: 1px solid #39B5FE;
+}
+.inspection_content {
+ display: flex;
+ flex-direction: column;
+ padding: 0 20px;
+ height: 500px;
+ overflow: auto;
+
+ .inspection_content_item {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 20px;
+ width: 100%;
+ color: #E1E3E9;
+
+ .inspection_content_item--header {
+ position: relative;
+ display: flex;
+ justify-content: space-between;
+ padding: 0 0 5px 15px;
+ border-bottom: 1px solid #39B5FE;
+
+ &::after {
+ content: "";
+ position: absolute;
+ top: 50%;
+ left: 0;
+ transform: translateY(-50%);
+ width: 3px;
+ height: 70%;
+ background: #19F7F7;
+ }
+
+ .label {
+ color: #19F7F7;
+ }
+ }
+
+ .inspection_content_item--content {
+ display: flex;
+ flex-direction: column;
+ padding: 10px 0;
+
+ .info_image {
+ margin: 10px 0;
+ width: 150px;
+ height: 140px;
+ border: 1px solid #39B5FE;
+ border-radius: 6px;
+ cursor: pointer;
+ }
+ }
+ }
+}
+
+.prop_image {
+ padding: 0 15px 20px 0;
+ width: 100%;
+ height: 450px;
+ background: transparent;
+}
+//预览按钮样式
+.preview_content{
+ padding: 24px 20px;
+ box-shadow: 2px 2px 12px 0 rgba(0, 0, 0, 0.06);
+ .preview_titles{
+ text-align: center;
+ font-size: 28px;
+ font-weight: 600;
+ color: #39B5FE;
+ }
+ .preview_times{
+ text-align: center;
+ font-size: 14px;
+ color: #999999;
+ margin-top: 15px;
+ padding-bottom: 15px;
+ border-bottom: 1px dashed #eaeaea;
+ }
+ .preview_main{
+ padding: 24px 20px 0px;
+ overflow: auto;
+ }
+}
+
+/deep/.el-dialog.is-fullscreen{
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 64%;
+ height: 92%;
+ margin-top: 40px;
+ background: #f6f6f6!important;
+}
+
+/deep/.el-input-number__decrease{
+ border-right-color: #39B5FE;
+ .el-icon-minus:before{
+ color: #19F6F8;
+ }
+}
+
+/deep/.el-input-number__increase{
+ border-left-color: #39B5FE;
+ .el-icon-plus:before{
+ color: #19F6F8;
+ }
+}
+
+/deep/.el-input-number__increase{
+ background-color: transparent;
+}
+
+/deep/.el-input-number__decrease{
+ background-color: transparent;
+}
+
+/deep/.el-textarea.is-disabled .el-textarea__inner{
+ background-color: #0D2657;
+ border-color: #39B5FE;
+}
+
+/* 滚动条统一样式修改 */
+/deep/ {
+ &::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+ }
+
+ &::-webkit-scrollbar-corner {
+ background-color: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ box-shadow: inset 0 0 5px transparent;
+ background: #39B5FE;
+ }
+
+ &::-webkit-scrollbar-track {
+ box-shadow: inset 0 0 5px transparent;
+ border-radius: 10px;
+ background: rgba(76, 188, 254, .3);
+ }
}
\ No newline at end of file
diff --git a/web/src/views/ProjectManage/SectionManage.vue b/web/src/views/ProjectManage/SectionManage.vue
index 09e277f..dbae05b 100644
--- a/web/src/views/ProjectManage/SectionManage.vue
+++ b/web/src/views/ProjectManage/SectionManage.vue
@@ -1,584 +1,637 @@
-<template>
- <!-- 工程项目管理 ==> 单位工程管理-->
- <div class="main">
- <div class="main_header">
- <div class="header_item">
- <span class="header_label">标段名称:</span>
- <el-input v-model="queryInfo.segmentName" clearable placeholder="请输入标段名称"></el-input>
- </div>
- <div class="header_item">
- <span class="header_label">项目名称:</span>
- <el-select v-model="queryInfo.proId" placeholder="请选择项目名称" clearable>
- <el-option v-for="item in optionsProject" :key="item.proId" :label="item.proName" :value="item.proId">
- </el-option>
- </el-select>
- </div>
- <div class="header_item">
- <el-button icon="el-icon-search" v-permission="'search'" @click="queryReset">查询</el-button>
- <el-button class="search_btn" icon="el-icon-plus" v-permission="'insert'" @click="addRow">新增</el-button>
- </div>
- </div>
- <div class="main_content">
- <cpnTable :table-index="true" :table-data="dataList" :table-columns="tableColumns" :page-total="total"
- :page-num.sync="queryInfo.pageNum" :page-size.sync="queryInfo.pageSize" :page-change="pageChange">
-
- <template #finished="{ row }">
- <div style="cursor: pointer;" @click="showDetail(row)">{{ row.completedQuantity }}</div>
- </template>
- </cpnTable>
- </div>
- <!-- dialog -->
- <el-dialog class="prop_dialog" v-if="isRender" :title="dialogTitle" :visible.sync="asyncVisible" width="660px"
- @close="closeForm">
- <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="auto" class="rule_form">
- <el-form-item label="项目名称:" prop="proId">
- <el-select v-model="ruleForm.proId" placeholder="请选择" @change="changeNeed">
- <el-option v-for="item in optionsProject" :key="item.proId" :label="item.proName" :value="item.proId">
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="起讫里程:" prop="mileage">
- <el-input v-model="ruleForm.mileage" clearable placeholder="请输入起讫里程"></el-input>
- </el-form-item>
- <el-form-item label="单位工程名称:" prop="unitProjectName">
- <el-input v-model="ruleForm.unitProjectName" clearable placeholder="请输入单位工程名称"></el-input>
- </el-form-item>
- <el-form-item label="需求负责人:" prop="segmentAdmin">
- <el-select v-model="ruleForm.segmentAdmin" placeholder="请选择求负责人">
- <el-option v-for="item in optionsUser" :key="item.userId" :label="item.realName" :value="item.userId">
- </el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="盾构单位:" prop="shieldEnp">
- <el-input v-model="ruleForm.shieldEnp" clearable placeholder="请输入盾构单位"></el-input>
- </el-form-item>
- <el-form-item label="开始时间:" prop="startTime">
- <el-date-picker v-model="ruleForm.startTime" value-format="yyyy-MM-dd" placeholder="请选择开始日期"></el-date-picker>
- </el-form-item>
- <el-form-item label="结束时间:" prop="endTime">
- <el-date-picker v-model="ruleForm.endTime" value-format="yyyy-MM-dd" placeholder="请选择结束日期"></el-date-picker>
- </el-form-item>
- <el-form-item label="工期:" prop="duration">
- <el-input v-model="ruleForm.duration" clearable placeholder="请输入工期"></el-input>
- </el-form-item>
- <el-form-item label="站点:" prop="station">
- <el-input v-model="ruleForm.station" clearable placeholder="请输入站点"></el-input>
- </el-form-item>
- <div class="section_needs">标段需求</div>
- <div class="section_needs_content">
- <div v-for="item in ruleForm.segmentList" :key="item.dictId" class="needs_items">
- <div class="needs_text">{{ item.dictName }}</div>
- <el-input placeholder="请输入数量" type="number" v-model="item.needNum" class="needs_num">
- <template slot="append">块</template>
- </el-input>
- </div>
- </div>
- </el-form>
- <div slot="footer">
- <el-button @click="asyncVisible = false">取 消</el-button>
- <el-button class="submit_btn" @click="onSubmit('ruleForm')">提 交</el-button>
- </div>
- </el-dialog>
- <!-- detail dialog -->
- <el-dialog class="prop_dialog" v-if="detail.isRenderDetail" title="管片数量" :visible.sync="detail.asyncVisible"
- width="1000px">
- <el-card>
- <div class="titles" v-for="item in detail.infoMap" :key="item.key">
- {{ item.name }} :
- <template v-if="item.key === 'waterproofType'">
- <span>{{ detail.infos[item.key] === 0 ? '有' : '无' }} </span>
- </template>
- <template v-else-if="item.key === 'proHas'">
- <span v-for="val in detail.infos[item.key]" :key="val.hasSteel">
- {{ val.dictName }}
- </span>
- </template>
- <template v-else>
- <span>{{ detail.infos[item.key] }}</span>
- </template>
- </div>
- </el-card>
- <cpnTable :table-index="true" :table-data="detail.tableData" :table-columns="detail.tableColumns"
- :page-total="detail.total" :page-num.sync="detail.pageNum" :page-size.sync="detail.pageSize"
- :page-change="detailPageChange">
- </cpnTable>
- </el-dialog>
- </div>
-</template>
-
-<script>
-import {throttle} from '../../plugins/public'; // 导入节流、动态切换组件尺寸方法
-import cpnTable from '@/components/element/Table'
-export default {
- data() {
- return {
- isRender: false,
- loading: false,
- asyncVisible: false,
- submitMode: '', // add update
- total: 0,
- queryInfo: {
- pageNum: 1,
- pageSize: 10,
- segmentName: '',
- proId: '',
- },
- dataList: [],
- tableColumns: [],
- optionsUser: [], //需求负责人
- optionsProject: [], // 项目名称
- ruleForm: {}, // 按钮表单
- rules: {
- proId: [{required: true, message: '请选择', trigger: 'change'}],
- mileage: [{required: true, message: '请输入', trigger: 'blur'}],
- unitProjectName: [{required: true, message: '请输入', trigger: 'blur'}],
- segmentAdmin: [{required: true, message: '请选择', trigger: 'change'}],
- shieldEnp: [{required: true, message: '请输入', trigger: 'blur'}],
- startTime: [{required: true, message: '请选择', trigger: 'change'}],
- endTime: [{required: true, message: '请选择', trigger: 'change'}],
- duration: [{required: true, message: '请输入', trigger: 'blur'}],
- station: [{required: true, message: '请输入', trigger: 'blur'}],
- },
- detail: {
- rowId: '',
- isRenderDetail: false,
- asyncVisible: false,
- pageNum: 1,
- pageSize: 10,
- total: 0,
- tableData: [],
- tableColumns: [],
- infos: [],
- infoMap: [
- {
- name: '项目名称',
- key: 'proName',
- },
- {
- name: '单位工程名称',
- key: 'createUnit',
- },
- {
- name: '外径',
- key: 'outsideDiameter',
- },
- {
- name: '內径',
- key: 'innerDiameter',
- },
- {
- name: '厚度',
- key: 'thickness',
- },
- {
- name: '环宽',
- key: 'ringWidth',
- },
- {
- name: '混凝土强度等级',
- key: 'concreteStrengthGrade',
- },
- {
- name: '抗渗等级',
- key: 'impermeabilityLevel',
- },
- {
- name: '配筋型号',
- key: 'proHas',
- },
- {
- name: '有无外弧面防水',
- key: 'waterproofType',
- }
- ]
- }
- }
- },
- components: {
- cpnTable
- },
- computed: {
- isUpdate() {
- return this.submitMode === 'update'
- },
- dialogTitle() {
- return this.isUpdate ? '修改新增单位工程' : '新增单位工程'
- },
- },
- created() {
- this.setFormProps()
- this.setTableColumn()
- this.getLists()
- this.getAllProjects()
- this.getAllPersons()
- // this.getAllBlocks() // 暂时没用,先屏蔽
- },
- methods: {
- // 获取table列表数据
- getLists() {
- this.loading = true
- let params = this.queryInfo
- this.$api.Engineer.searchSegment(params).then(res => {
- if (res.statusMsg === 'ok') {
- this.total = res.data.total
- this.dataList = res.data.list
- }
- this.loading = false
- })
- },
- //获得所有人员
- getAllPersons() {
- this.$api.Engineer.getPersonsList({}).then(res => {
- if (res.statusMsg === 'ok') {
- this.optionsUser = res.data
- } else {
- this.$message.warning('人员名称获取失败')
- }
- })
- },
- //获得所有项目名称
- getAllProjects() {
- let obj = {
- pageNum: 1,
- pageSize: 100000000
- }
- this.$api.Engineer.searchProjects(obj).then(res => {
- if (res.statusMsg === 'ok') {
- this.optionsProject = res.data.list
- } else {
- this.$message.warning('项目名称获取失败')
- }
- })
- },
- //字典里获取所有标段块号
- getAllBlocks() {
- let params = {
- pageNum: 1,
- pageSize: 100000000
- }
- this.$api.Dictionary.searchDictionary(params).then(res => {
- if (res.statusMsg === 'ok') {
- const segmentList = []
- res.data.list.forEach(item => {
- if (item.dictType === '5') {
- segmentList.push({
- dictName: item.dictName,
- needType: item.dictId,
- needNum: 0,
- segmentId: ''
- })
- }
- })
- this.ruleForm.segmentList = segmentList
- } else {
- this.$message.warning('标段获取失败')
- }
- })
- },
- // 已完成 table信息
- getDetailLists() {
- let detailData = this.detail
- this.$api.DuctpiecePLM.searchDuctpiecePLMList({
- segmentId: detailData.rowId,
- pageNum: detailData.pageNum,
- pageSize: detailData.pageSize
- }).then(res => {
- if (res.success) {
- detailData.total = res.data.total
- detailData.tableData = res.data.list
- }
- })
- },
- // 已完成 title信息
- getDetailInfos(id) {
- this.$api.Engineer.detailsProjects({proId: id}).then(res => {
- if (res.success) {
- this.detail.infos = res.data
- }
- })
- },
- // 初始化 ruleform
- setFormProps(options = {}) {
- let _form = {
- proId: '', // 项目名称id
- mileage: '', // 起讫里程
- unitProjectName: '', // 单位工程名称
- segmentAdmin: '', // 需求负责人
- shieldEnp: '', // 盾构单位
- startTime: null, // 开始时间
- endTime: null, // 结束时间
- duration: '', // 工期
- station: '', // 站点
- segmentList: [], // 标段需求
- }
- this.ruleForm = Object.keys(options).length ? options : _form
- },
- // 初始化 table 配置
- setTableColumn() {
- this.tableColumns = [
- {index: true},
- {slot: "finished", name: "已完成(块)"},
- {name: "项目名称", key: "proName", width: 160},
- {name: "起讫里程", key: "mileage"},
- {name: "单位工程名称", key: "unitProjectName"},
- {name: "盾构单位", key: "shieldEnp"},
- {name: "开始时间", key: "startTime", width: 100},
- {name: "结束时间", key: "endTime", width: 100},
- {name: "工期", key: "duration"},
- {name: "站点", key: "station"},
- {name: "负责人", key: "realName"},
- {
- operation: true, name: "操作", width: 140, value: [
- {name: "修改", class: "table_btn", permission: "update", handleRow: this.updateRow},
- {name: "删除", class: "delete_btn", permission: "delete", handleRow: this.deleteRow},
- ]
- },
- ]
- this.detail.tableColumns = [
- {index: true},
- {name: "环号", key: "ringNum"},
- {name: "管片编号", key: "pipeNum", width: 140},
- {name: "转向", key: "turnName", width: 106},
- {name: "配筋", key: "reinforcementName"},
- {name: "注浆孔", key: "groutingHolesName"},
- {name: "块号", key: "blockNumName"},
- {name: "模具", key: "mouldNum"},
- {name: "入模时间", key: "intoModTime", width: 136},
- {name: "浇筑时间", key: "pouringTime"},
- {name: "质检时间", key: "checkTime", width: 136},
- {name: "生产班组", key: "groupName"},
- {name: "项目", key: "proName", width: 240},
- {name: "质量标注", key: "checkResultStr"},
- ]
- },
- // 重置表单
- resetForm(formName) {
- this.$refs[formName].resetFields()
- },
- // 显示表单
- showForm() {
- !this.isRender && (this.isRender = true)
- this.asyncVisible = true
- },
- // 隐藏表单
- closeForm() {
- this.asyncVisible = false
- this.resetForm('ruleForm')
- this.setFormProps()
- },
- // 查询按钮列表信息
- queryReset() {
- this.queryInfo.pageNum = 1
- this.queryInfo.pageSize = 10
- this.getLists()
- },
- // 添加数据
- addRow() {
- this.submitMode = 'add'
- this.showForm()
- },
- // 更新数据
- async updateRow(row) {
- this.submitMode = 'update'
- this.showForm()
- const segmentList = await this.getProjectBlocks(row.segmentId)
- Object.keys(this.ruleForm).forEach(item => {
- if (row.hasOwnProperty.call(row, item)) {
- this.ruleForm[item] = row[item]
- }
- })
- this.ruleForm.segmentId = row.segmentId
- this.ruleForm.segmentList = segmentList
- },
- // 删除数据
- deleteRow(row) {
- this.$confirm("该操作将删除该信息,是否继续删除?", "提示", {
- confirmButtonText: "确定",
- cancelButtonText: "取消",
- type: "warning"
- }).then(() => {
- this.$api.Engineer.deleteSegment({segmentId: row.segmentId}).then(res => {
- if (res.statusMsg === 'ok') {
- this.queryReset();
- this.$message.success("删除成功!")
- } else {
- this.$message.warning(res.statusMsg)
- }
- })
- }).catch(() => {
- this.$message.warning("您已取消")
- })
- },
- //获取项目标段
- getProjectBlocks(id) {
- return new Promise(resolve => {
- this.$api.Engineer.detailsSegment({segmentId: id}).then(res => {
- let outData = []
- if (res.statusMsg === 'ok') {
- outData.push(...res.data.segmentNeeds)
- }
- resolve(outData)
- })
- })
- },
- //通过不同的项目展示不同的标段需求
- changeNeed(val) {
- this.$api.Reinforce.searchProjectBears({proId: val}).then(res => {
- if (res.statusMsg === 'ok') {
- const segmentList = []
- res.data.blokDtos.forEach(item => {
- segmentList.push({
- dictName: item.blockName,
- needType: item.blockNum,
- needNum: 0,
- segmentId: ''
- })
- })
- this.ruleForm.segmentList = segmentList
- } else {
- this.$message.warning('标段获取失败')
- }
- })
- },
- // 提交表单
- onSubmit: throttle(function () {
- this.$refs.ruleForm.validate(valid => {
- if (!valid) return
- const params = this.ruleForm
- if (this.isUpdate) {
- // 更新
- this.$api.Engineer.updateSegment(params).then((res) => {
- if (res.statusMsg === 'ok') {
- this.closeForm()
- this.getLists()
- this.$message.success('更新成功!')
- } else {
- this.$message.warning(res.statusMsg)
- }
- })
- } else {
- // 添加
- this.$api.Engineer.insertSegment(params).then((res) => {
- if (res.statusMsg === 'ok') {
- this.closeForm()
- this.getLists()
- this.$message.success('添加成功!')
- } else {
- this.$message.warning(res.statusMsg)
- }
- })
- }
- })
- }, 1000),
- showDetail(row) {
- let detailData = this.detail
- !detailData.isRenderDetail && (detailData.isRenderDetail = true)
- detailData.asyncVisible = true
- detailData.rowId = row.segmentId
- detailData.total = 0
- detailData.tableData = []
- detailData.infos = []
- this.getDetailInfos(row.proId)
- this.getDetailLists()
- },
- // 分页改变
- pageChange() {
- this.getLists();
- },
- // 已完成の分页改变
- detailPageChange() {
- this.getDetailLists();
- },
- }
-}
-</script>
-
-<style lang="scss" scoped>
-@import '../../style/layout-main.scss';
-
-/deep/ {
- &::-webkit-scrollbar {
- width: 8px;
- height: 8px;
- }
-
- &::-webkit-scrollbar-corner {
- background-color: transparent;
- }
-
- &::-webkit-scrollbar-thumb {
- border-radius: 10px;
- box-shadow: inset 0 0 5px transparent;
- background: #39B5FE;
- }
-
- &::-webkit-scrollbar-track {
- box-shadow: inset 0 0 5px transparent;
- border-radius: 10px;
- background: rgba(76, 188, 254, .3);
- }
-}
-
-.el-card {
- margin-bottom: 20px;
- border: none;
- color: #fff;
- background: rgba(9, 64, 101, 1);
-
- .titles {
- float: left;
- width: 25%;
- min-height: 36px;
- padding-right: 6px;
- margin-bottom: 6px;
- line-height: 18px;
- box-sizing: border-box;
- }
-
- span {
- color: #39B5FE;
- }
-}
-
-.section_needs {
- position: relative;
- color: #18F5F7;
- padding: 20px 20px 10px 15px;
- border-bottom: 1px solid #1949A3;
-
- &::before {
- position: absolute;
- content: "";
- width: 2px;
- height: 20px;
- background-color: #18F5F7;
- top: 20px;
- left: 5px;
- }
-}
-
-.section_needs_content {
- display: flex;
- flex-wrap: wrap;
-
- .needs_items {
- max-width: 190px;
- min-width: 142px;
- padding: 15px;
- display: flex;
-
- .needs_text {
- // width: 50px;
- flex: none;
- align-self: center;
- text-align: center;
- padding-right: 15px;
- color: #E1E3E9;
- }
-
- .needs_num {
- align-self: center;
- }
- }
-}
+<template>
+ <!-- 工程项目管理 ==> 单位工程管理-->
+ <div class="main">
+ <div class="main_header">
+ <div class="header_item">
+ <span class="header_label">标段名称:</span>
+ <el-input v-model="queryInfo.segmentName" clearable placeholder="请输入标段名称"></el-input>
+ </div>
+ <div class="header_item">
+ <span class="header_label">项目名称:</span>
+ <el-select v-model="queryInfo.proId" placeholder="请选择项目名称" clearable>
+ <el-option v-for="item in optionsProject" :key="item.proId" :label="item.proName" :value="item.proId">
+ </el-option>
+ </el-select>
+ </div>
+ <div class="header_item">
+ <el-button icon="el-icon-search" v-permission="'search'" @click="queryReset">查询</el-button>
+ <el-button class="search_btn" icon="el-icon-plus" v-permission="'insert'" @click="addRow">新增</el-button>
+ </div>
+ </div>
+ <div class="main_content">
+ <cpnTable :table-index="true" :table-loading="loading" :table-data="dataList" :table-columns="tableColumns"
+ :page-total="total" :page-num.sync="queryInfo.pageNum" :page-size.sync="queryInfo.pageSize"
+ :page-change="pageChange">
+
+ <template #finished="{ row }">
+ <div style="cursor: pointer;" @click="showDetail(row)">{{ row.completedQuantity }}</div>
+ </template>
+ </cpnTable>
+ </div>
+ <!-- dialog -->
+ <el-dialog class="prop_dialog" v-if="isRender" :title="dialogTitle" :visible.sync="asyncVisible" width="660px"
+ @close="closeForm">
+
+ <cpnForm :form-config="formConfig"></cpnForm>
+
+ <el-form ref="ruleForm" :model="ruleForm" :rules="rules" label-width="auto" class="rule_form">
+ <el-form-item label="项目名称:" prop="proId">
+ <el-select v-model="ruleForm.proId" placeholder="请选择" @change="changeNeed">
+ <el-option v-for="item in optionsProject" :key="item.proId" :label="item.proName" :value="item.proId">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="起讫里程:" prop="mileage">
+ <el-input v-model="ruleForm.mileage" clearable placeholder="请输入起讫里程"></el-input>
+ </el-form-item>
+ <el-form-item label="单位工程名称:" prop="unitProjectName">
+ <el-input v-model="ruleForm.unitProjectName" clearable placeholder="请输入单位工程名称"></el-input>
+ </el-form-item>
+ <el-form-item label="需求负责人:" prop="segmentAdmin">
+ <el-select v-model="ruleForm.segmentAdmin" placeholder="请选择求负责人">
+ <el-option v-for="item in optionsUser" :key="item.userId" :label="item.realName" :value="item.userId">
+ </el-option>
+ </el-select>
+ </el-form-item>
+ <el-form-item label="盾构单位:" prop="shieldEnp">
+ <el-input v-model="ruleForm.shieldEnp" clearable placeholder="请输入盾构单位"></el-input>
+ </el-form-item>
+ <el-form-item label="开始时间:" prop="startTime">
+ <el-date-picker v-model="ruleForm.startTime" value-format="yyyy-MM-dd" placeholder="请选择开始日期"></el-date-picker>
+ </el-form-item>
+ <el-form-item label="结束时间:" prop="endTime">
+ <el-date-picker v-model="ruleForm.endTime" value-format="yyyy-MM-dd" placeholder="请选择结束日期"></el-date-picker>
+ </el-form-item>
+ <el-form-item label="工期:" prop="duration">
+ <el-input v-model="ruleForm.duration" clearable placeholder="请输入工期"></el-input>
+ </el-form-item>
+ <el-form-item label="站点:" prop="station">
+ <el-input v-model="ruleForm.station" clearable placeholder="请输入站点"></el-input>
+ </el-form-item>
+ <div class="section_needs">标段需求</div>
+ <div class="section_needs_content">
+ <div v-for="item in ruleForm.segmentList" :key="item.dictId" class="needs_items">
+ <div class="needs_text">{{ item.dictName }}</div>
+ <el-input placeholder="请输入数量" type="number" v-model="item.needNum" class="needs_num">
+ <template slot="append">块</template>
+ </el-input>
+ </div>
+ </div>
+ </el-form>
+ <div slot="footer">
+ <el-button @click="asyncVisible = false">取 消</el-button>
+ <el-button class="submit_btn" @click="onSubmit('ruleForm')">提 交</el-button>
+ </div>
+ </el-dialog>
+ <!-- detail dialog -->
+ <el-dialog class="prop_dialog" v-if="detail.isRenderDetail" title="管片数量" :visible.sync="detail.asyncVisible"
+ width="1000px">
+ <el-card>
+ <div class="titles" v-for="item in detail.infoMap" :key="item.key">
+ {{ item.name }} :
+ <template v-if="item.key === 'waterproofType'">
+ <span>{{ detail.infos[item.key] === 0 ? '有' : '无' }} </span>
+ </template>
+ <template v-else-if="item.key === 'proHas'">
+ <span v-for="val in detail.infos[item.key]" :key="val.hasSteel">
+ {{ val.dictName }}
+ </span>
+ </template>
+ <template v-else>
+ <span>{{ detail.infos[item.key] }}</span>
+ </template>
+ </div>
+ </el-card>
+ <cpnTable :table-index="true" :table-data="detail.tableData" :table-columns="detail.tableColumns"
+ :page-total="detail.total" :page-num.sync="detail.pageNum" :page-size.sync="detail.pageSize"
+ :page-change="detailPageChange">
+ </cpnTable>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import {throttle} from '../../plugins/public'; // 导入节流、动态切换组件尺寸方法
+import cpnTable from '@/components/element/Table'
+import cpnForm from '@/components/element/Form'
+export default {
+ data() {
+ return {
+ isRender: false,
+ loading: false,
+ asyncVisible: false,
+ submitMode: '', // add update
+ total: 0,
+ queryInfo: {
+ pageNum: 1,
+ pageSize: 10,
+ segmentName: '',
+ proId: '',
+ },
+ dataList: [],
+ tableColumns: [],
+ optionsUser: [], //需求负责人
+ optionsProject: [], // 项目名称
+ ruleForm: {}, // 按钮表单
+ rules: {
+ proId: [{required: true, message: '请选择', trigger: 'change'}],
+ mileage: [{required: true, message: '请输入', trigger: 'blur'}],
+ unitProjectName: [{required: true, message: '请输入', trigger: 'blur'}],
+ segmentAdmin: [{required: true, message: '请选择', trigger: 'change'}],
+ shieldEnp: [{required: true, message: '请输入', trigger: 'blur'}],
+ startTime: [{required: true, message: '请选择', trigger: 'change'}],
+ endTime: [{required: true, message: '请选择', trigger: 'change'}],
+ duration: [{required: true, message: '请输入', trigger: 'blur'}],
+ station: [{required: true, message: '请输入', trigger: 'blur'}],
+ },
+ detail: {
+ rowId: '',
+ isRenderDetail: false,
+ asyncVisible: false,
+ pageNum: 1,
+ pageSize: 10,
+ total: 0,
+ tableData: [],
+ tableColumns: [],
+ infos: [],
+ infoMap: [
+ {
+ name: '项目名称',
+ key: 'proName',
+ },
+ {
+ name: '单位工程名称',
+ key: 'createUnit',
+ },
+ {
+ name: '外径',
+ key: 'outsideDiameter',
+ },
+ {
+ name: '內径',
+ key: 'innerDiameter',
+ },
+ {
+ name: '厚度',
+ key: 'thickness',
+ },
+ {
+ name: '环宽',
+ key: 'ringWidth',
+ },
+ {
+ name: '混凝土强度等级',
+ key: 'concreteStrengthGrade',
+ },
+ {
+ name: '抗渗等级',
+ key: 'impermeabilityLevel',
+ },
+ {
+ name: '配筋型号',
+ key: 'proHas',
+ },
+ {
+ name: '有无外弧面防水',
+ key: 'waterproofType',
+ }
+ ]
+ },
+
+ formConfig: {
+ formModels: {
+ proId: '', // 项目名称id
+ mileage: '', // 起讫里程
+ unitProjectName: '', // 单位工程名称
+ segmentAdmin: '', // 需求负责人
+ shieldEnp: '', // 盾构单位
+ startTime: null, // 开始时间
+ endTime: null, // 结束时间
+ duration: '', // 工期
+ station: '', // 站点
+ segmentList: [], // 标段需求
+ },
+ formItems: [
+ {
+ type: 'input', label: '用户id'
+ },
+ {
+ type: 'input', label: '用户名'
+ },
+
+ {
+ type: 'input', label: '真实姓名'
+ },
+ {
+ type: 'input', label: '电话号码'
+ },
+ {
+ type: 'select', label: '用户状态', options: [
+ {label: '禁用', value: 0},
+ {label: '启用', value: 1}
+ ]
+ },
+ {
+ type: 'datepicker', label: '创建时间', otherOptions: {
+ startPlaceholder: '开始时间',
+ endPlaceholder: '结束时间',
+ type: 'daterange',
+ 'unlink-panels': true
+ }
+ }
+ ],
+ itemColLayout: {
+ span: 8
+ }
+ }
+ }
+ },
+ components: {
+ cpnTable,
+ cpnForm
+ },
+ computed: {
+ isUpdate() {
+ return this.submitMode === 'update'
+ },
+ dialogTitle() {
+ return this.isUpdate ? '修改新增单位工程' : '新增单位工程'
+ },
+ },
+ created() {
+ this.setFormProps()
+ this.setTableColumn()
+ this.getLists()
+ this.getAllProjects()
+ this.getAllPersons()
+ // this.getAllBlocks() // 暂时没用,先屏蔽
+ },
+ methods: {
+ // 获取table列表数据
+ getLists() {
+ this.loading = true
+ let params = this.queryInfo
+ this.$api.Engineer.searchSegment(params).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.total = res.data.total
+ this.dataList = res.data.list
+ }
+ this.loading = false
+ })
+ },
+ //获得所有人员
+ getAllPersons() {
+ this.$api.Engineer.getPersonsList({}).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.optionsUser = res.data
+ } else {
+ this.$message.warning('人员名称获取失败')
+ }
+ })
+ },
+ //获得所有项目名称
+ getAllProjects() {
+ let obj = {
+ pageNum: 1,
+ pageSize: 100000000
+ }
+ this.$api.Engineer.searchProjects(obj).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.optionsProject = res.data.list
+ } else {
+ this.$message.warning('项目名称获取失败')
+ }
+ })
+ },
+ //字典里获取所有标段块号
+ getAllBlocks() {
+ let params = {
+ pageNum: 1,
+ pageSize: 100000000
+ }
+ this.$api.Dictionary.searchDictionary(params).then(res => {
+ if (res.statusMsg === 'ok') {
+ const segmentList = []
+ res.data.list.forEach(item => {
+ if (item.dictType === '5') {
+ segmentList.push({
+ dictName: item.dictName,
+ needType: item.dictId,
+ needNum: 0,
+ segmentId: ''
+ })
+ }
+ })
+ this.ruleForm.segmentList = segmentList
+ } else {
+ this.$message.warning('标段获取失败')
+ }
+ })
+ },
+ // 已完成 table信息
+ getDetailLists() {
+ let detailData = this.detail
+ this.$api.DuctpiecePLM.searchDuctpiecePLMList({
+ segmentId: detailData.rowId,
+ pageNum: detailData.pageNum,
+ pageSize: detailData.pageSize
+ }).then(res => {
+ if (res.success) {
+ detailData.total = res.data.total
+ detailData.tableData = res.data.list
+ }
+ })
+ },
+ // 已完成 title信息
+ getDetailInfos(id) {
+ this.$api.Engineer.detailsProjects({proId: id}).then(res => {
+ if (res.success) {
+ this.detail.infos = res.data
+ }
+ })
+ },
+ // 初始化 ruleform
+ setFormProps(options = {}) {
+ let _form = {
+ proId: '', // 项目名称id
+ mileage: '', // 起讫里程
+ unitProjectName: '', // 单位工程名称
+ segmentAdmin: '', // 需求负责人
+ shieldEnp: '', // 盾构单位
+ startTime: null, // 开始时间
+ endTime: null, // 结束时间
+ duration: '', // 工期
+ station: '', // 站点
+ segmentList: [], // 标段需求
+ }
+ this.ruleForm = Object.keys(options).length ? options : _form
+ },
+ // 初始化 table 配置
+ setTableColumn() {
+ this.tableColumns = [
+ {index: true},
+ {slot: "finished", name: "已完成(块)"},
+ {name: "项目名称", key: "proName", width: 160},
+ {name: "起讫里程", key: "mileage"},
+ {name: "单位工程名称", key: "unitProjectName"},
+ {name: "盾构单位", key: "shieldEnp"},
+ {name: "开始时间", key: "startTime", width: 100},
+ {name: "结束时间", key: "endTime", width: 100},
+ {name: "工期", key: "duration"},
+ {name: "站点", key: "station"},
+ {name: "负责人", key: "realName"},
+ {
+ operation: true, name: "操作", width: 140, value: [
+ {name: "修改", class: "table_btn", permission: "update", handleRow: this.updateRow},
+ {name: "删除", class: "delete_btn", permission: "delete", handleRow: this.deleteRow},
+ ]
+ },
+ ]
+ this.detail.tableColumns = [
+ {index: true},
+ {name: "环号", key: "ringNum"},
+ {name: "管片编号", key: "pipeNum", width: 140},
+ {name: "转向", key: "turnName", width: 106},
+ {name: "配筋", key: "reinforcementName"},
+ {name: "注浆孔", key: "groutingHolesName"},
+ {name: "块号", key: "blockNumName"},
+ {name: "模具", key: "mouldNum"},
+ {name: "入模时间", key: "intoModTime", width: 136},
+ {name: "浇筑时间", key: "pouringTime"},
+ {name: "质检时间", key: "checkTime", width: 136},
+ {name: "生产班组", key: "groupName"},
+ {name: "项目", key: "proName", width: 240},
+ {name: "质量标注", key: "checkResultStr"},
+ ]
+ },
+ // 重置表单
+ resetForm(formName) {
+ this.$refs[formName].resetFields()
+ },
+ // 显示表单
+ showForm() {
+ !this.isRender && (this.isRender = true)
+ this.asyncVisible = true
+ },
+ // 隐藏表单
+ closeForm() {
+ this.asyncVisible = false
+ this.resetForm('ruleForm')
+ this.setFormProps()
+ },
+ // 查询按钮列表信息
+ queryReset() {
+ this.queryInfo.pageNum = 1
+ this.queryInfo.pageSize = 10
+ this.getLists()
+ },
+ // 添加数据
+ addRow() {
+ this.submitMode = 'add'
+ this.showForm()
+ },
+ // 更新数据
+ async updateRow(row) {
+ this.submitMode = 'update'
+ this.showForm()
+ const segmentList = await this.getProjectBlocks(row.segmentId)
+ Object.keys(this.ruleForm).forEach(item => {
+ if (row.hasOwnProperty.call(row, item)) {
+ this.ruleForm[item] = row[item]
+ }
+ })
+ this.ruleForm.segmentId = row.segmentId
+ this.ruleForm.segmentList = segmentList
+ },
+ // 删除数据
+ deleteRow(row) {
+ this.$confirm("该操作将删除该信息,是否继续删除?", "提示", {
+ confirmButtonText: "确定",
+ cancelButtonText: "取消",
+ type: "warning"
+ }).then(() => {
+ this.$api.Engineer.deleteSegment({segmentId: row.segmentId}).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.queryReset();
+ this.$message.success("删除成功!")
+ } else {
+ this.$message.warning(res.statusMsg)
+ }
+ })
+ }).catch(() => {
+ this.$message.warning("您已取消")
+ })
+ },
+ //获取项目标段
+ getProjectBlocks(id) {
+ return new Promise(resolve => {
+ this.$api.Engineer.detailsSegment({segmentId: id}).then(res => {
+ let outData = []
+ if (res.statusMsg === 'ok') {
+ outData.push(...res.data.segmentNeeds)
+ }
+ resolve(outData)
+ })
+ })
+ },
+ //通过不同的项目展示不同的标段需求
+ changeNeed(val) {
+ this.$api.Reinforce.searchProjectBears({proId: val}).then(res => {
+ if (res.statusMsg === 'ok') {
+ const segmentList = []
+ res.data.blokDtos.forEach(item => {
+ segmentList.push({
+ dictName: item.blockName,
+ needType: item.blockNum,
+ needNum: 0,
+ segmentId: ''
+ })
+ })
+ this.ruleForm.segmentList = segmentList
+ } else {
+ this.$message.warning('标段获取失败')
+ }
+ })
+ },
+ // 提交表单
+ onSubmit: throttle(function () {
+ this.$refs.ruleForm.validate(valid => {
+ if (!valid) return
+ const params = this.ruleForm
+ if (this.isUpdate) {
+ // 更新
+ this.$api.Engineer.updateSegment(params).then((res) => {
+ if (res.statusMsg === 'ok') {
+ this.closeForm()
+ this.getLists()
+ this.$message.success('更新成功!')
+ } else {
+ this.$message.warning(res.statusMsg)
+ }
+ })
+ } else {
+ // 添加
+ this.$api.Engineer.insertSegment(params).then((res) => {
+ if (res.statusMsg === 'ok') {
+ this.closeForm()
+ this.getLists()
+ this.$message.success('添加成功!')
+ } else {
+ this.$message.warning(res.statusMsg)
+ }
+ })
+ }
+ })
+ }, 1000),
+ showDetail(row) {
+ let detailData = this.detail
+ !detailData.isRenderDetail && (detailData.isRenderDetail = true)
+ detailData.asyncVisible = true
+ detailData.rowId = row.segmentId
+ detailData.total = 0
+ detailData.tableData = []
+ detailData.infos = []
+ this.getDetailInfos(row.proId)
+ this.getDetailLists()
+ },
+ // 分页改变
+ pageChange() {
+ this.getLists();
+ },
+ // 已完成の分页改变
+ detailPageChange() {
+ this.getDetailLists();
+ },
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '../../style/layout-main.scss';
+
+/deep/ {
+ &::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+ }
+
+ &::-webkit-scrollbar-corner {
+ background-color: transparent;
+ }
+
+ &::-webkit-scrollbar-thumb {
+ border-radius: 10px;
+ box-shadow: inset 0 0 5px transparent;
+ background: #39B5FE;
+ }
+
+ &::-webkit-scrollbar-track {
+ box-shadow: inset 0 0 5px transparent;
+ border-radius: 10px;
+ background: rgba(76, 188, 254, .3);
+ }
+}
+
+.el-card {
+ margin-bottom: 20px;
+ border: none;
+ color: #fff;
+ background: rgba(9, 64, 101, 1);
+
+ .titles {
+ float: left;
+ width: 25%;
+ min-height: 36px;
+ padding-right: 6px;
+ margin-bottom: 6px;
+ line-height: 18px;
+ box-sizing: border-box;
+ }
+
+ span {
+ color: #39B5FE;
+ }
+}
+
+.section_needs {
+ position: relative;
+ color: #18F5F7;
+ padding: 20px 20px 10px 15px;
+ border-bottom: 1px solid #1949A3;
+
+ &::before {
+ position: absolute;
+ content: "";
+ width: 2px;
+ height: 20px;
+ background-color: #18F5F7;
+ top: 20px;
+ left: 5px;
+ }
+}
+
+.section_needs_content {
+ display: flex;
+ flex-wrap: wrap;
+
+ .needs_items {
+ max-width: 190px;
+ min-width: 142px;
+ padding: 15px;
+ display: flex;
+
+ .needs_text {
+ // width: 50px;
+ flex: none;
+ align-self: center;
+ text-align: center;
+ padding-right: 15px;
+ color: #E1E3E9;
+ }
+
+ .needs_num {
+ align-self: center;
+ }
+ }
+}
</style>
\ No newline at end of file
diff --git a/web/src/views/SecureManage/SmartHelmet/AlarmRecord.vue b/web/src/views/SecureManage/SmartHelmet/AlarmRecord.vue
index 668cc49..9c82ec0 100644
--- a/web/src/views/SecureManage/SmartHelmet/AlarmRecord.vue
+++ b/web/src/views/SecureManage/SmartHelmet/AlarmRecord.vue
@@ -1,3 +1,725 @@
-<template>
- <div>报警记录</div>
-</template>
\ No newline at end of file
+<template>
+ <!-- 安全管理 ==> 智能安全帽 => 报警记录 -->
+ <div class="main">
+ <!-- main_left -->
+ <div class="main_left" v-show="!isRenderDetail">
+ <div class="main_left_search">
+ <div class="search_item">
+ <span>姓名:</span>
+ <el-input size="mini" v-model="queryInfo.userName" placeholder="请输入姓名" clearable></el-input>
+ </div>
+ <div class="search_item">
+ <span>设备编号:</span>
+ <el-input size="mini" v-model="queryInfo.deviceNum" placeholder="请输入设备编号" clearable></el-input>
+ <el-button icon="el-icon-search" @click="queryTable">查询</el-button>
+ </div>
+ </div>
+ <div class="main_left_table">
+ <cpnTable :table-loading="loading" :table-data="dataList" :table-columns="tableColumns">
+ </cpnTable>
+ </div>
+ </div>
+ <!-- main_right -->
+ <div class="main_right" v-show="!isRenderDetail">
+ <div class="echart_options">
+ <el-radio-group v-model="chart.radioGroupVal" @change="loadChart">
+ <el-radio-button label="7">近7天报警数</el-radio-button>
+ <el-radio-button label="31">近31天报警数</el-radio-button>
+ </el-radio-group>
+ </div>
+ <div ref="echart_bar" class="echart_bar"></div>
+ <div class="echart_drop">
+ <div ref="echart_drop_1" :class="{ show: chart.isShowDrop1, hide: !chart.isShowDrop1 }"></div>
+ <div ref="echart_drop_2" :class="{ show: chart.isShowDrop2, hide: !chart.isShowDrop2 }"></div>
+ </div>
+ </div>
+ <!-- detail -->
+ <div class="detail" v-if="isRenderDetail">
+ <div class="detail_option">
+ <div class="search_item">
+ <span>日期:</span>
+ <el-date-picker class="elDatePicker" type="daterange" v-model="detail.date" value-format="yyyy-MM-dd"
+ start-placeholder="开始日期" end-placeholder="结束日期" clearable></el-date-picker>
+ </div>
+ <el-button icon="el-icon-search" @click="queryDetail">查询</el-button>
+ <el-button style="float:right" @click="hideDetail">返回</el-button>
+ </div>
+ <div class="detail_botbox">
+ <div class="detail_table">
+ <cpnTable :table-data="detail.dataList" :table-columns="detail.tableColumns">
+ </cpnTable>
+ </div>
+ <div class="detail_map">
+ <div id="container"></div>
+ <div class="detail_map_info_l" v-show="detail.isShowInfo">
+ <h2>静默报警</h2>
+ <p>原因: <span>{{ detail.info.cause }}</span></p>
+ <p>姓名: <span>{{ detail.info.name }}</span></p>
+ <p>设备: <span>{{ detail.info.device }}</span></p>
+ <p>位置: <span>{{ detail.info.position }}</span></p>
+ <p>时间: <span>{{ detail.info.time }}</span></p>
+ <el-button style="float: right;" @click="() => { detail.isShowInfo = false }">确定</el-button>
+ </div>
+ <div class="detail_map_info_r" v-show="detail.isShowInfo">
+ <h2>报警设备信息</h2>
+ <p>姓名: <span>{{ detail.info.name }}</span></p>
+ <p>时间: <span>{{ detail.info.time }}</span></p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import AMapLoader from '@amap/amap-jsapi-loader';
+import cpnTable from '@/components/element/Table'
+import 'echarts-liquidfill' // 水滴图形
+export default {
+ data() {
+ return {
+ loading: false,
+ isRenderDetail: false, // 是否查看轨迹地图
+ queryInfo: {
+ pageNum: 1,
+ pageSize: 9999,
+ userName: '',
+ deviceNum: '',
+ },
+ dataList: [],
+ tableColumns: [],
+ userId: '', // 用户id
+ userName: '', // 用户名称
+ deviceNum: '', // 设备编号
+ // 图表数据
+ chart: {
+ date: '',
+ radioGroupVal: '7', // (7 31)默认近7天
+ isShowDrop1: false,
+ isShowDrop2: false,
+ chartInstanceLine: null, // 柱状图实例
+ chartInstanceDrop1: null, // 水滴图实例
+ chartInstanceDrop2: null,
+ },
+ detail: { // 详情
+ date: [], // 日期查询
+ dataList: [],
+ tableColumns: [],
+ isShowInfo: false,
+ // 报警信息
+ info: {
+ cause: '',
+ name: '',
+ device: '',
+ position: '',
+ time: '',
+ },
+ // 报警类型原因
+ sosTypes: {
+ 1: '长时间静止'
+ },
+ },
+ $http: '', // 接口api路径
+ }
+ },
+ components: {
+ cpnTable
+ },
+ created() {
+ // 添加密钥,获取高德地址使用
+ window._AMapSecurityConfig = {
+ securityJsCode: "aa90b00e27025d1f57286675cc8b232e",
+ }
+ this.$http = this.$api.Safety.SmartHelmet.warning
+ this.setTableColumn()
+ this.getLists()
+ },
+ mounted() {
+ this.initChart()
+ window.addEventListener("resize", this.screenAdapter)
+ },
+ beforeDestroy() {
+ this.clearMap()
+ this.clearChart()
+ window.removeEventListener("resize", this.screenAdapter)
+ },
+ methods: {
+ setTableColumn() {
+ this.tableColumns = [
+ {name: "用户ID", key: "userId"},
+ {name: "姓名", key: "userName"},
+ {name: "设备编号", key: "deviceNum"},
+ {
+ operation: true, name: "操作", width: 140, value: [
+ {name: "查看", class: "table_btn", handleRow: this.warchRow},
+ {name: "详情", class: "table_btn", handleRow: this.detailRow},
+ ]
+ },
+ ]
+ },
+ // 获取报警信息
+ async getWarning() {
+ let out = {}
+ const params = {
+ userId: this.userId,
+ strTime: this.chart.date?.[0],
+ endTime: this.chart.date?.[1],
+ }
+ const {data, statusMsg} = await this.$http.getWarning(params)
+ if (statusMsg === 'ok') {
+ out = data
+ }
+ return out
+ },
+ // 获取table数据
+ getLists() {
+ this.loading = true
+ this.$api.Safety.SmartHelmet.getLists(this.queryInfo).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.dataList = res.data.list
+ }
+ this.loading = false
+ })
+ },
+ // table-详情按钮
+ detailRow(row) {
+ this.userId = row.userId
+ this.deviceNum = row.deviceNum
+ this.renderDetail()
+ },
+ // table-查看按钮
+ warchRow(row) {
+ if (this.userId === row.userId) return
+ this.userId = row.userId
+ this.userName = row.userName
+ console.log(row)
+ this.chart.isShowDrop1 = false
+ this.chart.isShowDrop2 = false
+ this.loadChart()
+ },
+ // 加载图表
+ loadChart() {
+ this.changeDay()
+ this.showDrop()
+ this.renderChart()
+ },
+ // 水滴图表根据 7/31 切换显示
+ showDrop() {
+ if (this.chart.radioGroupVal === '7') {
+ this.chart.isShowDrop1 = true
+ } else if (this.chart.radioGroupVal === '31') {
+ this.chart.isShowDrop2 = true
+ }
+ },
+ // 近 7/31 天切换
+ changeDay() {
+ const nowDate = new Date().format()
+ const beforeDate7 = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).format()
+ const beforeDate31 = new Date(Date.now() - 31 * 24 * 60 * 60 * 1000).format()
+ const beforeDate = this.chart.radioGroupVal === '7' ? beforeDate7 : (this.chart.radioGroupVal === '31' ? beforeDate31 : '')
+
+ this.chart.date = [beforeDate, nowDate]
+ },
+ // 初始化图表
+ initChart() {
+ this.chart.chartInstanceLine = this.$echarts.init(this.$refs.echart_bar)
+ this.chart.chartInstanceDrop1 = this.$echarts.init(this.$refs.echart_drop_1)
+ this.chart.chartInstanceDrop2 = this.$echarts.init(this.$refs.echart_drop_2)
+ this.renderBaseChart()
+ },
+ // 渲染chart基础配置
+ renderBaseChart() {
+ const baseBarOptions = {
+ animationDuration: 1500,
+ tooltip: {
+ trigger: "axis",
+ formatter: "日期: {b} <div></div> 在线时长: {c}分",
+ },
+ grid: {
+ top: "10%",
+ right: "0",
+ left: "2%",
+ bottom: "14",
+ containLabel: true,
+ },
+ xAxis: [{
+ type: 'category',
+ axisLine: {
+ lineStyle: {
+ width: 2,
+ color: "#B7E4F7",
+ },
+ },
+ axisTick: {
+ show: false,
+ },
+ }],
+ yAxis: [{
+ type: 'value',
+ axisLabel: {
+ formatter: "{value}",
+ color: "#CAD3E0",
+ },
+ splitLine: {
+ lineStyle: {
+ width: 2,
+ type: "dashed",
+ color: "#5A7E9D",
+ },
+ },
+ }],
+ series: [{
+ type: 'line',
+ smooth: true,
+ barWidth: 14,
+ color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {offset: 0, color: "#C15B3C"},
+ {offset: 1, color: "#FACD91"},
+ ]),
+ }],
+ }
+ const baseDropOptions1 = {
+ title: {
+ text: '近一周报警天数',
+ left: '32%',
+ top: 30,
+ textStyle: {
+ color: "#fff",
+ },
+ },
+ series: [{
+ type: 'liquidFill',
+ data: [0],
+ radius: '60%', //图表的大小 值是圆的直径
+ shape: 'circle', //水填充图的形状 circle默认圆形 rect圆角矩形 triangle三角形 diamond菱形 pin水滴状 arrow箭头状 还可以是svg的path
+ center: ['50%', '50%'], //图表相对于盒子的位置
+ outline: {
+ show: false
+ },
+ backgroundStyle: { // 背景配置
+ color: 'transparent', //背景颜色
+ borderWidth: '2',//边框大小
+ borderColor: 'rgba(17, 94, 176, 0.4)', // 边框颜色
+ },
+ itemStyle: {
+ color: new this.$echarts.graphic.LinearGradient(
+ 0, 0, 0, 1, //4个参数用于配置渐变色的起止位置, 这4个参数依次对应右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始
+ [
+ {offset: 0, color: '#2790F4'},
+ {offset: 1, color: '#165190'}
+ ] //数组, 用于配置颜色的渐变过程. 每一项为一个对象, 包含offset和color两个参数. offset的范围是0 ~ 1, 用于表示位置
+ )
+ },
+ }]
+ }
+ const baseDropOptions2 = {
+ title: {
+ text: '近一个月(31天)报警天数',
+ right: '24%',
+ top: 30,
+ textStyle: {
+ color: "#fff",
+ },
+ },
+ series: [{
+ type: 'liquidFill',
+ data: [0],
+ radius: '60%', //图表的大小 值是圆的直径
+ shape: 'circle', //水填充图的形状 circle默认圆形 rect圆角矩形 triangle三角形 diamond菱形 pin水滴状 arrow箭头状 还可以是svg的path
+ center: ['50%', '50%'], //图表相对于盒子的位置
+ outline: {
+ show: false
+ },
+ backgroundStyle: { // 背景配置
+ color: 'transparent', //背景颜色
+ borderWidth: '2',//边框大小
+ borderColor: 'rgba(17, 94, 176, 0.4)', // 边框颜色
+ },
+ itemStyle: {
+ color: new this.$echarts.graphic.LinearGradient(
+ 0, 0, 0, 1, //4个参数用于配置渐变色的起止位置, 这4个参数依次对应右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始
+ [
+ {offset: 0, color: '#2790F4'},
+ {offset: 1, color: '#165190'}
+ ] //数组, 用于配置颜色的渐变过程. 每一项为一个对象, 包含offset和color两个参数. offset的范围是0 ~ 1, 用于表示位置
+ )
+ },
+ }]
+ }
+ this.chart.chartInstanceLine.setOption(baseBarOptions)
+ this.chart.chartInstanceDrop1.setOption(baseDropOptions1)
+ this.chart.chartInstanceDrop2.setOption(baseDropOptions2)
+ },
+ // 渲染chart内容数据(x,y,series)
+ async renderChart() {
+ const obj = await this.getWarning()
+ const day = obj.day // 报警天数
+ const percentDay = (day / this.chart.radioGroupVal).toFixed(2) //百分比
+ const x = [] // x轴数据
+ const y = [] // y轴数据
+ obj.reportNumDtos.forEach(item => {
+ x.push(item.smTime)
+ y.push(item.num)
+ })
+ const lineOptions = {
+ title: {
+ text: `${this.userName} 近${this.chart.radioGroupVal}天报警天数`,
+ left: '42%',
+ textStyle: {
+ color: "#E2E5EA",
+ fontSize: 12,
+ },
+ },
+ xAxis: {
+ index: 0,
+ data: x
+ },
+ series: {
+ index: 0,
+ data: y
+ }
+ }
+ const dropOptions = {
+ series: {
+ index: 0,
+ data: [percentDay],
+ label: {
+ color: '#fff',
+ formatter: () => day,
+ }
+ }
+ }
+ this.chart.chartInstanceLine.setOption(lineOptions)
+ if (this.chart.radioGroupVal === '7') {
+ this.chart.chartInstanceDrop1.setOption(dropOptions)
+
+ } else if (this.chart.radioGroupVal === '31') {
+ this.chart.chartInstanceDrop2.setOption(dropOptions)
+ }
+ },
+ screenAdapter() {
+ this.chart.chartInstanceLine?.resize()
+ this.chart.chartInstanceDrop1?.resize()
+ this.chart.chartInstanceDrop2?.resize()
+ },
+ queryTable() {
+ this.getLists()
+ },
+ /* --------详情页面-s */
+ renderDetail() {
+ this.isRenderDetail = true
+ this.setTableDetailColumn()
+ this.getDetailLists()
+ this.renderMap()
+ },
+ setTableDetailColumn() {
+ if (this.detail.tableColumns.length) return
+ this.detail.tableColumns = [
+ {name: "时间", key: "smTime"},
+ {name: "姓名", key: "userName", width: 70},
+ {name: "原因", key: "sosType", width: 80, formatter: (row) => this.detail.sosTypes[row.sosType] || ''},
+ {
+ operation: true, name: "操作", width: 100, value: [
+ {name: "查看", class: "table_btn", handleRow: this.warchDetailRow},
+ ]
+ },
+ ]
+ },
+ getDetailLists() {
+ const params = {
+ userId: this.userId,
+ strTime: this.detail.date?.[0],
+ endTime: this.detail.date?.[1],
+ }
+ this.detail.dataList = []
+ this.$http.getDetailWarning(params).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.detail.dataList = res.data
+ }
+ })
+ },
+ // 查看具体报警信息
+ async warchDetailRow(row) {
+ const _position = await this.getAdress(row.xpoint, row.ypoint)
+ const info = {
+ cause: this.detail.sosTypes[row.sosType],
+ name: row.userName,
+ device: this.deviceNum,
+ position: `${_position}(经度:${row.ypoint}, 纬度${row.xpoint})`,
+ time: row.smTime,
+ }
+ this.detail.info = info
+ this.detail.isShowInfo = true
+ },
+ renderMap() {
+ AMapLoader.load({
+ key: "1dc3895771d98745fa27bbcc3280464f", // 申请好的Web端开发者Key,首次调用 load 时必填
+ version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+ }).then(AMap => {
+ this.detail.AMap = AMap
+ this.detail.map = new AMap.Map("container", {
+ resizeEnable: true,
+ viewMode: "2D", // 是否为3D地图模式
+ zoom: 13, // 初始化地图级别
+ })
+ })
+ },
+ createMapMarker(lnglatXY) {
+ if (!this.detail.marker) {
+ const AMap = this.detail.AMap
+ this.detail.marker = new AMap.Marker()
+ }
+ const marker = this.detail.marker
+ marker.setMap(null)
+ marker.setPosition(lnglatXY)
+ this.detail.map.add(marker)
+ this.detail.map.setFitView()
+ },
+ // 获取地址
+ getAdress(x, y) {
+ return new Promise(resolve => {
+ let address = ''
+ const AMap = this.detail.AMap
+ const lnglatXY = [y, x] // 位置的经纬度
+ this.createMapMarker(lnglatXY)
+ AMap.plugin('AMap.Geocoder', () => {
+ const geocoder = new AMap.Geocoder({
+ radius: 1000,
+ extensions: "all"
+ })
+ geocoder.getAddress(lnglatXY, function (status, result) {
+ if (status === 'complete' && result.info === 'OK') {
+ address = result.regeocode.formattedAddress
+ }
+ resolve(address)
+ })
+ })
+ })
+ },
+ hideDetail() {
+ this.clearMap()
+ this.detail.date = []
+ this.detail.isShowInfo = false
+ this.isRenderDetail = !this.isRenderDetail
+ },
+ queryDetail() {
+ this.getDetailLists()
+ },
+ /* --------详情页面-e */
+ clearMap() {
+ this.detail.map?.destroy()
+ },
+ clearChart() {
+ this.chart.chartInstanceLine?.clear()
+ this.chart.chartInstanceDrop1?.clear()
+ this.chart.chartInstanceDrop2?.clear()
+ },
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/style/layout-main.scss';
+
+::v-deep .el-radio-button__inner {
+ border: 1px solid #39B5FE;
+ color: #fff;
+ background: transparent;
+}
+
+.hide {
+ opacity: 0;
+}
+
+.show {
+ opacity: 1;
+}
+
+#container {
+ width: 100%;
+ height: 100%;
+}
+
+.main {
+ display: flex;
+ flex-direction: row;
+ color: #EBEBEB;
+
+ .main_left {
+ display: flex;
+ flex-direction: column;
+ width: 380px;
+ padding: 14px;
+ margin-right: 18px;
+ border: 1px solid #39B5FE;
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .search_item {
+ span {
+ display: inline-block;
+ min-width: 54px;
+ margin-right: 6px;
+ text-align: right;
+ }
+
+ .el-input {
+ width: 220px;
+ margin: 0 28px 16px 0;
+ }
+ }
+
+ ::v-deep.main_left_table {
+ overflow: hidden;
+
+ .el-table {
+ display: flex;
+ flex-direction: column;
+
+ .el-table__body-wrapper {
+ overflow-y: auto;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .main_right {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 20px;
+ border: 1px solid #39B5FE;
+ background-color: rgba(0, 52, 121, 0.3);
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .echart_options {
+ margin-bottom: 10px;
+
+
+ }
+
+ .echart_bar {
+ flex: 1;
+ }
+
+ .echart_drop {
+ flex: 1.1;
+
+ > div {
+ float: left;
+ width: 50%;
+ height: 100%;
+ }
+ }
+ }
+
+ .detail {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ padding: 20px;
+
+ .detail_option {
+ .search_item {
+ float: left;
+
+ span {
+ display: inline-block;
+ margin-right: 6px;
+ }
+
+ .el-input {
+ width: 220px;
+ margin: 0 28px 16px 0;
+ }
+
+ .elDatePicker {
+ margin: 0 10px 14px 0;
+ }
+ }
+ }
+
+ .detail_botbox {
+ overflow: hidden;
+ flex: 1;
+ }
+
+ ::v-deep.detail_table {
+ float: left;
+ width: 400px;
+ height: 100%;
+ margin-right: 20px;
+
+ .el-table {
+ display: flex;
+ flex-direction: column;
+
+ .el-table__body-wrapper {
+ overflow-y: auto;
+ flex: 1;
+ }
+ }
+ }
+
+ .detail_map {
+ position: relative;
+ overflow: hidden;
+ min-height: 200px;
+ height: 100%;
+
+ p {
+ display: flex;
+ width: 300px;
+ padding-left: 10px;
+ line-height: 32px;
+ word-break: break-all;
+ border-radius: 3px;
+ background: #143164;
+
+ span {
+ padding: 0 6px;
+ color: #39B5FE;
+ flex: 1;
+ }
+
+ }
+
+ .detail_map_info_l {
+ position: absolute;
+ left: 44px;
+ top: 160px;
+ padding: 0 20px 10px 20px;
+ border-radius: 5px;
+ background: #0D1846;
+
+ h2 {
+ margin-bottom: 30px;
+ color: #F94550;
+ }
+ }
+
+ .detail_map_info_r {
+ position: absolute;
+ right: 36px;
+ top: 260px;
+ padding: 0 20px;
+ border-radius: 5px;
+ background: #0D1846;
+
+ h2 {
+ margin-bottom: 30px;
+ color: #39B5FE;
+ }
+ }
+ }
+
+ }
+}
+</style>
\ No newline at end of file
diff --git a/web/src/views/SecureManage/SmartHelmet/PhoneManage.vue b/web/src/views/SecureManage/SmartHelmet/PhoneManage.vue
index f377ec1..300e799 100644
--- a/web/src/views/SecureManage/SmartHelmet/PhoneManage.vue
+++ b/web/src/views/SecureManage/SmartHelmet/PhoneManage.vue
@@ -1,3 +1,250 @@
-<template>
- <div>照片管理</div>
-</template>
\ No newline at end of file
+<template>
+ <!-- 安全管理 ==> 智能安全帽 => 照片管理 -->
+ <div class="main">
+ <!-- main_left -->
+ <div class="main_left">
+ <div class="main_left_search">
+ <div class="search_item">
+ <span>姓名:</span>
+ <el-input size="mini" v-model="queryInfo.userName" placeholder="请输入姓名" clearable></el-input>
+ </div>
+ <div class="search_item">
+ <span>设备编号:</span>
+ <el-input size="mini" v-model="queryInfo.deviceNum" placeholder="请输入设备编号" clearable></el-input>
+ <el-button icon="el-icon-search" @click="queryTable">查询</el-button>
+ </div>
+ </div>
+ <div class="main_left_table">
+ <cpnTable :table-loading="loading" :table-data="dataList" :table-columns="tableColumns"
+ :row-click="rowClick">
+ </cpnTable>
+ </div>
+ </div>
+ <!-- main_right -->
+ <div class="main_right">
+ <div class="search_item">
+ <span>日期:</span>
+ <el-date-picker type="daterange" v-model="pics.date" value-format="yyyy-MM-dd" start-placeholder="开始日期"
+ end-placeholder="结束日期" clearable></el-date-picker>
+ <!-- <el-select v-model="pics.type">
+ <el-option :value="1">所有照片</el-option>
+ <el-option :value="2">安全带取证</el-option>
+ </el-select> -->
+ <el-button icon="el-icon-search" @click="queryPic">查询</el-button>
+ </div>
+ <div class="pic_wrap">
+ <div class="pic_item" v-for="item in pics.data" :key="item.iid">
+ <el-image :src="item.imageUrl" :preview-src-list="[item.imageUrl]" lazy></el-image>
+ <div class="pic_item_info">
+ <div class="pic_item_info_time">{{ item.smTime }}</div>
+ <div class="pic_item_info_des"></div>
+ <div class="pic_item_info_btn">
+ </div>
+ </div>
+ </div>
+ <div class="nopic" v-if="!pics.data.length">暂无图片</div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import cpnTable from '@/components/element/Table'
+export default {
+ data() {
+ return {
+ loading: false,
+ queryInfo: {
+ pageNum: 1,
+ pageSize: 9999,
+ userName: '',
+ deviceNum: '',
+ },
+ dataList: [],
+ tableColumns: [],
+ userId: '', // 用户id
+ pics: {
+ date: [],
+ type: '',
+ data: [],
+ },
+ $http: '', // 接口api路径
+ }
+ },
+ components: {
+ cpnTable
+ },
+ created() {
+ this.$http = this.$api.Safety.SmartHelmet.pic
+ this.setTableColumn()
+ this.getLists()
+ },
+ methods: {
+ setTableColumn() {
+ this.tableColumns = [
+ {selection: true},
+ {name: "用户ID", key: "userId"},
+ {name: "姓名", key: "userName"},
+ {name: "设备编号", key: "deviceNum"},
+ ]
+ },
+ getLists() {
+ this.loading = true
+ this.$api.Safety.SmartHelmet.getLists(this.queryInfo).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.dataList = res.data.list
+ }
+ }).finally(() => this.loading = false)
+ },
+ getPics() {
+ const params = {
+ userId: this.userId,
+ pageNum: 1,
+ pageSize: 9999,
+ strTime: this.pics.date?.[0],
+ endTime: this.pics.date?.[1],
+ }
+ this.$http.getPics(params).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.pics.data = res.data.list
+ }
+ })
+ },
+ rowClick(row) {
+ this.userId = row.userId
+ this.getPics()
+ },
+ queryTable() {
+ this.getLists()
+ },
+ queryPic() {
+ this.getPics()
+ },
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/style/layout-main.scss';
+
+.main {
+ display: flex;
+ flex-direction: row;
+ color: #EBEBEB;
+
+ .main_left {
+ display: flex;
+ flex-direction: column;
+ width: 380px;
+ padding: 14px;
+ margin-right: 18px;
+ border: 1px solid #39B5FE;
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .search_item {
+ span {
+ display: inline-block;
+ min-width: 54px;
+ margin-right: 6px;
+ text-align: right;
+ }
+
+ .el-input {
+ width: 220px;
+ margin: 0 28px 16px 0;
+ }
+ }
+
+ ::v-deep.main_left_table {
+ overflow: hidden;
+
+ .el-table__row {
+ cursor: pointer
+ }
+
+ .el-table {
+ display: flex;
+ flex-direction: column;
+
+ .el-table__body-wrapper {
+ overflow-y: auto;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .main_right {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 20px;
+ border: 1px solid #39B5FE;
+ background-color: rgba(0, 52, 121, 0.3);
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .search_item {
+
+ .el-button,
+ .el-input,
+ .el-select {
+ margin: 0 12px 14px 6px;
+ }
+ }
+
+ .pic_wrap {
+ flex: 1;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ align-items: center;
+ overflow-y: auto;
+
+ .nopic {
+ width: 100%;
+ text-align: center;
+ font-size: 28px;
+ }
+
+ .pic_item {
+ display: flex;
+ flex-direction: column;
+ width: 380px;
+ height: 300px;
+ border: 1px solid green;
+ margin: 10px;
+
+ .el-image {
+ border: 1px solid #4EA7DD;
+ }
+
+ .pic_item_info {
+ position: relative;
+ flex: 1;
+ margin-top: 3px;
+ border: 1px solid #3DC8FF;
+ background: rgba(21, 66, 107, .6);
+
+ .pic_item_info_time {
+ position: absolute;
+ top: 40%;
+ font-size: 13px;
+ text-indent: 20px;
+ }
+
+ .pic_item_info_btn {
+ position: absolute;
+ top: 34px;
+ right: 20px;
+ }
+ }
+ }
+ }
+ }
+}
+</style>
\ No newline at end of file
diff --git a/web/src/views/SecureManage/SmartHelmet/SafeHat.vue b/web/src/views/SecureManage/SmartHelmet/SafeHat.vue
index ac93bb0..06f4ff5 100644
--- a/web/src/views/SecureManage/SmartHelmet/SafeHat.vue
+++ b/web/src/views/SecureManage/SmartHelmet/SafeHat.vue
@@ -1,3 +1,129 @@
-<template>
- <div>安全帽设备</div>
-</template>
\ No newline at end of file
+<template>
+ <!-- 安全管理 ==> 智能安全帽 => 安全帽设备 -->
+ <div class="main">
+ <!-- main_left -->
+ <div class="main_left">
+ <div class="main_left_search">
+ <div class="search_item">
+ <span>姓名:</span>
+ <el-input size="mini" v-model="queryInfo.userName" placeholder="请输入姓名" clearable></el-input>
+ </div>
+ <div class="search_item">
+ <span>设备编号:</span>
+ <el-input size="mini" v-model="queryInfo.deviceNum" placeholder="请输入设备编号" clearable></el-input>
+ <el-button icon="el-icon-search" v-permission="'search'" @click="queryTable">查询</el-button>
+ </div>
+ </div>
+ <div class="main_left_table">
+ <cpnTable :table-loading="loading" :table-data="dataList" :table-columns="tableColumns"
+ :row-click="rowClick">
+ </cpnTable>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import cpnTable from '@/components/element/Table'
+export default {
+ data() {
+ return {
+ loading: false,
+ queryInfo: {
+ pageNum: 1,
+ pageSize: 9999,
+ userName: '',
+ deviceNum: '',
+ },
+ dataList: [],
+ tableColumns: [],
+ userId: '', // 用户id
+ }
+ },
+ components: {
+ cpnTable
+ },
+ created() {
+ this.setTableColumn()
+ this.getLists()
+ },
+ methods: {
+ setTableColumn() {
+ this.tableColumns = [
+ {selection: true},
+ {name: "用户ID", key: "userId"},
+ {name: "姓名", key: "userName"},
+ {name: "设备编号", key: "deviceNum"},
+ ]
+ },
+ getLists() {
+ this.loading = true
+ this.$api.Safety.SmartHelmet.getLists(this.queryInfo).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.dataList = res.data.list
+ }
+ }).finally(() => this.loading = false)
+ },
+ rowClick(row) {
+ this.userId = row.userId
+ },
+ queryTable() {
+ this.getLists()
+ },
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/style/layout-main.scss';
+
+.main {
+ display: flex;
+ flex-direction: row;
+ color: #EBEBEB;
+
+ .main_left {
+ display: flex;
+ flex-direction: column;
+ width: 380px;
+ padding: 14px;
+ margin-right: 18px;
+ border: 1px solid #39B5FE;
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .search_item {
+ span {
+ display: inline-block;
+ min-width: 54px;
+ margin-right: 6px;
+ text-align: right;
+ }
+
+ .el-input {
+ width: 220px;
+ margin: 0 28px 16px 0;
+ }
+ }
+
+ ::v-deep.main_left_table {
+ overflow: hidden;
+
+ .el-table__row {
+ cursor: pointer
+ }
+
+ .el-table {
+ display: flex;
+ flex-direction: column;
+
+ .el-table__body-wrapper {
+ overflow-y: auto;
+ flex: 1;
+ }
+ }
+ }
+ }
+}
+</style>
\ No newline at end of file
diff --git a/web/src/views/SecureManage/SmartHelmet/TrackBack.vue b/web/src/views/SecureManage/SmartHelmet/TrackBack.vue
index 1939462..a943fa9 100644
--- a/web/src/views/SecureManage/SmartHelmet/TrackBack.vue
+++ b/web/src/views/SecureManage/SmartHelmet/TrackBack.vue
@@ -1,3 +1,738 @@
-<template>
- <div>轨迹回放</div>
-</template>
\ No newline at end of file
+<template>
+ <!-- 安全管理 ==> 智能安全帽 => 轨迹回放 -->
+ <div class="main">
+ <!-- table -->
+ <div class="main_left">
+ <div class="main_left_search">
+ <div class="search_item">
+ <span>姓名:</span>
+ <el-input size="mini" v-model="queryInfo.userName" placeholder="请输入姓名" clearable></el-input>
+ </div>
+ <div class="search_item">
+ <span>设备编号:</span>
+ <el-input size="mini" v-model="queryInfo.deviceNum" placeholder="请输入设备编号" clearable></el-input>
+ <el-button icon="el-icon-search" @click="queryTable">查询</el-button>
+ </div>
+ </div>
+ <div class="main_left_table">
+ <cpnTable :table-loading="loading" :table-data="dataList" :table-columns="tableColumns"
+ :row-click="rowClick">
+ </cpnTable>
+ </div>
+ </div>
+ <!-- chart -->
+ <div class="main_right_echart" v-show="!isShowMap">
+ <div class="echart_options">
+ <span>日期:</span>
+ <el-date-picker class="elDatePicker" type="daterange" v-model="chart.date" value-format="yyyy-MM-dd"
+ start-placeholder="开始日期" end-placeholder="结束日期" clearable></el-date-picker>
+ <el-button icon="el-icon-search" @click="queryEchart">查询</el-button>
+ <el-button style="float:right" @click="watchMap">查看</el-button>
+ </div>
+ <div ref="echart_bar" class="echart_bar"></div>
+ <div ref="echart_drop" class="echart_drop"></div>
+ </div>
+ <!-- map -->
+ <div class="main_right_map" v-show="isShowMap">
+ <div class="map_option">
+ <span>日期:</span>
+ <el-date-picker class="elDatePicker" type="daterange" v-model="chart.date" value-format="yyyy-MM-dd"
+ start-placeholder="开始日期" end-placeholder="结束日期" clearable></el-date-picker>
+ <el-button icon="el-icon-search" @click="queryEchart">查询</el-button>
+ <el-button style="float:right" @click="hideMap">返回</el-button>
+ </div>
+ <div class="map_view">
+ <div class="map_view_main">
+ <div id="container"></div>
+ <div id="trackDetail" v-show="isShowTrackDetail">
+ <h2>位置信息统计</h2>
+ <div class="ul_box">
+ <ul>
+ <li :class="{ active: index === maps.trackListIndex }"
+ v-for="(val, index) in maps.trackLists " :key="index" @click="trackListClick(index)">
+ {{ val }}
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ <div class="map_view_btn">
+ <el-button @click="startAnimation">开始动画</el-button>
+ <el-button @click="pauseAnimation">停止动画</el-button>
+ <el-button @click="resumeAnimation">继续动画</el-button>
+ <el-button @click="stopAnimation">停止动画</el-button>
+ <el-button @click="showTrackDetail">轨迹详情</el-button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>
+
+<script>
+import AMapLoader from '@amap/amap-jsapi-loader';
+import cpnTable from '@/components/element/Table'
+import icon from '@/assets/markerIcon.png'
+import 'echarts-liquidfill' // 水滴图形
+export default {
+ data() {
+ return {
+ loading: false,
+ isShowMap: false, // 是否查看轨迹地图
+ isShowTrackDetail: false, // 是否渲染轨迹详情
+ queryInfo: {
+ pageNum: 1,
+ pageSize: 9999,
+ userName: '',
+ deviceNum: '',
+ },
+ dataList: [],
+ tableColumns: [],
+ userId: '', // 用户id
+ // 图表数据
+ chart: {
+ date: [new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).format(), new Date().format()], // 轨迹图表日期.默认近一个月
+ totaltime: '', // 安全帽在线总时长
+ },
+ maps: { // 地图数据
+ date: '',
+ trackLists: [], // 轨迹详情
+ trackListIndex: '',
+ },
+ }
+ },
+ components: {
+ cpnTable
+ },
+ created() {
+ // 添加密钥,获取高德地址使用
+ window._AMapSecurityConfig = {
+ securityJsCode: "aa90b00e27025d1f57286675cc8b232e",
+ }
+ // 存储全局变量.(不响应式)
+ this.maps.times = []
+ this.maps.lineArr = []
+ this.maps.AMap = null
+ this.maps.map = null
+ this.maps.mapMarker = null
+ this.chart.chartInstanceBar = null
+ this.chart.chartInstanceDrop = null
+ this.$http = this.$api.Safety.SmartHelmet.trackBack // 接口api路径
+
+ this.setTableColumn()
+ this.getLists()
+ },
+ mounted() {
+ window.addEventListener("resize", this.screenAdapter)
+ },
+ beforeDestroy() {
+ this.clearMap()
+ this.clearChart()
+ window.removeEventListener("resize", this.screenAdapter)
+ },
+ methods: {
+ setTableColumn() {
+ this.tableColumns = [
+ {selection: true},
+ {name: "用户ID", key: "userId"},
+ {name: "姓名", key: "userName"},
+ {name: "设备编号", key: "deviceNum"},
+ ]
+ },
+ getLists() {
+ this.loading = true
+ this.$api.Safety.SmartHelmet.getLists(this.queryInfo).then(res => {
+ if (res.statusMsg === 'ok') {
+ this.dataList = res.data.list
+ }
+ this.loading = false
+ })
+ },
+ // 获取用户在线时长
+ async getOnlineTime() {
+ let out = {}
+ const params = {
+ userId: this.userId,
+ // strTime: this.chart.date?.[0],
+ // endTime: this.chart.date?.[1],
+ strTime: '2023-06-01',
+ endTime: '2023-06-31',
+ }
+ const {data, statusMsg} = await this.$http.getOnlineTime(params)
+ if (statusMsg === 'ok') {
+ out = {
+ list: data.tHelmetTrajectory,
+ total: data.total,
+ }
+ }
+ return out
+ },
+ // 获取用户轨迹
+ async getTrackLists() {
+ let out = {
+ positions: [], // 经纬度
+ times: [], // 时间
+ }
+ const params = {
+ userId: this.userId,
+ // strTime: this.chart.date?.[0],
+ // endTime: this.chart.date?.[1],
+ strTime: '2023-06-01',
+ endTime: '2023-06-31',
+ }
+ const {data, statusMsg} = await this.$http.getTrackLists(params)
+ if (statusMsg === 'ok') {
+ data.forEach(item => {
+ out.positions.push([+item.ypoint, +item.xpoint])
+ out.times.push(item.smTime)
+ })
+ }
+ return out
+ },
+ // 初始化图表
+ initChart() {
+ this.chart.chartInstanceBar = this.$echarts.init(this.$refs.echart_bar)
+ this.chart.chartInstanceDrop = this.$echarts.init(this.$refs.echart_drop)
+ this.renderBaseChart()
+ },
+ // 渲染chart基础配置
+ renderBaseChart() {
+ const baseBarOptions = {
+ animationDuration: 1500,
+ tooltip: {
+ trigger: "axis",
+ },
+ legend: {
+ itemWidth: 35,
+ itemHeight: 12,
+ x: 'right',
+ y: 'top',
+ textStyle: {
+ color: "#fff",
+ },
+ },
+ grid: {
+ top: "10%",
+ right: "0",
+ left: "2%",
+ bottom: "14",
+ containLabel: true,
+ },
+ xAxis: [{
+ type: 'category',
+ axisLine: {
+ lineStyle: {
+ width: 2,
+ color: "#B7E4F7",
+ },
+ },
+ axisTick: {
+ show: false,
+ },
+ }],
+ yAxis: [{
+ type: 'value',
+ axisLabel: {
+ formatter: "{value}",
+ color: "#CAD3E0",
+ },
+ splitLine: {
+ lineStyle: {
+ width: 2,
+ type: "dashed",
+ color: "#5A7E9D",
+ },
+ },
+ }],
+ series: [{
+ type: 'bar',
+ name: "在线时长",
+ barWidth: 14,
+ color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {offset: 0, color: "#C15B3C"},
+ {offset: 1, color: "#FACD91"},
+ ]),
+ }],
+ }
+ const baseDropOptions = {
+ series: [{
+ type: 'liquidFill',
+ data: [0],
+ radius: '70%', //图表的大小 值是圆的直径
+ shape: 'circle', //水填充图的形状 circle默认圆形 rect圆角矩形 triangle三角形 diamond菱形 pin水滴状 arrow箭头状 还可以是svg的path
+ center: ['50%', '50%'], //图表相对于盒子的位置
+ outline: {
+ show: false
+ },
+ backgroundStyle: { // 背景配置
+ color: 'transparent', //背景颜色
+ borderWidth: '2',//边框大小
+ borderColor: 'rgba(17, 94, 176, 0.4)', // 边框颜色
+ },
+ itemStyle: {
+ color: new this.$echarts.graphic.LinearGradient(
+ 0, 0, 0, 1, //4个参数用于配置渐变色的起止位置, 这4个参数依次对应右/下/左/上四个方位. 而0 0 0 1则代表渐变色从正上方开始
+ [
+ {offset: 0, color: '#2790F4'},
+ {offset: 1, color: '#165190'}
+ ] //数组, 用于配置颜色的渐变过程. 每一项为一个对象, 包含offset和color两个参数. offset的范围是0 ~ 1, 用于表示位置
+ )
+ },
+ }]
+ }
+ this.chart.chartInstanceBar.setOption(baseBarOptions)
+ this.chart.chartInstanceDrop.setOption(baseDropOptions)
+ },
+ // 渲染chart内容数据(x,y,series)
+ async renderChart() {
+ const {list, total} = await this.getOnlineTime()
+ const x = [] // x轴数据
+ const y = [] // y轴数据
+ list.forEach(item => {
+ x.push(item.ctime)
+ y.push(item.ltime)
+ })
+ const baseBarOptions = {
+ xAxis: {
+ index: 0,
+ data: x
+ },
+ series: {
+ index: 0,
+ data: y
+ }
+ }
+ const baseDropOptions = {
+ series: {
+ index: 0,
+ data: [0.3],
+ label: {
+ color: '#fff',
+ fontSize: 28,
+ formatter: () => this.handleTime(total),
+ }
+ }
+ }
+ this.chart.chartInstanceBar.setOption(baseBarOptions)
+ this.chart.chartInstanceDrop.setOption(baseDropOptions)
+ },
+ // 处理秒=>天时分
+ handleTime(num) {
+ let second = num * 60
+ let day = 0
+ let hour = 0
+ let minutes = 0
+ if (second < 86400) {
+ day = 0;
+ if (second < 3600) {
+ hour = 0;
+ if (second < 60) {
+ minutes = 0;
+ } else {
+ minutes = Math.floor(second / 60);
+ }
+ } else {
+ hour = Math.floor(second / 3600);
+ if (second - hour * 3600 < 60) {
+ minutes = 0;
+ } else {
+ minutes = Math.floor((second - hour * 3600) / 60);
+ }
+ }
+ } else {
+ day = Math.floor(second / 86400);
+ if (second - 86400 * day < 3600) {
+ hour = 0;
+ minutes = Math.floor((second - 86400 * day) / 60);
+ } else {
+ hour = Math.floor((second - 86400 * day) / 3600);
+ if (second - 86400 * day - 3600 * hour < 60) {
+ minutes = 0;
+ } else {
+ minutes = Math.floor((second - 86400 * day - 3600 * hour) / 60);
+ }
+ }
+ }
+ day = day ? day + "天" : ''
+ hour = hour ? hour + "小时" : ''
+ minutes = minutes && minutes + "分"
+ return day + hour + minutes
+ },
+ rowClick(row) {
+ this.userId = row.userId
+ if (!this.chart.chartInstanceBar) {
+ this.initChart()
+ }
+ this.hideMap()
+ this.renderChart()
+ },
+ queryTable() {
+ this.getLists()
+ },
+ queryEchart() {
+ this.renderChart()
+ },
+ queryMap() {
+
+ },
+ // chart 查看按钮
+ watchMap() {
+ if (!this.userId) {
+ this.$message.warning('请先选择用户');
+ return
+ }
+ this.renderMap()
+ },
+ async renderMap() {
+ this.isShowMap = !this.isShowMap
+ let {positions, times} = await this.getTrackLists()
+ this.maps.times = times
+ this.maps.lineArr = positions
+ AMapLoader.load({
+ key: "1dc3895771d98745fa27bbcc3280464f", // 申请好的Web端开发者Key,首次调用 load 时必填
+ version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
+ }).then(AMap => {
+ this.maps.AMap = AMap
+ AMap.plugin('AMap.MoveAnimation', () => {
+ // 创建地图
+ this.maps.map = new AMap.Map("container", {
+ resizeEnable: true,
+ viewMode: "2D", // 是否为3D地图模式
+ zoom: 17, // 初始化地图级别
+ })
+ if (positions.length) {
+ // 创建一个 (小人) Icon
+ var personIcon = new AMap.Icon({
+ image: icon, // 图标的取图地址
+ imageSize: new AMap.Size(40, 40), // 图标所用图片大小
+ })
+ // 创建marker实例
+ let mapMarker = this.maps.mapMarker = new AMap.Marker({
+ map: this.maps.map,
+ position: positions[0],
+ icon: personIcon,
+ zIndex: 10,
+ offset: new AMap.Pixel(-20, -36),
+ })
+ // marker提示框
+ let infoWindow = new AMap.InfoWindow({offset: new AMap.Pixel(0, -30)});
+ let markerMouseover = async (e) => {
+ let index = e.target.content
+ let adress = await this.getAdress(positions[index])
+ let time = times[index]
+ let el = `
+ <p><t>地址:</t><span>${adress}</span></p>
+ <p><t>时间:</t><span>${time}</span></p>
+ <p><t>经纬度:</t><span>${positions[index][0]}, ${positions[index][1]}</span></p>
+ `
+ infoWindow.setContent(el)
+ infoWindow.open(this.maps.map, e.target.getPosition())
+ }
+ // 给折线图添加拐点和绑定事件
+ for (var i = 0; i < positions.length; i += 1) {
+ let center = positions[i]
+ let icon = new AMap.Icon({
+ size: new AMap.Size(6, 11), // 图标尺寸
+ image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png', // Icon的图像
+ imageSize: new AMap.Size(6, 11)
+ })
+ let marker = new AMap.Marker({
+ map: this.maps.map,
+ position: center,
+ icon: icon,
+ offset: new AMap.Pixel(-3, -10)
+ })
+ marker.content = i
+ marker.on("mouseover", markerMouseover)
+ }
+ // 绘制轨迹
+ new AMap.Polyline({
+ map: this.maps.map,
+ path: positions,
+ // showDir: true,
+ strokeColor: "#28F", //线颜色
+ strokeWeight: 3, //线宽
+ })
+ // 已通过轨迹
+ let passedPolyline = new AMap.Polyline({
+ map: this.maps.map,
+ strokeColor: "red", //线颜色
+ strokeWeight: 3, //线宽
+ })
+ mapMarker.on('moving', (e) => {
+ passedPolyline.setPath(e.passedPath);
+ this.maps.map.setCenter(e.target.getPosition(), true)
+ })
+ this.maps.map.setFitView()
+ }
+ })
+ })
+ },
+ // 获取地址
+ getAdress(lnglats) {
+ return new Promise(resolve => {
+ const AMap = this.maps.AMap
+ AMap.plugin('AMap.Geocoder', () => {
+ const geocoder = new AMap.Geocoder({
+ radius: 1000,
+ extensions: "all"
+ })
+ geocoder.getAddress(lnglats, (status, result) => {
+ let address = ''
+ if (status === 'complete' && result.info === 'OK') {
+ address = result.regeocodes ? result.regeocodes : result.regeocode.formattedAddress
+ }
+ resolve(address)
+ })
+ })
+ })
+ },
+ hideMap() {
+ this.clearMap()
+ this.isShowMap = false
+ this.maps.trackLists = []
+ this.maps.trackListIndex = ''
+ },
+ startAnimation() {
+ this.maps.mapMarker?.moveAlong(this.maps.lineArr, {
+ // 每一段的时长
+ duration: 500,//可根据实际采集时间间隔设置
+ // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
+ autoRotation: true,
+ })
+ },
+ pauseAnimation() {
+ this.maps.mapMarker?.pauseMove()
+ },
+ resumeAnimation() {
+ this.maps.mapMarker?.resumeMove()
+ },
+ stopAnimation() {
+ this.maps.mapMarker?.stopMove()
+ },
+ // 显示轨迹详情
+ async showTrackDetail() {
+ this.isShowTrackDetail = !this.isShowTrackDetail
+ if (this.maps.trackLists.length) {
+ return
+ }
+ if (this.maps.times.length && this.maps.lineArr.length) {
+ let tracks = []
+ let adress = await this.getAdress([...this.maps.lineArr])
+ adress.forEach((item, index) => {
+ tracks.push(`位置: ${this.maps.times[index]}(${item.formattedAddress})`)
+ })
+ this.maps.trackLists = tracks
+ }
+ },
+ trackListClick(index) {
+ this.maps.trackListIndex = index
+ },
+ screenAdapter() {
+ this.chart.chartInstanceBar?.resize()
+ this.chart.chartInstanceDrop?.resize()
+ },
+ clearMap() {
+ this.maps.mapMarker?.stopMove()
+ this.maps.map?.destroy()
+ },
+ clearChart() {
+ this.chart.chartInstanceBar?.clear()
+ this.chart.chartInstanceDrop?.clear()
+ },
+ }
+}
+</script>
+
+<style lang="scss" scoped>
+@import '@/style/layout-main.scss';
+
+::v-deep .amap-info-content {
+ flex-direction: row;
+ width: 220px;
+ padding: 14px;
+ line-height: 20px;
+ border-radius: 5px;
+ background: #0D1846;
+
+ p {
+ display: flex;
+ width: 100%;
+ }
+
+ t {
+ width: 40px;
+ }
+
+ span {
+ flex: 1;
+ color: #39B5FE;
+ }
+}
+
+::v-deep .bottom-center .amap-info-sharp {
+ border-top: 8px solid #0D1846;
+}
+
+.active {
+ color: #39B5FE;
+}
+
+#container {
+ min-height: 400px;
+ flex: 1.6;
+}
+
+#trackDetail {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+
+ h2 {
+ text-indent: 20px;
+ }
+
+ .ul_box {
+ overflow-y: auto;
+ flex: 1;
+
+ ul {
+ margin: 0;
+ padding: 0 16px;
+ }
+
+ li {
+ padding: 10px 0;
+ font-size: 15px;
+ line-height: 24px;
+ list-style: none;
+ border-bottom: 1px dashed #fff;
+ cursor: pointer;
+ }
+ }
+}
+
+.main {
+ display: flex;
+ flex-direction: row;
+ color: #EBEBEB;
+
+ .main_left {
+ display: flex;
+ flex-direction: column;
+ width: 380px;
+ padding: 14px;
+ margin-right: 18px;
+ border: 1px solid #39B5FE;
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .search_item {
+ span {
+ display: inline-block;
+ min-width: 54px;
+ margin-right: 6px;
+ text-align: right;
+ }
+
+ .el-input {
+ width: 220px;
+ margin: 0 28px 16px 0;
+ }
+ }
+
+ ::v-deep.main_left_table {
+ overflow: hidden;
+
+ .el-table__row {
+ cursor: pointer
+ }
+
+ .el-table {
+ display: flex;
+ flex-direction: column;
+
+ .el-table__body-wrapper {
+ overflow-y: auto;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .main_right_echart {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+ padding: 20px;
+ border: 1px solid #39B5FE;
+ background-color: rgba(0, 52, 121, 0.3);
+ border-radius: 10px;
+ box-shadow: rgba(0, 145, 255, 0.7) 0 0 18px inset;
+ box-sizing: content-box;
+
+ .echart_options {
+ span {
+ display: inline-block;
+ margin-right: 6px;
+ text-align: right;
+ }
+
+ .elDatePicker {
+ width: 260px;
+ margin: 0 10px 14px 0;
+ }
+ }
+
+ .echart_bar {
+ flex: 1;
+ }
+
+ .echart_drop {
+ flex: 1.1;
+ }
+ }
+
+ .main_right_map {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ right: 0;
+ left: 430px;
+ top: 0;
+ bottom: 0;
+ padding: 20px;
+
+ .map_option {
+ span {
+ display: inline-block;
+ margin-right: 6px;
+ }
+
+ .elDatePicker {
+ width: 260px;
+ margin: 0 10px 14px 0;
+ }
+ }
+
+ .map_view {
+ overflow: hidden;
+ display: flex;
+ flex-direction: column;
+ flex: 1;
+
+ .map_view_main {
+ overflow: hidden;
+ display: flex;
+ flex: 1;
+ }
+
+ .map_view_btn {
+ margin-top: 10px;
+ }
+ }
+ }
+}
+</style>
\ No newline at end of file
--
Gitblit v1.9.3