| | |
| | | "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", |
| | |
| | | } |
| | | } |
| | | }, |
| | | "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", |
| | |
| | | "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", |
| | |
| | | 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 }),
|
| | | }
|
| | | } |
| | | } |
对比新文件 |
| | |
| | | <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> |
| | |
| | | <template> |
| | | <div> |
| | | <div class="box">
|
| | | <!-- elTable --> |
| | | <el-table v-loading="tableLoading" :data="tableData" :ref="tableRef" :size="tableSize" @row-click="rowClick" |
| | | @row-dblclick="rowDblClick" @selection-change="handleSelectionChange" border stripe> |
| | | <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 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"> |
| | | <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> |
| | |
| | | </template> |
| | | </el-table> |
| | | <!-- 分页组件 --> |
| | | <cPagination :total="pageTotal" :page-num.sync="pageNum" :page-size.sync="pageSize" @change-page-num="changePageNum" |
| | | @change-page-size="changePageSize" /> |
| | | <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> |
| | |
| | | handleSelection: { |
| | | type: Function, |
| | | default: () => { } |
| | | } |
| | | },
|
| | | rowClick: {
|
| | | type: Function,
|
| | | default: () => { }
|
| | | },
|
| | | }, |
| | | components: { |
| | | cPagination |
| | | }, |
| | | methods: { |
| | | changePageNum(val) { |
| | | // console.log(val) |
| | | // this.pageNum = val |
| | | this.$emit("update:pageNum", val); |
| | | this.pageChange(); |
| | | this.$emit("update:pageNum", val)
|
| | | this.pageChange()
|
| | | }, |
| | | changePageSize(val) { |
| | | this.$emit("update:pageSize", val); |
| | | this.$emit("update:pageSize", val)
|
| | | if (val * (this.pageNum - 1) <= this.pageTotal) { |
| | | this.pageChange(); |
| | | this.pageChange()
|
| | | } |
| | | }, |
| | | // 单击 |
| | | rowClick() { |
| | | // this.time && clearTimeout(this.time); |
| | | // this.time = setTimeout(() => { |
| | | // this.$refs[this.tableRef].toggleRowSelection(row); |
| | | // }, 200); |
| | | handleRowClick(row) {
|
| | | this.rowClick(row)
|
| | | }, |
| | | // 双击 |
| | | rowDblClick() { |
| | | // this.time && clearTimeout(this.time); |
| | | }, |
| | | clearSelection() { |
| | | this.$refs[this.tableRef].clearSelection(); |
| | | }, |
| | | handleRowDblClick() { },
|
| | | handleSelectionChange(val) { |
| | | this.handleSelection(val); |
| | | this.handleSelection(val)
|
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | <style lang="scss" scoped> |
| | | .box {
|
| | | height: 100%;
|
| | | }
|
| | |
|
| | | .el-table { |
| | | border: none; |
| | | height: 100%;
|
| | | } |
| | | </style> |
| | |
| | | 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
|
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | ::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; |
| | | } |
| | |
| | | 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);
|
| | | }
|
| | | } |
| | |
| | | </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"> |
| | | <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> |
| | |
| | | <!-- 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"> |
| | |
| | | <script> |
| | | import {throttle} from '../../plugins/public'; // 导入节流、动态切换组件尺寸方法 |
| | | import cpnTable from '@/components/element/Table' |
| | | import cpnForm from '@/components/element/Form'
|
| | | export default { |
| | | data() { |
| | | return { |
| | |
| | | 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 |
| | | cpnTable,
|
| | | cpnForm
|
| | | }, |
| | | computed: { |
| | | isUpdate() { |
| | |
| | | <template> |
| | | <div>报警记录</div> |
| | | <!-- 安全管理 ==> 智能安全帽 => 报警记录 -->
|
| | | <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> |
| | |
| | | <template> |
| | | <div>照片管理</div> |
| | | <!-- 安全管理 ==> 智能安全帽 => 照片管理 -->
|
| | | <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> |
| | |
| | | <template> |
| | | <div>安全帽设备</div> |
| | | <!-- 安全管理 ==> 智能安全帽 => 安全帽设备 -->
|
| | | <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> |
| | |
| | | <template> |
| | | <div>轨迹回放</div> |
| | | <!-- 安全管理 ==> 智能安全帽 => 轨迹回放 -->
|
| | | <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> |