| @ -0,0 +1,18 @@ | |||
| import request from '@/utils/request' | |||
| export function listPatroltype(query) { | |||
| return request({ | |||
| url: "/basedata/alg/list", | |||
| method: "get", | |||
| params: query, | |||
| }); | |||
| } | |||
| // 算法配置列表 | |||
| export function listPartrolResult (query) { | |||
| return request({ | |||
| url: '/basedata/subtype/list', | |||
| method: 'get', | |||
| params: query | |||
| }) | |||
| } | |||
| @ -0,0 +1,52 @@ | |||
| import request from '@/utils/request' | |||
| // 查询基础数据-设备台账主列表 | |||
| export function listEqpbook(query) { | |||
| return request({ | |||
| url: '/basedata/eqpbook/list', | |||
| method: 'get', | |||
| params: query | |||
| }) | |||
| } | |||
| // 查询基础数据-设备台账主详细 | |||
| export function getEqpbook(eqpbookId) { | |||
| return request({ | |||
| url: '/basedata/eqpbook/' + eqpbookId, | |||
| method: 'get' | |||
| }) | |||
| } | |||
| // 新增基础数据-设备台账主 | |||
| export function addEqpbook(data) { | |||
| return request({ | |||
| url: '/basedata/eqpbook', | |||
| method: 'post', | |||
| data: data | |||
| }) | |||
| } | |||
| // 修改基础数据-设备台账主 | |||
| export function updateEqpbook(data) { | |||
| return request({ | |||
| url: '/basedata/eqpbook/edit', | |||
| method: 'post', | |||
| data: data | |||
| }) | |||
| } | |||
| // 删除基础数据-设备台账主 | |||
| export function delEqpbook(eqpbookId) { | |||
| return request({ | |||
| url: '/basedata/eqpbook/remove/' + eqpbookId, | |||
| method: 'post' | |||
| }) | |||
| } | |||
| // 获取主系统字典 | |||
| export function getMainSystems(){ | |||
| return request({ | |||
| url: '/basedata/bdconfig/mainsystem/list?pageNum=1&pageSize=10000', | |||
| method: 'get' | |||
| }) | |||
| } | |||
| @ -0,0 +1,255 @@ | |||
| import request from '@/utils/request' | |||
| import { type } from 'os' | |||
| /** | |||
| * 控制设备 | |||
| * @param {*} data | |||
| * @returns | |||
| */ | |||
| export function invoke (data) { | |||
| return request({ | |||
| url: '/manager/dev/control/invokeIotDevYunTaiXgFunction', | |||
| method: 'post', | |||
| data | |||
| }) | |||
| } | |||
| /** | |||
| * 指定设备姿态 | |||
| * @param {*} data | |||
| */ | |||
| export function invokeControl (data) { | |||
| return request({ | |||
| url: '/manager/dev/control/invokeIotDevCtrlCommandFunctionForXg', | |||
| method: 'post', | |||
| data | |||
| }) | |||
| } | |||
| /** | |||
| * 获取设备姿态 | |||
| * @param {*}} deviceCode | |||
| */ | |||
| export function getDevicePosture (deviceCode) { | |||
| return request({ | |||
| url: '/manager/dev/device/getDevStatusFromCacheByKey/' + deviceCode, | |||
| method: 'get' | |||
| }) | |||
| } | |||
| /** | |||
| * 获取播放地址 | |||
| * @param {*} deviceCode | |||
| * @param {*} channelCode | |||
| */ | |||
| export function getMediaUrl (deviceCode, channelCode, noAlert) { | |||
| return request({ | |||
| noAlert, | |||
| url: "/patrol/video/realtime", | |||
| methods: 'get', | |||
| params: { | |||
| patroldeviceCode: deviceCode, | |||
| channelCode | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 云台控制 | |||
| * @param {*} params | |||
| */ | |||
| export function controlPanTilt (params) { | |||
| return request({ | |||
| url: "/patrol/videotape/ptz", | |||
| methods: 'get', | |||
| params | |||
| }) | |||
| } | |||
| /** | |||
| * 刷新联动数据 | |||
| */ | |||
| export function refreshUnionTaskData () { | |||
| return request({ | |||
| url: "/patrol/linkage/popup", | |||
| methods: 'get' | |||
| }) | |||
| } | |||
| /** | |||
| * 获取通道列表 | |||
| */ | |||
| export function getDeviceChannelList (deviceCode) { | |||
| return request({ | |||
| url: "/basedata/eqpbook/channel/getChannelByEqpbookCode", | |||
| methods: 'get', | |||
| params: { | |||
| patroldeviceCode: deviceCode | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 根据任务获取巡视设备及视频通道树 | |||
| */ | |||
| export function taskByEqbookchannel (taskCode) { | |||
| return request({ | |||
| url: "/patrol/task/taskByEqbookchannel", | |||
| methods: 'get', | |||
| params: { | |||
| taskCode: taskCode | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 控制机器人 | |||
| */ | |||
| export function controlRobot (deviceCode, type, command, value = null) { | |||
| const data = { | |||
| Code: deviceCode, | |||
| Type: type, | |||
| Command: command | |||
| } | |||
| if (value) { | |||
| data.Items = [ | |||
| { | |||
| Value: value | |||
| } | |||
| ] | |||
| } | |||
| return request({ | |||
| url: "/patrol/client/send", | |||
| method: 'post', | |||
| data | |||
| }) | |||
| } | |||
| /** | |||
| * 控制机器人带验证 | |||
| */ | |||
| export function controlRobotWithVerifition (deviceCode, type, command, value = null) { | |||
| const data = { | |||
| Code: deviceCode, | |||
| Type: type, | |||
| Command: command | |||
| } | |||
| if (value) { | |||
| data.Items = [ | |||
| { | |||
| Value: value | |||
| } | |||
| ] | |||
| } | |||
| return request({ | |||
| url: "/patrol/client/sendImportantMsg", | |||
| method: 'post', | |||
| data | |||
| }) | |||
| } | |||
| /** | |||
| * 心跳 | |||
| * @param {*} streamId | |||
| * @returns | |||
| */ | |||
| export function recordHeartbeat (streamId) { | |||
| return request({ | |||
| url: '/patrol/videotape/heartbeat', | |||
| method: 'get', | |||
| params: { | |||
| streamId: streamId | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 开始录像 | |||
| * @param {*} streamId | |||
| * @param {*} action 0 / 1 | |||
| * @returns | |||
| */ | |||
| export function record (streamId, action = 0) { | |||
| return request({ | |||
| url: '/patrol/videotape/record', | |||
| method: 'get', | |||
| params: { | |||
| streamid: streamId, | |||
| action | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 获取服务器信息 | |||
| * @returns | |||
| */ | |||
| export function getServiceDeviceInfo () { | |||
| return request({ | |||
| url: '/patrol/client/systemInfo', | |||
| method: 'get', | |||
| params: {} | |||
| }) | |||
| } | |||
| /** | |||
| * 获取服务器信息 | |||
| * @returns | |||
| */ | |||
| export function getTemperatureValue (shapeInfo, type, imgUrl) { | |||
| return request({ | |||
| url: '/patrol/infrared', | |||
| method: 'get', | |||
| params: { | |||
| imgUrl, | |||
| coordinate: shapeInfo, | |||
| type | |||
| } | |||
| }) | |||
| } | |||
| /** | |||
| * 获取nvr信息 | |||
| * @returns | |||
| */ | |||
| export function getNvrInfoList () { | |||
| return request({ | |||
| url: '/basedata/nvr/selectNewInfo', | |||
| method: 'post', | |||
| data: {} | |||
| }) | |||
| } | |||
| /** | |||
| * 获取nvr信息在线状态 | |||
| * @returns | |||
| */ | |||
| export function getAllNvrDeviceOlineStatusDataByCache () { | |||
| return request({ | |||
| url: '/basedata/montdata/querydata/getAllNvrDeviceOlineStatusDataByCache', | |||
| method: 'get', | |||
| data: {} | |||
| }) | |||
| } | |||
| /** | |||
| * 修改声纹 | |||
| * @returns | |||
| */ | |||
| export function changeVoiceState (deviceId, bflag) { | |||
| return request({ | |||
| url: '/voicedata/swOn', | |||
| method: 'get', | |||
| params: { | |||
| devId: deviceId, | |||
| flag: bflag ? 'ON' : 'OFF' | |||
| } | |||
| }) | |||
| } | |||
| @ -0,0 +1,60 @@ | |||
| // 告警确认 | |||
| import request from "@/utils/request"; | |||
| import { parseStrEmpty } from "@/utils/ruoyi"; | |||
| // 告警确认列表 | |||
| export function listAlarmConfirm(query) { | |||
| return request({ | |||
| url: "/patrol/analysis/list", | |||
| method: "get", | |||
| params: query, | |||
| }); | |||
| } | |||
| // 告警确认详情 | |||
| export function getAlarmConfirmDetail(id) { | |||
| return request({ | |||
| url: "/patrol/analysis/" + parseStrEmpty(id), | |||
| method: "get", | |||
| }); | |||
| } | |||
| // 告警确认处理 | |||
| export function handleAlarmConfirm(params) { | |||
| return request({ | |||
| url: "/patrol/analysis/updateWarn", | |||
| method: "get", | |||
| params: params, | |||
| }); | |||
| } | |||
| // 批量告警确认处理 | |||
| export function handleBatchAlarmConfirm(params) { | |||
| return request({ | |||
| url: "/patrol/analysis/updateWarn", | |||
| method: "get", | |||
| params: params, | |||
| }); | |||
| } | |||
| // 设备树 | |||
| export function getDeviceTree(params = {}) { | |||
| return request({ | |||
| url: "/basedata/prodevmnt/device/treeAreaDeviceSelect", | |||
| method: "get", | |||
| params: params, | |||
| }); | |||
| } | |||
| // 获取全部算法列表 | |||
| export function getAllAlgorithmList() { | |||
| return request({ | |||
| url: "/basedata/subtype/list", | |||
| method: "get", | |||
| params: { | |||
| pageNum: 1, | |||
| pageSize: 99999, | |||
| }, | |||
| }); | |||
| } | |||
| @ -0,0 +1,13 @@ | |||
| // 异常点位 | |||
| import request from '@/utils/request' | |||
| import { parseStrEmpty } from "@/utils/ruoyi"; | |||
| // 异常点位列表 | |||
| export function listAbnormalPoints(query) { | |||
| return request({ | |||
| url: '/patrol/analysis/abnormal', | |||
| method: 'get', | |||
| params: query | |||
| }) | |||
| } | |||
| @ -0,0 +1,49 @@ | |||
| // 告警确认 | |||
| import request from '@/utils/request' | |||
| import { parseStrEmpty } from "@/utils/ruoyi"; | |||
| // 巡视结果列表 | |||
| export function listPartrolResult (query) { | |||
| return request({ | |||
| url: '/patrol/resultmain/list', | |||
| method: 'get', | |||
| params: query | |||
| }) | |||
| } | |||
| // 巡视结果修正 | |||
| export function correctPartrolResult (params) { | |||
| return request({ | |||
| url: '/patrol/partrolresult/edit', | |||
| method: 'post', | |||
| data: params | |||
| }) | |||
| } | |||
| // 巡视详情 | |||
| export function partrolResultDetail (params) { | |||
| return request({ | |||
| url: '/patrol/partrolresult/detail', | |||
| method: 'get', | |||
| params | |||
| }) | |||
| } | |||
| // 巡视详情列表 | |||
| export function listPartrolResultDetail (params) { | |||
| return request({ | |||
| url: '/patrol/partrolresult/list', | |||
| method: 'get', | |||
| params | |||
| }) | |||
| } | |||
| // 归档 | |||
| export function partrolResultArchive (params) { | |||
| return request({ | |||
| url: '/patrol/resultmain/updateInfo', | |||
| method: 'get', | |||
| params | |||
| }) | |||
| } | |||
| @ -0,0 +1,21 @@ | |||
| // 巡视报告 | |||
| import request from "@/utils/request"; | |||
| import { parseStrEmpty } from "@/utils/ruoyi"; | |||
| // 异常点位列表 | |||
| export function listPatrolReport(query) { | |||
| return request({ | |||
| url: "/patrol/insreport/list", | |||
| method: "get", | |||
| params: query, | |||
| }); | |||
| } | |||
| export function getPatrolReport(lineId,filter) { | |||
| return request({ | |||
| url: `/patrol/insreport/${lineId}/${filter}`, | |||
| method: "get", | |||
| params: {}, | |||
| }); | |||
| } | |||
| @ -0,0 +1,157 @@ | |||
| <template> | |||
| <el-image | |||
| :fit="fit" | |||
| :preview-src-list="imageList" | |||
| :src="imgUrl" | |||
| @load="handleImageLoad" | |||
| @error="handleImageLoadError" | |||
| @click="onClicked" | |||
| > | |||
| <div slot="placeholder" class="image-slot"> | |||
| 加载中<span class="dot">...</span> | |||
| </div> | |||
| <div slot="error" class="image-slot"> | |||
| {{ errorTips }} | |||
| </div> | |||
| </el-image> | |||
| </template> | |||
| <script> | |||
| // import { ftpImageViewUrl } from "@/utils/index"; | |||
| import { mapGetters } from "vuex"; | |||
| import { getConfigByKeys } from "@/api/system/config"; | |||
| import store from "@/store"; | |||
| export default { | |||
| name: "AsyncImage", | |||
| components: {}, | |||
| props: { | |||
| fit: { | |||
| type: String, | |||
| default: "scale-down", | |||
| }, | |||
| srcList: { | |||
| type: Array, | |||
| default: () => [], | |||
| }, | |||
| src: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| errorTips: { | |||
| type: String, | |||
| default: "加载失败", | |||
| }, | |||
| supportPreview: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| async created() {}, | |||
| data() { | |||
| return { | |||
| imgUrl: "", | |||
| loading: false, | |||
| imageList: [], | |||
| config: null, | |||
| }; | |||
| }, | |||
| computed: { | |||
| ...mapGetters(["systemParams"]), | |||
| }, | |||
| methods: { | |||
| async ftpImageViewUrl(url) { | |||
| if (url.startsWith("http://") || url.startsWith("https://")) { | |||
| return url; | |||
| } | |||
| if (!this.systemParams.ftpViewAddress) { | |||
| const systemParams = {}; | |||
| await getConfigByKeys([ | |||
| "EXTRANET_ADDRESS", | |||
| "EXTRANET_FTP_VIEW_ADDRESS", | |||
| "INTRANET_FTP_VIEW_ADDRESS", | |||
| "VIRTUAL_RTC_MEDIAURL", | |||
| "EXTRANET_MEDIA_URL", | |||
| "INTRANET_MEDIA_URL", | |||
| "VIRTUAL_FLV_MEDIAURL", | |||
| "INTRANET_FLV_MEDIA_URL", | |||
| "EXTRANET_FLV_MEDIA_URL", | |||
| ]).then((res) => { | |||
| res.data.forEach((x) => { | |||
| systemParams[x.configKey] = x.configValue; | |||
| }); | |||
| systemParams.PREFIX = | |||
| location.hostname === systemParams.EXTRANET_ADDRESS | |||
| ? "EXTRANET" | |||
| : "INTRANET"; | |||
| systemParams.ftpViewAddress = | |||
| systemParams[systemParams.PREFIX + "_FTP_VIEW_ADDRESS"]; | |||
| systemParams.MEDIA_URL = | |||
| systemParams[systemParams.PREFIX + "_MEDIA_URL"]; | |||
| systemParams.FLV_MEDIA_URL = | |||
| systemParams[systemParams.PREFIX + "_FLV_MEDIA_URL"]; | |||
| }); | |||
| return systemParams.ftpViewAddress + url; | |||
| } else { | |||
| return this.systemParams.ftpViewAddress + url; | |||
| } | |||
| }, | |||
| async getUrls(val) { | |||
| this.imageList = []; | |||
| const urls = []; | |||
| for (let index = 0; index < val.length; index++) { | |||
| const element = val[index]; | |||
| urls.push(await this.ftpImageViewUrl(element)); | |||
| } | |||
| if (this.supportPreview) { | |||
| this.imageList = urls; | |||
| } | |||
| }, | |||
| handleImageLoad(e) { | |||
| const imgOriginalHeight = e.target.naturalHeight; | |||
| const imgOriginalWidth = e.target.naturalWidth; | |||
| this.$emit("imgload", { imgOriginalHeight, imgOriginalWidth }); | |||
| }, | |||
| handleImageLoadError() { | |||
| this.$emit("imgloaderror"); | |||
| }, | |||
| onClicked() { | |||
| this.$emit("click"); | |||
| }, | |||
| }, | |||
| watch: { | |||
| srcList: { | |||
| handler(val) { | |||
| this.getUrls(val); | |||
| }, | |||
| immediate: true, | |||
| }, | |||
| src: { | |||
| async handler(val) { | |||
| if (val && val.length > 0) { | |||
| this.imgUrl = await this.ftpImageViewUrl(val); | |||
| if (this.srcList.length === 0) { | |||
| this.getUrls([val]); | |||
| } | |||
| } else { | |||
| this.imgUrl = ""; | |||
| } | |||
| }, | |||
| immediate: true, | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .image-slot { | |||
| display: flex; | |||
| justify-content: center; | |||
| align-items: center; | |||
| width: 100%; | |||
| height: 100%; | |||
| color: #ddd; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,562 @@ | |||
| <template> | |||
| <canvas class="drawCanvas" v-show="visible" ref="canvas" @contextmenu="canvasContextMenu" :width="canvasWidth" | |||
| :height="canvasHeight"> | |||
| </canvas> | |||
| </template> | |||
| <script> | |||
| /** | |||
| * 所有图形类都继承形状基类 | |||
| * 每个图形自己实现相关交互(包括不限于响应:点击,鼠标移动,鼠标按下,鼠标抬起等事件) | |||
| * 与canvas拖拽鼠标按下相关事件区分开 | |||
| * 这样更好维护 | |||
| */ | |||
| class Shape { | |||
| //绘制方法 | |||
| draw () { } | |||
| startDraw () { } | |||
| stopDraw () { } | |||
| getData () { } | |||
| setData () { } | |||
| constructor(canvasEl, context, hub) { | |||
| this.type = '' | |||
| this.canvasEl = canvasEl; | |||
| this.context = context; | |||
| // 鼠标事件缓存坐标 | |||
| this.x1 = 0; | |||
| this.y1 = 0; | |||
| //拖拽标记 | |||
| this.isDragging = false; | |||
| //拉伸标记,默认false | |||
| this.isStretching = false; | |||
| //活动标记 只有出现活动标记时,才追加拉伸框 | |||
| this.isActive = false; | |||
| //是否正在绘制 | |||
| this.isDrawing = false; | |||
| //事件回调总线 | |||
| this.hub = hub; | |||
| } | |||
| stopDraw () { | |||
| this.isDragging = false; | |||
| this.canvasEl.onmouseup = null; | |||
| this.canvasEl.onmousemove = null; | |||
| this.canvasEl.onmousedown = null; | |||
| } | |||
| } | |||
| /** | |||
| * 多边形 | |||
| */ | |||
| class Polygon extends Shape { | |||
| constructor(hub, canvas, ctx) { | |||
| super(canvas, ctx, hub); | |||
| this.points = []; | |||
| this.type = 'Polygon' | |||
| this.clickCount = 0 | |||
| } | |||
| setData (data) { | |||
| const temp = data.split(',') | |||
| const x = temp[0] | |||
| const y = temp[1] | |||
| const w = temp[2] | |||
| const h = temp[3] | |||
| const cw = temp[4] | |||
| const ch = temp[5] | |||
| } | |||
| getData () { | |||
| let data = [] | |||
| this.points.forEach(p => { | |||
| data = data.concat(p) | |||
| }) | |||
| data = data.concat([this.canvasEl.clientWidth, this.canvasEl.clientHeight]) | |||
| return { | |||
| type: 'Polygon', | |||
| data: data.join(',') | |||
| } | |||
| } | |||
| /** | |||
| * 绘制方法 | |||
| */ | |||
| draw (point) { | |||
| const rect = this; | |||
| // 绘制矩形 | |||
| this.context.strokeStyle = rect.color || "#FF0000"; | |||
| this.context.clearRect(0, 0, this.canvasEl.clientWidth, this.canvasEl.clientHeight); | |||
| // 如果有传入点,则追追加绘制 | |||
| const points = point ? this.points.concat([point]) : this.points; | |||
| this.context.beginPath(); | |||
| this.context.moveTo(points[0][0], points[0][1]); | |||
| for (let i = 1; i < points.length; i++) { | |||
| this.context.lineTo(points[i][0], points[i][1]); | |||
| } | |||
| this.context.closePath(); | |||
| this.context.stroke(); | |||
| } | |||
| startDraw () { | |||
| this.isDrawing = true; | |||
| this.clickCount = 0; | |||
| const me = this; | |||
| this.canvasEl.onmouseup = (e) => { | |||
| me.mouseUp(e); | |||
| }; | |||
| this.canvasEl.onmousemove = (e) => { | |||
| me.mouseMove(e); | |||
| }; | |||
| } | |||
| mouseUp (e) { | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| if (this.isDrawing) { | |||
| // this.clickCount += 1; | |||
| if (e.button === 2) { | |||
| this.isDrawing = false; | |||
| this.hub({ | |||
| key: 'drawFinish', | |||
| data: this | |||
| }) | |||
| this.draw(); | |||
| } else { | |||
| this.points.push(point) | |||
| } | |||
| this.draw(); | |||
| } | |||
| //清除标记 | |||
| this.isStretching = false; | |||
| this.isDragging = false; | |||
| } | |||
| mouseMove (e) { | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| if (this.isDrawing) { | |||
| this.draw(point); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 折线,非闭合,用于现场管控 | |||
| */ | |||
| class BrokenLine extends Shape { | |||
| constructor(hub, canvas, ctx) { | |||
| super(canvas, ctx, hub); | |||
| this.points = []; | |||
| this.type = 'BrokenLine' | |||
| this.clickCount = 0 | |||
| // 要画的线数 | |||
| this.lineCount = 0; | |||
| } | |||
| setData (data) { | |||
| const temp = data.split(',') | |||
| const x = temp[0] | |||
| const y = temp[1] | |||
| const w = temp[2] | |||
| const h = temp[3] | |||
| const cw = temp[4] | |||
| const ch = temp[5] | |||
| } | |||
| getData () { | |||
| let data = [] | |||
| this.points.forEach(p => { | |||
| data = data.concat(p) | |||
| }) | |||
| data = data.concat([this.canvasEl.clientWidth, this.canvasEl.clientHeight]) | |||
| return { | |||
| type: 'BrokenLine', | |||
| data: data.join(',') | |||
| } | |||
| } | |||
| /** | |||
| * 绘制方法 | |||
| */ | |||
| draw (point) { | |||
| const rect = this; | |||
| // 绘制矩形 | |||
| this.context.strokeStyle = rect.color || "#FF0000"; | |||
| this.context.clearRect(0, 0, this.canvasEl.clientWidth, this.canvasEl.clientHeight); | |||
| // 如果有传入点,则追追加绘制 | |||
| const points = point ? this.points.concat([point]) : this.points; | |||
| this.context.beginPath(); | |||
| this.context.moveTo(points[0][0], points[0][1]); | |||
| for (let i = 1; i < points.length; i++) { | |||
| this.context.lineTo(points[i][0], points[i][1]); | |||
| } | |||
| // this.context.closePath(); | |||
| this.context.stroke(); | |||
| } | |||
| startDraw () { | |||
| this.isDrawing = true; | |||
| this.clickCount = 0; | |||
| const me = this; | |||
| this.canvasEl.onmouseup = (e) => { | |||
| me.mouseUp(e); | |||
| }; | |||
| this.canvasEl.onmousemove = (e) => { | |||
| me.mouseMove(e); | |||
| }; | |||
| } | |||
| // 根据线数判断是否结束绘制 | |||
| isNeedOverDraw () { | |||
| if (this.lineCount <= 0) { | |||
| return false | |||
| } | |||
| // 两个点为一条线,所以-1 | |||
| return (this.lineCount <= this.clickCount - 1) | |||
| } | |||
| mouseUp (e) { | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| if (this.isDrawing) { | |||
| this.clickCount += 1; | |||
| if (e.button === 2) { | |||
| this.isDrawing = false; | |||
| this.hub({ | |||
| key: 'drawFinish', | |||
| data: this | |||
| }) | |||
| this.draw(); | |||
| } else { | |||
| this.points.push(point) | |||
| } | |||
| // 是否需要结束 | |||
| if (this.isNeedOverDraw()) { | |||
| this.isDrawing = false; | |||
| this.hub({ | |||
| key: 'drawFinish', | |||
| data: this | |||
| }) | |||
| } | |||
| this.draw(); | |||
| } | |||
| //清除标记 | |||
| this.isStretching = false; | |||
| this.isDragging = false; | |||
| } | |||
| mouseMove (e) { | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| if (this.isDrawing) { | |||
| this.draw(point); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 矩形类 | |||
| */ | |||
| class Rectangle extends Shape { | |||
| /** | |||
| * 矩形类 | |||
| * @param canvasEl canvas 元素对象 | |||
| * @param context object canvas 上下文 | |||
| * @param x int 默认 0 | |||
| * @param y int 默认 0 | |||
| * @param width 宽度 默认 100 | |||
| * @param height 高度 默认 100 | |||
| * @param lineColr string 绘制线的颜色 | |||
| */ | |||
| constructor(hub, canvasEl, context, x, y, width, height, lineColor = '#FF0000') { | |||
| //调用父类构造函数 | |||
| super(canvasEl, context, hub); | |||
| this.x = x; | |||
| this.y = y; | |||
| this.width = width; | |||
| this.height = height; | |||
| this.color = lineColor; | |||
| this.type = 'Rectangle'; | |||
| this.clickCount = 0; | |||
| } | |||
| setData (data) { | |||
| const temp = data.split(',') | |||
| const x = temp[0] | |||
| const y = temp[1] | |||
| const w = temp[2] | |||
| const h = temp[3] | |||
| const cw = temp[4] | |||
| const ch = temp[5] | |||
| } | |||
| getData () { | |||
| // 调整顺序,按照顺时针绘制 | |||
| let data = [this.x, this.y, this.x + this.width, this.y, this.x + this.width, this.y + this.height, this.x, this.y + this.height, this.canvasEl.clientWidth, this.canvasEl.clientHeight] | |||
| if (this.width < 0 && this.height > 0) { | |||
| data = [this.x + this.width, this.y, this.x, this.y, this.x, this.y + this.height, this.x + this.width, this.y + this.height, this.canvasEl.clientWidth, this.canvasEl.clientHeight] | |||
| } | |||
| else if (this.width > 0 && this.height < 0) { | |||
| data = [this.x, this.y + this.height, this.x + this.width, this.y + this.height, this.x + this.width, this.y, this.x, this.y, this.canvasEl.clientWidth, this.canvasEl.clientHeight] | |||
| } | |||
| else if (this.width < 0 && this.height < 0) { | |||
| data = [this.x + this.width, this.y + this.height, this.x, this.y + this.height, this.x, this.y, this.x + this.width, this.y, this.canvasEl.clientWidth, this.canvasEl.clientHeight] | |||
| } | |||
| return { | |||
| type: 'Rectangle', | |||
| data: data.join(',') | |||
| } | |||
| } | |||
| /** | |||
| * 绘制方法 | |||
| */ | |||
| draw () { | |||
| const rect = this; | |||
| // 绘制矩形 | |||
| this.context.strokeStyle = rect.color || "#FF0000"; | |||
| if (this.isDrawing) { | |||
| this.context.clearRect(0, 0, this.canvasEl.clientWidth, this.canvasEl.clientHeight); | |||
| } | |||
| // 绘制矩形到画布 | |||
| this.context.strokeRect(rect.x, rect.y, rect.width, rect.height); | |||
| } | |||
| startDraw () { | |||
| this.isDrawing = true; | |||
| this.clickCount = 0; | |||
| const me = this; | |||
| this.canvasEl.onmouseup = (e) => { | |||
| me.mouseUp(e); | |||
| }; | |||
| this.canvasEl.onmousemove = (e) => { | |||
| me.mouseMove(e); | |||
| }; | |||
| } | |||
| mouseUp (e) { | |||
| if (this.isDrawing) { | |||
| this.clickCount += 1; | |||
| if (this.clickCount === 1) { | |||
| const point = [e.offsetX, e.offsetY] | |||
| this.x = point[0]; | |||
| this.y = point[1]; | |||
| } | |||
| if (this.clickCount > 1) { | |||
| this.isDrawing = true; | |||
| this.clickCount = 0 | |||
| this.hub({ | |||
| key: 'drawFinish', | |||
| data: this | |||
| }) | |||
| } | |||
| } | |||
| //清除标记 | |||
| this.isStretching = false; | |||
| this.isDragging = false; | |||
| } | |||
| mouseMove (e) { | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| if (this.isDrawing && this.clickCount > 0) { | |||
| // 绘制 | |||
| this.width = point[0] - this.x; | |||
| this.height = point[1] - this.y; | |||
| this.draw(); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 点 | |||
| */ | |||
| class Point extends Shape { | |||
| constructor(hub, canvas, ctx) { | |||
| super(canvas, ctx, hub); | |||
| this.points = []; | |||
| this.type = "Point"; | |||
| this.clickCount = 0; | |||
| } | |||
| setData (data) { | |||
| const temp = data.split(","); | |||
| const x = temp[0]; | |||
| const y = temp[1]; | |||
| const w = temp[2]; | |||
| const h = temp[3]; | |||
| const cw = temp[4]; | |||
| const ch = temp[5]; | |||
| } | |||
| getData () { | |||
| let data = []; | |||
| this.points.forEach((p) => { | |||
| data = data.concat(p); | |||
| }); | |||
| data = data.concat([this.canvasEl.clientWidth, this.canvasEl.clientHeight]); | |||
| return { | |||
| type: "Point", | |||
| data: data.join(","), | |||
| }; | |||
| } | |||
| /** | |||
| * 绘制方法 | |||
| */ | |||
| draw (point) { | |||
| const rect = this; | |||
| // 绘制矩形 | |||
| this.context.strokeStyle = rect.color || "#FF0000"; | |||
| this.context.clearRect( | |||
| 0, | |||
| 0, | |||
| this.canvasEl.clientWidth, | |||
| this.canvasEl.clientHeight | |||
| ); | |||
| // 如果有传入点,则追追加绘制 | |||
| const points = point ? this.points.concat([point]) : this.points; | |||
| this.context.beginPath(); | |||
| this.context.arc(point[0], point[1], 5, 0, 360, false); | |||
| // this.context.fillstyle="#FF0000"; | |||
| this.context.fill(); | |||
| // this.context.moveTo(points[0][0], points[0][1]); | |||
| // for (let i = 1; i < points.length; i++) { | |||
| // this.context.lineTo(points[i][0], points[i][1]); | |||
| // } | |||
| // this.context.closePath(); | |||
| this.context.stroke(); | |||
| } | |||
| startDraw () { | |||
| this.isDrawing = true; | |||
| this.clickCount = 0; | |||
| const me = this; | |||
| this.canvasEl.onmousedown = (e) => { | |||
| me.mousedown(e); | |||
| }; | |||
| } | |||
| mousedown (e) { | |||
| // if (!this.isDrawing) { | |||
| // return | |||
| // } | |||
| // 取得鼠标画布位置 | |||
| const point = [e.offsetX, e.offsetY]; | |||
| this.draw(point) | |||
| this.points = [point] | |||
| this.isDrawing = false; | |||
| this.hub({ | |||
| key: 'drawFinish', | |||
| data: this | |||
| }) | |||
| } | |||
| } | |||
| const ShapeEnum = { | |||
| "rect": "Rectangle", | |||
| "brokenline": "BrokenLine", | |||
| "polygon": "Polygon", | |||
| "point": "Point", | |||
| } | |||
| class ShapeFactory { | |||
| static createShape (shapeEnum, canvas, ctx, messageHub) { | |||
| switch (shapeEnum) { | |||
| case "Rectangle": | |||
| return new Rectangle(messageHub, canvas, ctx, 0, 0, 10, 10); | |||
| case "BrokenLine": | |||
| return new BrokenLine(messageHub, canvas, ctx); | |||
| case "Polygon": | |||
| return new Polygon(messageHub, canvas, ctx); | |||
| case "Point": | |||
| return new Point(messageHub, canvas, ctx); | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| * 转换坐标系 | |||
| */ | |||
| function toTargetRect (sourceRect, targetRect) { | |||
| const sourceX = sourceRect[0], sourceY = sourceRect[1], sourceWidth = sourceRect[2], sourceHeight = sourceRect[3], sourceCanvasWidth = sourceRect[4], sourceCanvasHeight = sourceRect[5]; | |||
| let targetX = targetRect[0], targetY = targetRect[1], targetWidth = targetRect[2], targetHeight = targetRect[3], targetCanvasWidth = targetRect[4], targetCanvasHeight = targetRect[5]; | |||
| const scaleX = targetCanvasWidth / sourceCanvasWidth, scaleY = targetCanvasHeight / sourceCanvasHeight; | |||
| targetX = sourceX * scaleX; | |||
| targetY = sourceY * scaleY; | |||
| targetWidth = sourceWidth * scaleX; | |||
| targetHeight = sourceHeight * scaleY; | |||
| return [targetX, targetY, targetWidth, targetHeight, targetCanvasWidth, targetCanvasHeight]; | |||
| } | |||
| export { | |||
| Rectangle, | |||
| toTargetRect, | |||
| ShapeEnum | |||
| } | |||
| import lodash from 'lodash' | |||
| export default { | |||
| props: { | |||
| // 折线的线数 | |||
| brokenLineCount: { | |||
| type: Number, | |||
| default: 0 | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| visible: false, | |||
| canvasWidth: 400, | |||
| canvasHeight: 300, | |||
| // canvas 元素 | |||
| canvas: null, | |||
| context: null, | |||
| //正在绘制的图形对象 | |||
| drawingShape: null | |||
| } | |||
| }, | |||
| methods: { | |||
| canvasContextMenu (e) { | |||
| e.cancelBubble = true | |||
| e.preventDefault(); | |||
| }, | |||
| show () { | |||
| this.visible = true | |||
| }, | |||
| hide () { | |||
| this.visible = false | |||
| }, | |||
| startDraw (shapeEnum) { | |||
| const me = this | |||
| // 清除画布,准备绘制 | |||
| this.context.clearRect(0, 0, this.canvas.clientWidth, this.canvas.clientHeight); | |||
| if (this.drawingShape) { | |||
| this.drawingShape.stopDraw() | |||
| } | |||
| this.drawingShape = ShapeFactory.createShape(shapeEnum, this.canvas, this.context, ({ key }) => { | |||
| if (key === 'drawFinish') { | |||
| me.stopDraw(); | |||
| } | |||
| }); | |||
| // 折线可设置线数 | |||
| if (shapeEnum == ShapeEnum.brokenline) { | |||
| this.drawingShape.lineCount = this.brokenLineCount | |||
| } | |||
| this.drawingShape.startDraw(); | |||
| }, | |||
| stopDraw () { | |||
| this.$emit('drawComplete', lodash.cloneDeep(this.drawingShape)); | |||
| }, | |||
| clearShapes () { | |||
| this.context.clearRect(0, 0, this.canvas.clientWidth, this.canvas.clientHeight); | |||
| }, | |||
| /** | |||
| * 初始化事件 | |||
| */ | |||
| init () { | |||
| this.canvasWidth = this.$refs.canvas.clientWidth; | |||
| this.canvasHeight = this.$refs.canvas.clientHeight; | |||
| this.canvas = this.$refs.canvas; | |||
| this.context = this.canvas.getContext("2d"); | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| .drawCanvas { | |||
| box-sizing: border-box; | |||
| position: absolute; | |||
| left: 0; | |||
| top: 0; | |||
| border: 1px solid blueviolet; | |||
| // background-color: rgba(230, 214, 245, 0.562); | |||
| width: 100%; | |||
| height: 100%; | |||
| z-index: 100; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,125 @@ | |||
| <template> | |||
| <div :class="{ hidden: hidden }" class="pagination-container"> | |||
| <el-pagination | |||
| :background="background" | |||
| :current-page.sync="currentPage" | |||
| :page-size.sync="pageSize" | |||
| :layout="layout" | |||
| :page-sizes="pageSizes" | |||
| :pager-count="pagerCount" | |||
| :total="total" | |||
| v-bind="$attrs" | |||
| popper-class="card-select-dropdown" | |||
| @size-change="handleSizeChange" | |||
| @current-change="handleCurrentChange" | |||
| /> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import { scrollTo } from "@/utils/scroll-to"; | |||
| export default { | |||
| name: "CardPagination", | |||
| props: { | |||
| total: { | |||
| required: true, | |||
| type: Number, | |||
| }, | |||
| page: { | |||
| type: Number, | |||
| default: 1, | |||
| }, | |||
| limit: { | |||
| type: Number, | |||
| default: 20, | |||
| }, | |||
| pageSizes: { | |||
| type: Array, | |||
| default() { | |||
| return [10, 20, 30, 50]; | |||
| }, | |||
| }, | |||
| // 移动端页码按钮的数量端默认值5 | |||
| pagerCount: { | |||
| type: Number, | |||
| default: document.body.clientWidth < 992 ? 5 : 7, | |||
| }, | |||
| layout: { | |||
| type: String, | |||
| default: "total, sizes, prev, pager, next, jumper", | |||
| }, | |||
| background: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| autoScroll: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| hidden: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| data() { | |||
| return {}; | |||
| }, | |||
| computed: { | |||
| currentPage: { | |||
| get() { | |||
| return this.page; | |||
| }, | |||
| set(val) { | |||
| this.$emit("update:page", val); | |||
| }, | |||
| }, | |||
| pageSize: { | |||
| get() { | |||
| return this.limit; | |||
| }, | |||
| set(val) { | |||
| this.$emit("update:limit", val); | |||
| }, | |||
| }, | |||
| }, | |||
| methods: { | |||
| handleSizeChange(val) { | |||
| if (this.currentPage * val > this.total) { | |||
| this.currentPage = 1; | |||
| } | |||
| this.$emit("pagination", { page: this.currentPage, limit: val }); | |||
| if (this.autoScroll) { | |||
| scrollTo(0, 800); | |||
| } | |||
| }, | |||
| handleCurrentChange(val) { | |||
| this.$emit("pagination", { page: val, limit: this.pageSize }); | |||
| if (this.autoScroll) { | |||
| scrollTo(0, 800); | |||
| } | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .pagination-container { | |||
| background: #fff; | |||
| padding: 0px 20px !important; | |||
| margin-top: 5px; | |||
| margin-bottom: 0px; | |||
| ::v-deep .el-pagination span:not([class*="suffix"]), | |||
| ::v-deep .el-pagination button { | |||
| font-size: 14px; | |||
| } | |||
| ::v-deep .el-pager li { | |||
| font-size: 14px; | |||
| } | |||
| } | |||
| .pagination-container.hidden { | |||
| display: none; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,442 @@ | |||
| <template> | |||
| <el-dialog | |||
| :title="title" | |||
| :visible.sync="visible" | |||
| :close-on-click-modal="false" | |||
| :close-on-press-escape="false" | |||
| :destroy-on-close="true" | |||
| :before-close="handleClose" | |||
| width="90%" | |||
| append-to-body | |||
| > | |||
| <div v-if="showInfo"> | |||
| <div | |||
| class="flex-row" | |||
| v-if="newInfo && originalInfo.value != newInfo.value" | |||
| > | |||
| <div class="data-wrap"> | |||
| <el-card> | |||
| <div class="home_box_title">修正原数据</div> | |||
| <el-descriptions :column="1" border> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 值 </template> | |||
| {{ originalInfo.value }} | |||
| </el-descriptions-item> | |||
| </el-descriptions> | |||
| </el-card> | |||
| </div> | |||
| <div class="data-wrap"> | |||
| <el-card> | |||
| <div class="home_box_title">修正后数据</div> | |||
| <el-descriptions :column="1" border> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 值 </template> | |||
| <span style="color: red">{{ newInfo.value }}</span> | |||
| </el-descriptions-item> | |||
| </el-descriptions> | |||
| </el-card> | |||
| </div> | |||
| </div> | |||
| <div style="padding: 10px"> | |||
| <el-card> | |||
| <div class="home_box_title">详情数据</div> | |||
| <el-descriptions :column="3" border> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 巡视设备 </template> | |||
| {{ showInfo.patroldeviceName }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 巡视编号 </template> | |||
| {{ showInfo.patroldeviceCode }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 巡视任务执行ID </template> | |||
| {{ showInfo.taskPatrolledId }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 任务名称 </template> | |||
| {{ showInfo.taskName }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 任务编码 </template> | |||
| {{ showInfo.taskCode }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 识别类型 </template> | |||
| <dict-tag | |||
| :options="dict.type.patrol_result_recognition_type" | |||
| :value="showInfo.recognitionType" | |||
| /> | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 数据来源 </template> | |||
| {{ getDataTypeStr(showInfo.dataType) }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 设备点位名称 </template> | |||
| {{ showInfo.deviceName }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 设备点位ID </template> | |||
| {{ showInfo.deviceId }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 时间 </template> | |||
| {{ showInfo.time }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 值类型 </template> | |||
| <dict-tag | |||
| :options="dict.type.patrol_result_value_type" | |||
| :value="showInfo.valueType" | |||
| /> | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 值 </template> | |||
| {{ showInfo.value }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 值带单位 </template> | |||
| {{ showInfo.valueUnit }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 单位 </template> | |||
| {{ showInfo.unit }} | |||
| </el-descriptions-item> | |||
| <!-- <el-descriptions-item> | |||
| <template slot="label"> 阈值 </template> | |||
| {{ showInfo.threshold }} | |||
| </el-descriptions-item> --> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 结论 </template> | |||
| <dict-tag | |||
| :options="dict.type.patrol_result_valid_type" | |||
| :value="showInfo.valid" | |||
| /> | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 归档状态 </template> | |||
| {{ originalInfo.patrolStatus == 1 ? "已归档" : "未归档" }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 审核人 </template> | |||
| {{ originalInfo.checkPerson }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 审核时间 </template> | |||
| {{ originalInfo.checkTime }} | |||
| </el-descriptions-item> | |||
| <el-descriptions-item> | |||
| <template slot="label"> 巡视结论 </template> | |||
| {{ originalInfo.checkResult }} | |||
| </el-descriptions-item> | |||
| </el-descriptions> | |||
| <div class="file-info-wrap"> | |||
| <div class="home_box_title">阈值</div> | |||
| <el-table :data="thresholdList"> | |||
| <el-table-column label="序号" type="index" /> | |||
| <el-table-column label="算法类型" align="center" prop="code"> | |||
| <template slot-scope="scope"> | |||
| <span>{{ getAlgorithmName(scope.row.code) }}</span> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="最小值" align="center" prop="lowerValue"> | |||
| <template slot-scope="scope"> | |||
| <span>{{ | |||
| scope.row.lowerValue ? scope.row.lowerValue : "-" | |||
| }}</span> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="最大值" align="center" prop="upperValue"> | |||
| <template slot-scope="scope"> | |||
| <span>{{ | |||
| scope.row.upperValue ? scope.row.upperValue : "-" | |||
| }}</span> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </div> | |||
| <div class="file-info-wrap" v-if="showInfo.photo.length > 0"> | |||
| <div class="home_box_title">识别图片</div> | |||
| <el-row> | |||
| <el-col | |||
| :span="12" | |||
| style="padding: 5px" | |||
| v-for="(item, index) in showInfo.photo" | |||
| :key="index" | |||
| > | |||
| <div | |||
| class="img-item-bg" | |||
| @click="previewImages(index, showInfo.photo)" | |||
| > | |||
| <!-- 图片 --> | |||
| <AsyncImage | |||
| style="width: 100%; height: 100%" | |||
| fit="contain" | |||
| :src="item" | |||
| ></AsyncImage> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| </div> | |||
| <div class="file-info-wrap" v-if="showInfo.infraRed.length > 0"> | |||
| <div class="home_box_title">红外图谱</div> | |||
| <el-row> | |||
| <el-col | |||
| :span="12" | |||
| style="padding: 5px" | |||
| v-for="(item, index) in showInfo.infraRed" | |||
| :key="index" | |||
| > | |||
| <div | |||
| class="img-item-bg" | |||
| @click="previewImages(index, showInfo.infraRed)" | |||
| > | |||
| <!-- 图片 --> | |||
| <AsyncImage | |||
| style="width: 100%; height: 100%" | |||
| fit="contain" | |||
| :src="item" | |||
| ></AsyncImage> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| </div> | |||
| <div class="file-info-wrap" v-if="showInfo.visible.length > 0"> | |||
| <div class="home_box_title">可见光照片</div> | |||
| <el-row> | |||
| <el-col | |||
| :span="12" | |||
| style="padding: 5px" | |||
| v-for="(item, index) in showInfo.visible" | |||
| :key="index" | |||
| > | |||
| <div | |||
| class="img-item-bg" | |||
| @click="previewImages(index, showInfo.visible)" | |||
| > | |||
| <!-- 图片 --> | |||
| <AsyncImage | |||
| style="width: 100%; height: 100%" | |||
| fit="contain" | |||
| :src="item" | |||
| ></AsyncImage> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| </div> | |||
| <div class="file-info-wrap" v-if="showInfo.audio.length > 0"> | |||
| <div class="home_box_title">音频</div> | |||
| <el-row> | |||
| <el-col | |||
| :span="12" | |||
| style="padding: 5px" | |||
| v-for="(item, index) in showInfo.audio" | |||
| :key="index" | |||
| > | |||
| <div> | |||
| <audio controls :src="item"></audio> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| </div> | |||
| <div class="file-info-wrap" v-if="showInfo.video.length > 0"> | |||
| <div class="home_box_title">视频</div> | |||
| <el-row> | |||
| <el-col | |||
| :span="12" | |||
| style="padding: 5px" | |||
| v-for="(item, index) in showInfo.video" | |||
| :key="index" | |||
| > | |||
| <div class="img-item-bg"> | |||
| <!-- 视频 --> | |||
| <AsyncVideo :src="item" /> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| </div> | |||
| </el-card> | |||
| </div> | |||
| </div> | |||
| <image-preview-dialog | |||
| :visible.sync="showPreviewImages" | |||
| :selectImgPosition="previewImagePos" | |||
| :imageUrls="showImgesUrls" | |||
| /> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import ImagePreviewDialog from "../../components/ImagePreviewDialog/index.vue"; | |||
| import AsyncVideo from "../../components/AsyncVideo/index.vue"; | |||
| import { getAllAlgorithmList } from "@/api/inspectionDataManage/alarmConfirm.js"; | |||
| // 巡视归档对比对话框 | |||
| export default { | |||
| name: "InspectionArchiveContrastDialog", | |||
| components: { ImagePreviewDialog, AsyncVideo }, | |||
| dicts: [ | |||
| "patrol_result_value_type", | |||
| "patrol_result_recognition_type", | |||
| "patrol_result_valid_type", | |||
| ], | |||
| props: { | |||
| // 标题 | |||
| title: { | |||
| type: String, | |||
| default: "巡视结果详情", | |||
| }, | |||
| // 是否显示弹窗 | |||
| visible: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| // 详情 | |||
| newInfo: { | |||
| type: Object, | |||
| require: true, | |||
| default: () => { | |||
| return {}; | |||
| }, | |||
| }, | |||
| originalInfo: { | |||
| type: Object, | |||
| require: true, | |||
| default: () => { | |||
| return {}; | |||
| }, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| showPreviewImages: false, | |||
| previewImagePos: 0, | |||
| showImgesUrls: [], | |||
| algorithmList: [], | |||
| }; | |||
| }, | |||
| computed: { | |||
| // 显示的信息 | |||
| showInfo() { | |||
| return this.newInfo ? this.newInfo : this.originalInfo; | |||
| }, | |||
| thresholdList() { | |||
| if (!this.showInfo.threshold) { | |||
| return []; | |||
| } | |||
| return JSON.parse(this.showInfo.threshold); | |||
| }, | |||
| }, | |||
| created() { | |||
| this.getAlgorithmList(); | |||
| }, | |||
| methods: { | |||
| getAlgorithmList() { | |||
| getAllAlgorithmList().then((res) => { | |||
| this.algorithmList = res.rows; | |||
| }); | |||
| }, | |||
| // 获取算法名称 | |||
| getAlgorithmName(code) { | |||
| if (!this.algorithmList) { | |||
| return ""; | |||
| } | |||
| const name = this.algorithmList.find( | |||
| (item) => item.algSubtypeCode == code | |||
| ); | |||
| return name ? name.algSubtypeName : ""; | |||
| }, | |||
| handleClose(done) { | |||
| this.$emit("update:visible", false); | |||
| }, | |||
| // 数据来源 | |||
| getDataTypeStr(dataType) { | |||
| switch (dataType) { | |||
| case 1: | |||
| return "摄像机"; | |||
| case 2: | |||
| return "机器人"; | |||
| case 3: | |||
| return "无人机"; | |||
| case 4: | |||
| return "声纹"; | |||
| case 5: | |||
| return "在线监测"; | |||
| } | |||
| }, | |||
| previewImages(index, imgUrls) { | |||
| this.previewImagePos = index; | |||
| this.showImgesUrls = imgUrls; | |||
| this.showPreviewImages = true; | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| ::v-deep .el-dialog__header { | |||
| background-color: #001946; | |||
| color: #fff; | |||
| .el-dialog__headerbtn .el-dialog__close { | |||
| color: #fff; | |||
| } | |||
| .el-dialog__title { | |||
| color: #fff; | |||
| } | |||
| } | |||
| ::v-deep .el-dialog__body { | |||
| background-color: #001946; | |||
| padding: 0px 20px 20px; | |||
| } | |||
| .flex-row { | |||
| display: flex; | |||
| } | |||
| .data-wrap { | |||
| flex: 1; | |||
| height: 100; | |||
| padding: 10px; | |||
| } | |||
| .home_box_title { | |||
| padding-bottom: 10px; | |||
| flex: 31px; | |||
| font-size: 20px; | |||
| &::before { | |||
| content: ""; | |||
| width: 3px; | |||
| background: #1890ff; | |||
| height: 18px; | |||
| display: block; | |||
| margin-right: 5px; | |||
| float: left; | |||
| margin-top: 3px; | |||
| } | |||
| } | |||
| .file-info-wrap { | |||
| padding: 10px; | |||
| } | |||
| .img-item-bg { | |||
| background-color: #000; | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,138 @@ | |||
| <template> | |||
| <div class="card-box-bg" :style="cardBoxStyle"> | |||
| <div v-if="showTitle" class="card-box-title-box" :style="titleStyle"> | |||
| <div class="card-box-title"> | |||
| <div | |||
| v-if="showBackBtn" | |||
| style="display: inline-block; cursor: pointer" | |||
| @click="handleBack" | |||
| > | |||
| <i class="el-icon-back"></i> | |||
| </div> | |||
| {{ title }} | |||
| </div> | |||
| <div class="title-btns-slot"> | |||
| <slot name="title-btns"></slot> | |||
| </div> | |||
| </div> | |||
| <div class="content" :class="{ 'content-border': !bgImgURL }"> | |||
| <slot /> | |||
| </div> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| name: "CardBox", | |||
| props: { | |||
| // 背景图 | |||
| bgImgURL: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| // 标题 | |||
| title: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| // 不设置bgImgURL时使用 | |||
| titleImgURL: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| showTitle: { | |||
| type: Boolean, | |||
| default: true, | |||
| }, | |||
| showBackBtn: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| data() { | |||
| return {}; | |||
| }, | |||
| computed: { | |||
| cardBoxStyle() { | |||
| if (this.bgImgURL) { | |||
| return { | |||
| backgroundImage: "url(" + this.bgImgURL + ")", | |||
| backgroundSize: "cover", | |||
| }; | |||
| } else { | |||
| return {}; | |||
| } | |||
| }, | |||
| titleStyle() { | |||
| if (this.titleImgURL) { | |||
| return { | |||
| backgroundImage: "url(" + this.titleImgURL + ")", | |||
| backgroundSize: "cover", | |||
| }; | |||
| } else { | |||
| return {}; | |||
| } | |||
| }, | |||
| }, | |||
| created() {}, | |||
| beforeDestroy() {}, | |||
| methods: { | |||
| handleBack() { | |||
| this.$emit("onBack"); | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .card-box-bg { | |||
| background-size: cover; | |||
| background-repeat: no-repeat; | |||
| background-position: center; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .card-box-title-box { | |||
| display: flex; | |||
| flex-direction: row; | |||
| } | |||
| .card-box-title { | |||
| color: #fff; | |||
| font-size: 22px; | |||
| font-weight: bold; | |||
| height: 40px; | |||
| line-height: 40px; | |||
| margin-left: 60px; | |||
| flex: 2; | |||
| z-index: 1; | |||
| } | |||
| .title-btns-slot { | |||
| flex: 1; | |||
| display: flex; | |||
| align-items: flex-end; | |||
| justify-content: flex-end; | |||
| padding-bottom: 2px; | |||
| padding-right: 5px; | |||
| } | |||
| .content-border { | |||
| /* 分割线 */ | |||
| border: 1px solid #40486a; | |||
| } | |||
| .content { | |||
| flex: 1; | |||
| height: 0; | |||
| padding: 15px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,48 @@ | |||
| let messageId = 0; | |||
| /** | |||
| * 调用卡片系统弹窗 | |||
| * @param {*} zhan_name 站点名称 | |||
| * @param {*} sourceCardId 源卡片id | |||
| * @param {*} targetCardId 目标卡片id | |||
| * @param {*} dialogTitle 弹窗标题 | |||
| * @param {*} dialogIsDrag 弹窗是否可拖拽 默认 true | |||
| * @param {*} positionTop 弹窗上边距 | |||
| * @param {*} positionLeft 弹窗左边距 | |||
| * @param {*} contentWidth 弹窗内容宽度 | |||
| * @param {*} contentHeight 弹窗内容高度 | |||
| * @param {*} params 要传递给卡片的参数 | |||
| */ | |||
| export function openDialog({ | |||
| zhan_name = "", | |||
| sourceCardId, | |||
| targetCardId, | |||
| dialogTitle, | |||
| dialogIsDrag = true, | |||
| positionTop = "30", | |||
| positionLeft = "30", | |||
| contentWidth = "1856", | |||
| contentHeight = "896", | |||
| params = {}, | |||
| }) { | |||
| const id = "message_" + ++messageId; | |||
| var data = { | |||
| id, | |||
| sourceId: zhan_name + sourceCardId, | |||
| targetId: "main_frame_global_modal", // 基座系统弹窗ID | |||
| event: { | |||
| type: "SWITCH_GLOBAL_MODAL", | |||
| data: { | |||
| title: dialogTitle, // 弹窗标题 | |||
| cardId: zhan_name + targetCardId, | |||
| isDrag: dialogIsDrag, // 弹窗是否可拖拽,默认为true可拖拽 | |||
| positionTop, // 数字,弹窗上边距 positionTop | |||
| positionLeft, // 数字,弹窗左边距 positionLeft | |||
| contentWidth, // 数字,弹窗内容宽度 | |||
| contentHeight, // 数字,弹窗内容高度 | |||
| params, // 需要传递的参数 | |||
| }, | |||
| }, | |||
| tm: new Date().getTime(), // 时间戳 | |||
| }; | |||
| window.parent.postMessage(JSON.stringify(data), "*"); | |||
| } | |||
| @ -0,0 +1,591 @@ | |||
| <template> | |||
| <el-dialog | |||
| :title="pointDialogDataName" | |||
| :visible.sync="pointDialogShow" | |||
| width="70%" | |||
| :before-close="bindingMonitorPointClose" | |||
| > | |||
| <el-row :gutter="20"> | |||
| <el-col :span="5"> | |||
| <div class="bindingMonitorPointTree"> | |||
| <el-tree | |||
| :data="dialogPointTree" | |||
| :props="defaultPropsMonitor" | |||
| @node-click="handleMonitor" | |||
| ></el-tree> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="13"> | |||
| <div class="bindingMonitorPointDiv"> | |||
| <videoPlayer /> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="6"> | |||
| <div style="background: #eee; padding: 5px"> | |||
| {{ $t("site_management.PTZ") }} | |||
| </div> | |||
| <div class="PTZ-content"> | |||
| <img src="@/assets/images/PTZImg.png" alt="" class="PTZImg" /> | |||
| <div class="r-ti2-pos"> | |||
| <div @click="ptzBtn('UP', 'UP_STOP')"></div> | |||
| <div @click="ptzBtn('UP_RIGHT', 'UP_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('RIGHT', 'RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_RIGHT', 'DOWN_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN', 'DOWN_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_LEFT', 'DOWN_LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('LEFT', 'LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('UP_LEFT', 'UP_LEFT_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3"> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/searchImg.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="ptzBtn('ZOOM_OUT', 'ZOOM_OUT_STOP')"></div> | |||
| <div @click="ptzBtn('ZOOM_IN', 'ZOOM_IN_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r2Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('nearfocus', 'nearfocusstop')"></div> | |||
| <div @click="fiBtn('farfocus', 'farfocusstop')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r3Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('apertureoff', 'apertureoffstop')"></div> | |||
| <div @click="fiBtn('apertureon', 'apertureonstop')"></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti4"> | |||
| <div style="display: flex"> | |||
| <el-select | |||
| v-model="presetDotNum" | |||
| :placeholder="$t('site_management.PleaseSelectAPresetPoint')" | |||
| @change="presetDotBtn" | |||
| > | |||
| <el-option | |||
| :label="item.dictLabel" | |||
| :value="item.dictValue" | |||
| v-for="item in listByEqIdAndChanneData" | |||
| :key="item.dictValue" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| <img | |||
| src="@/assets/images/playImg.png" | |||
| @click="editPresetDot1" | |||
| title="编辑预置点名称" | |||
| /> | |||
| <img src="@/assets/images/addImg.png" alt="" @click="popoverOpen" /> | |||
| <el-popover | |||
| placement="top" | |||
| width="300" | |||
| v-model="popovervisible" | |||
| trigger="click" | |||
| > | |||
| <el-input placeholder="请输入内容" v-model="newpresetName" /> | |||
| <div class="popover-footer"> | |||
| <el-button | |||
| size="mini" | |||
| type="primary" | |||
| @click="popovervisibleShow" | |||
| >取消</el-button | |||
| > | |||
| <el-button size="mini" type="primary" @click="setPresetDot1" | |||
| >确定</el-button | |||
| > | |||
| </div> | |||
| </el-popover> | |||
| </div> | |||
| <div style="display: flex; margin-top: 20px"> | |||
| <el-input | |||
| v-model="presetName" | |||
| :placeholder="$t('site_management.PleaseEnterTheContent')" | |||
| ></el-input> | |||
| <img | |||
| src="@/assets/images/setImg.png" | |||
| alt="" | |||
| title="编辑预置点名称" | |||
| @click="editPresetDot2" | |||
| /> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-table | |||
| :data="bindingMonitorPointTableData" | |||
| style="width: 100%" | |||
| @header-click="clickFun" | |||
| > | |||
| <el-table-column :label="$t('site_management.ActionType')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-select v-model="scope.row.actionType"> | |||
| <el-option label="拍照" value="1" /> | |||
| <el-option label="录像" value="2" /> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.RecordingDuration')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.videoTime" | |||
| v-if="scope.row.actionType == 2" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.NumberOfPhotosTaken')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoCount" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| <!-- <span v-if="scope.row.actionType == 1">1</span> --> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.PhotoInterval')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoSeper" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| :render-header="(h, obj) => renderHeader(h, obj, $t('share.addTo'))" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-button | |||
| type="text" | |||
| size="small" | |||
| @click="removeAction(scope.$index)" | |||
| >移除</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <template #footer> | |||
| <div class="add-btn add-bth1 card-page"> | |||
| <el-button type="primary" @click="saveDot1">确定</el-button> | |||
| <el-button @click="bindingMonitorPointClose">取消</el-button> | |||
| </div> | |||
| </template> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import videoPlayer from "@/components/videoPlayer/index.vue"; | |||
| import { | |||
| vl, | |||
| listByEqIdAndChannelId, | |||
| realtime, | |||
| PZT, | |||
| fi, | |||
| goto, | |||
| issue, | |||
| bindingPreset, | |||
| } from "@/api/point/site_management"; | |||
| export default { | |||
| components: { videoPlayer }, | |||
| props: ["pointDialogDataName", "pointDialogShow", "dialogProp"], | |||
| data() { | |||
| return { | |||
| bindingMonitorPointTitle: "绑定可见光检测点", | |||
| // pointDialogShow: false, | |||
| dialogPointTree: [], | |||
| defaultPropsMonitor: { | |||
| children: "children", | |||
| label: "name", | |||
| }, | |||
| listByEqIdAndChanneData: [], | |||
| bindingMonitorPointTableData: [], | |||
| presetDotNum: "", | |||
| PZTData: {}, | |||
| presetName: "", | |||
| popovervisible: false, | |||
| newpresetName: "", | |||
| presetData: { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| presetPointList: [], | |||
| }, | |||
| }; | |||
| }, | |||
| methods: { | |||
| bindingMonitorPointClose() { | |||
| // this.pointDialogShow = false; | |||
| this.$emit("site_videoDialogClose",false); | |||
| }, | |||
| // 绑定可见光监测点点击树事件 | |||
| handleMonitor(e) { | |||
| console.log(e, 111, this.dialogProp); | |||
| if (e.eqpbookId) { | |||
| this.presetData.patrolpointId = this.dialogProp.patrolpointId; | |||
| this.presetData.stdparolPointId = this.dialogProp.stdparolPointId; | |||
| this.presetData.deviceId = this.dialogProp.deviceId; | |||
| this.presetData.eqpbookId = e.eqpbookId; | |||
| this.presetData.channelId = e.channelId; | |||
| this.PZTData = e; | |||
| listByEqIdAndChannelId({ | |||
| channelCode: e.channelCode, | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| this.listByEqIdAndChanneData = res.data; | |||
| } | |||
| }); | |||
| realtime({ | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| channelCode: e.channelCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| // this.bindingMonitorPointTableData=res.data; | |||
| console.log(res, 1111); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| renderHeader(h, { column, $index }, type) { | |||
| let that = this; | |||
| return h("div", [ | |||
| // 列名称 | |||
| h("span", column.label), | |||
| // 按钮 | |||
| h( | |||
| "el-button", | |||
| { | |||
| props: { | |||
| type: "text", | |||
| size: "small", | |||
| }, | |||
| style: "margin-left: 5px;", | |||
| on: { | |||
| click: function () { | |||
| that.clickButton(type); | |||
| }, | |||
| }, | |||
| }, | |||
| this.$t("share.addTo") | |||
| ), | |||
| ]); | |||
| }, | |||
| clickButton(type) { | |||
| // console.log("我点击了" + type + "的列"); | |||
| this.bindingMonitorPointTableData.push({ | |||
| actionType: "", | |||
| videoTime: "", | |||
| photoCount: "1", | |||
| photoSeper: "", | |||
| }); | |||
| }, | |||
| clickFun() {}, | |||
| init() { | |||
| vl().then((res) => { | |||
| if (res.code == 200) { | |||
| this.dialogPointTree = res.data; | |||
| } | |||
| }); | |||
| }, | |||
| ptzBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| PZT(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| PZT(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| fiBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| fi(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| fi(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| presetDotBtn(value) { | |||
| this.presetData.presetPosCode = value; | |||
| this.listByEqIdAndChanneData.forEach((item) => { | |||
| if (item.dictValue == this.presetDotNum) { | |||
| this.presetName = item.dictLabel; | |||
| } | |||
| }); | |||
| }, | |||
| // 编辑预置点名称 | |||
| editPresetDot1() { | |||
| let data = { | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| presetDotNum: this.presetDotNum, | |||
| name: this.presetName, | |||
| }; | |||
| goto(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popovervisibleShow() { | |||
| this.popovervisible = false; | |||
| this.newpresetName = ""; | |||
| }, | |||
| setPresetDot1() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.presetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| issue(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.popovervisible = false; | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popoverOpen() { | |||
| this.popovervisible = true; | |||
| }, | |||
| // 设置预设点名称 | |||
| editPresetDot2() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.newpresetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| }, | |||
| // 表格按钮移除 | |||
| removeAction() { | |||
| this.bindingMonitorPointTableData.splice(index, 1); | |||
| }, | |||
| // 保存 | |||
| saveDot1() { | |||
| this.presetData.presetPosName = this.presetName; | |||
| this.presetData.presetActionList = this.bindingMonitorPointTableData; | |||
| bindingPreset(this.presetData).then((res) => { | |||
| console.log(res, 11111); | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.presetData = { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| }; | |||
| this.pointDialogShow=false; | |||
| this.$emit('site_saveDot1',true) | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| mounted() { | |||
| this.init(); | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .bindingMonitorPointTree { | |||
| width: 100%; | |||
| height: 37vh; | |||
| overflow-y: scroll; | |||
| } | |||
| .bindingMonitorPointDiv { | |||
| width: 100%; | |||
| height: 40vh; | |||
| // background: red; | |||
| } | |||
| .PTZ-content { | |||
| width: 170px; | |||
| margin: 10px auto; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| } | |||
| .r-ti2-pos { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div { | |||
| position: absolute; | |||
| z-index: 999; | |||
| width: 20px; | |||
| height: 15px; | |||
| cursor: pointer; | |||
| } | |||
| div:first-child { | |||
| top: 32px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(2) { | |||
| top: 50px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(3) { | |||
| top: 77px; | |||
| right: 30px; | |||
| } | |||
| div:nth-child(4) { | |||
| bottom: 56px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(5) { | |||
| bottom: 36px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(6) { | |||
| bottom: 56px; | |||
| right: 100px; | |||
| } | |||
| div:nth-child(7) { | |||
| bottom: 80px; | |||
| left: 30px; | |||
| } | |||
| div:nth-child(8) { | |||
| top: 50px; | |||
| right: 102px; | |||
| } | |||
| } | |||
| .r-ti3 { | |||
| width: 100%; | |||
| display: flex; | |||
| padding-top: 10px; | |||
| -webkit-box-pack: justify; | |||
| justify-content: space-between; | |||
| } | |||
| .r-ti3-d1 { | |||
| width: 76px; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| .r-ti3-d2 { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div:first-child { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| cursor: pointer; | |||
| } | |||
| div:nth-child(2) { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| right: 0; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| } | |||
| .r-ti4 { | |||
| padding-top: 20px; | |||
| img { | |||
| width: 24px; | |||
| height: 24px; | |||
| position: relative; | |||
| top: 6px; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| .popover-footer { | |||
| width: 100%; | |||
| margin-top: 20px; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,696 @@ | |||
| <template> | |||
| <el-dialog | |||
| :title="pointDialogDataName" | |||
| :visible.sync="pointDialogShow" | |||
| width="70%" | |||
| :before-close="bindingMonitorPointClose" | |||
| > | |||
| <el-row :gutter="20"> | |||
| <el-col :span="5"> | |||
| <div class="bindingMonitorPointTree"> | |||
| <el-tree | |||
| :data="dialogPointTree" | |||
| :props="defaultPropsMonitor" | |||
| @node-click="handleMonitor" | |||
| ></el-tree> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="13"> | |||
| <div class="bindingMonitorPointDiv"> | |||
| <!-- <videoPlayer /> --> | |||
| <VideoPlayerPlatform | |||
| ref="playerPlayform" | |||
| @changeIndex="handleChangeIndex" | |||
| :showBottomToolBar="false" | |||
| :defaultLayout="'1x1'" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <DrawShape | |||
| @drawComplete=" | |||
| (shape) => { | |||
| handleDrawComplete(scope, shape); | |||
| } | |||
| " | |||
| /> | |||
| </template> | |||
| </VideoPlayerPlatform> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="6"> | |||
| <div style="background: #eee; padding: 5px"> | |||
| {{ $t("site_management.PTZ") }} | |||
| </div> | |||
| <div class="PTZ-content"> | |||
| <img src="@/assets/images/PTZImg.png" alt="" class="PTZImg" /> | |||
| <div class="r-ti2-pos"> | |||
| <div @click="ptzBtn('UP', 'UP_STOP')"></div> | |||
| <div @click="ptzBtn('UP_RIGHT', 'UP_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('RIGHT', 'RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_RIGHT', 'DOWN_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN', 'DOWN_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_LEFT', 'DOWN_LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('LEFT', 'LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('UP_LEFT', 'UP_LEFT_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3"> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/searchImg.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="ptzBtn('ZOOM_OUT', 'ZOOM_OUT_STOP')"></div> | |||
| <div @click="ptzBtn('ZOOM_IN', 'ZOOM_IN_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r2Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('nearfocus', 'nearfocusstop')"></div> | |||
| <div @click="fiBtn('farfocus', 'farfocusstop')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r3Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('apertureoff', 'apertureoffstop')"></div> | |||
| <div @click="fiBtn('apertureon', 'apertureonstop')"></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti4"> | |||
| <div style="display: flex"> | |||
| <el-select | |||
| v-model="presetDotNum" | |||
| :placeholder="$t('site_management.PleaseSelectAPresetPoint')" | |||
| @change="presetDotBtn" | |||
| > | |||
| <el-option | |||
| :label="item.dictLabel" | |||
| :value="item.dictValue" | |||
| v-for="item in listByEqIdAndChanneData" | |||
| :key="item.dictValue" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| <img | |||
| src="@/assets/images/playImg.png" | |||
| @click="editPresetDot1" | |||
| title="编辑预置点名称" | |||
| /> | |||
| <img src="@/assets/images/addImg.png" alt="" @click="popoverOpen" /> | |||
| <el-popover | |||
| placement="top" | |||
| width="300" | |||
| v-model="popovervisible" | |||
| trigger="click" | |||
| > | |||
| <el-input placeholder="请输入内容" v-model="newpresetName" /> | |||
| <div class="popover-footer"> | |||
| <el-button | |||
| size="mini" | |||
| type="primary" | |||
| @click="popovervisibleShow" | |||
| >取消</el-button | |||
| > | |||
| <el-button size="mini" type="primary" @click="setPresetDot1" | |||
| >确定</el-button | |||
| > | |||
| </div> | |||
| </el-popover> | |||
| </div> | |||
| <div style="display: flex; margin-top: 20px"> | |||
| <el-input | |||
| v-model="presetName" | |||
| :placeholder="$t('site_management.PleaseEnterTheContent')" | |||
| ></el-input> | |||
| <img | |||
| src="@/assets/images/setImg.png" | |||
| alt="" | |||
| title="编辑预置点名称" | |||
| @click="editPresetDot2" | |||
| /> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-table | |||
| :data="bindingMonitorPointTableData" | |||
| style="width: 100%" | |||
| @header-click="clickFun" | |||
| > | |||
| <el-table-column :label="$t('site_management.ActionType')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-select v-model="scope.row.actionType"> | |||
| <el-option label="拍照" value="1" /> | |||
| <el-option label="录像" value="2" /> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.RecordingDuration')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.videoTime" | |||
| v-if="scope.row.actionType == 2" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.NumberOfPhotosTaken')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoCount" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| <!-- <span v-if="scope.row.actionType == 1">1</span> --> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.PhotoInterval')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoSeper" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| :render-header="(h, obj) => renderHeader(h, obj, $t('share.addTo'))" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-button | |||
| type="text" | |||
| size="small" | |||
| @click="removeAction(scope.$index)" | |||
| >移除</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <template #footer> | |||
| <div class="add-btn add-bth1 card-page"> | |||
| <el-button type="primary" @click="nextBtn" v-if="typeNextBtn" | |||
| >下一步,配置测温位置</el-button | |||
| > | |||
| <el-button type="primary" @click="saveDot1" v-if="!typeNextBtn">确定</el-button> | |||
| <el-button @click="bindingMonitorPointClose">取消</el-button> | |||
| </div> | |||
| </template> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import videoPlayer from "@/components/videoPlayer/index.vue"; | |||
| import { | |||
| vl, | |||
| ir, | |||
| listByEqIdAndChannelId, | |||
| realtime, | |||
| PZT, | |||
| fi, | |||
| goto, | |||
| issue, | |||
| bindingPreset, | |||
| } from "@/api/point/site_management"; | |||
| import { | |||
| listPatroltype, | |||
| getDeviceList, | |||
| } from "@/api/basedata/patrolpointmnt/patroltype"; | |||
| import VideoPlayerPlatform from "@/components/VideoPlayerPlatform"; | |||
| import DrawShape, { | |||
| toTargetRect, | |||
| ShapeEnum, | |||
| } from "@/components/Canvas/DrawShape.vue"; | |||
| export default { | |||
| components: { | |||
| videoPlayer, | |||
| VideoPlayerPlatform, | |||
| DrawShape, | |||
| }, | |||
| props: [ | |||
| "pointDialogDataName", | |||
| "pointDialogShow", | |||
| "dialogProp", | |||
| "typeVideoDialog", | |||
| ], | |||
| data() { | |||
| return { | |||
| bindingMonitorPointTitle: "绑定可见光检测点", | |||
| // pointDialogShow: false, | |||
| dialogPointTree: [], | |||
| defaultPropsMonitor: { | |||
| children: "children", | |||
| label: "name", | |||
| }, | |||
| listByEqIdAndChanneData: [], | |||
| bindingMonitorPointTableData: [], | |||
| presetDotNum: "", | |||
| PZTData: {}, | |||
| presetName: "", | |||
| popovervisible: false, | |||
| newpresetName: "", | |||
| presetData: { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| presetPointList: [], | |||
| }, | |||
| ShapeEnum: { | |||
| rect: "Rectangle", | |||
| brokenline: "BrokenLine", | |||
| polygon: "Polygon", | |||
| point: "Point", | |||
| } /* 绘制方式 */, | |||
| typeNextBtn: false, | |||
| }; | |||
| }, | |||
| watch: { | |||
| typeVideoDialog(newVal, oldVal) { | |||
| if (newVal !== oldVal) { | |||
| // 当 typeVideoDialog 变化时执行 | |||
| this.init(); // 例如重新调用 init 方法 | |||
| } | |||
| }, | |||
| }, | |||
| methods: { | |||
| bindingMonitorPointClose() { | |||
| // this.pointDialogShow = false; | |||
| this.$emit("site_videoDialogClose", false); | |||
| }, | |||
| // 绑定可见光监测点点击树事件 | |||
| handleMonitor(e) { | |||
| console.log(e, 111, this.dialogProp); | |||
| if (e.eqpbookId) { | |||
| this.presetData.patrolpointId = this.dialogProp.patrolpointId; | |||
| this.presetData.stdparolPointId = this.dialogProp.stdparolPointId; | |||
| this.presetData.deviceId = this.dialogProp.deviceId; | |||
| this.presetData.eqpbookId = e.eqpbookId; | |||
| this.presetData.channelId = e.channelId; | |||
| this.PZTData = e; | |||
| listByEqIdAndChannelId({ | |||
| channelCode: e.channelCode, | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| this.listByEqIdAndChanneData = res.data; | |||
| } | |||
| }); | |||
| realtime({ | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| channelCode: e.channelCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| // this.bindingMonitorPointTableData=res.data; | |||
| console.log(res, 1111); | |||
| } | |||
| }); | |||
| let data = { | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| channelId: e.channelId, | |||
| channelCode: e.channelCode, | |||
| }; | |||
| this.handleOpenChannel(data); | |||
| } | |||
| }, | |||
| renderHeader(h, { column, $index }, type) { | |||
| let that = this; | |||
| return h("div", [ | |||
| // 列名称 | |||
| h("span", column.label), | |||
| // 按钮 | |||
| h( | |||
| "el-button", | |||
| { | |||
| props: { | |||
| type: "text", | |||
| size: "small", | |||
| }, | |||
| style: "margin-left: 5px;", | |||
| on: { | |||
| click: function () { | |||
| that.clickButton(type); | |||
| }, | |||
| }, | |||
| }, | |||
| this.$t("share.addTo") | |||
| ), | |||
| ]); | |||
| }, | |||
| clickButton(type) { | |||
| // console.log("我点击了" + type + "的列"); | |||
| this.bindingMonitorPointTableData.push({ | |||
| actionType: "", | |||
| videoTime: "", | |||
| photoCount: "1", | |||
| photoSeper: "", | |||
| }); | |||
| }, | |||
| clickFun() {}, | |||
| init() { | |||
| if (this.typeVideoDialog == 0) { | |||
| this.typeNextBtn = false; | |||
| vl().then((res) => { | |||
| if (res.code == 200) { | |||
| this.dialogPointTree = res.data; | |||
| } | |||
| }); | |||
| } else { | |||
| this.typeNextBtn = true; | |||
| ir().then((res) => { | |||
| if (res.code == 200) { | |||
| this.dialogPointTree = res.data; | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| ptzBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| PZT(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| PZT(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| fiBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| fi(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| fi(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| presetDotBtn(value) { | |||
| this.presetData.presetPosCode = value; | |||
| this.listByEqIdAndChanneData.forEach((item) => { | |||
| if (item.dictValue == this.presetDotNum) { | |||
| this.presetName = item.dictLabel; | |||
| } | |||
| }); | |||
| }, | |||
| // 编辑预置点名称 | |||
| editPresetDot1() { | |||
| let data = { | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| presetDotNum: this.presetDotNum, | |||
| name: this.presetName, | |||
| }; | |||
| goto(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popovervisibleShow() { | |||
| this.popovervisible = false; | |||
| this.newpresetName = ""; | |||
| }, | |||
| setPresetDot1() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.presetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| issue(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.popovervisible = false; | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popoverOpen() { | |||
| this.popovervisible = true; | |||
| }, | |||
| // 设置预设点名称 | |||
| editPresetDot2() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.newpresetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| }, | |||
| // 表格按钮移除 | |||
| removeAction() { | |||
| this.bindingMonitorPointTableData.splice(index, 1); | |||
| }, | |||
| // 保存 | |||
| saveDot1() { | |||
| this.presetData.presetPosName = this.presetName; | |||
| this.presetData.presetActionList = this.bindingMonitorPointTableData; | |||
| bindingPreset(this.presetData).then((res) => { | |||
| console.log(res, 11111); | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.presetData = { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| }; | |||
| this.pointDialogShow = false; | |||
| this.$emit("site_saveDot1", true); | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| handleDrawComplete(scope, shape) { | |||
| setTimeout(() => { | |||
| this.addDot1(shape); | |||
| }, 100); | |||
| }, | |||
| handleChangeIndex(e) { | |||
| this.currentPlayer = e.player; | |||
| // console.log(this.currentPlayer) | |||
| }, | |||
| getDeviceList() { | |||
| getDeviceList(this.patroldeviceCode, this.channelCode).then( | |||
| ({ data }) => { | |||
| this.presetArr = data; | |||
| } | |||
| ); | |||
| }, | |||
| handleOpenChannel(row, next) { | |||
| this.patroldeviceCode = row.patroldeviceCode; | |||
| this.channelCode = row.channelCode; | |||
| this.presetName = ""; | |||
| this.presetNumber = ""; | |||
| this.getDeviceList(); | |||
| this.$nextTick(() => { | |||
| this.$refs[next ? "playerPlayform2" : "playerPlayform"] | |||
| .openChannel({ | |||
| deviceId: 1, | |||
| deviceCode: row.patroldeviceCode, | |||
| channelId: row.channelId, | |||
| channelCode: row.channelCode, | |||
| playerType: "zl", | |||
| }) | |||
| .then(() => {}); | |||
| }); | |||
| }, | |||
| nextBtn() {}, | |||
| }, | |||
| mounted() { | |||
| // this.init(); | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .bindingMonitorPointTree { | |||
| width: 100%; | |||
| height: 37vh; | |||
| overflow-y: scroll; | |||
| } | |||
| .bindingMonitorPointDiv { | |||
| width: 100%; | |||
| height: 40vh; | |||
| // background: red; | |||
| } | |||
| .PTZ-content { | |||
| width: 170px; | |||
| margin: 10px auto; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| } | |||
| .r-ti2-pos { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div { | |||
| position: absolute; | |||
| z-index: 999; | |||
| width: 20px; | |||
| height: 15px; | |||
| cursor: pointer; | |||
| } | |||
| div:first-child { | |||
| top: 32px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(2) { | |||
| top: 50px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(3) { | |||
| top: 77px; | |||
| right: 30px; | |||
| } | |||
| div:nth-child(4) { | |||
| bottom: 56px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(5) { | |||
| bottom: 36px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(6) { | |||
| bottom: 56px; | |||
| right: 100px; | |||
| } | |||
| div:nth-child(7) { | |||
| bottom: 80px; | |||
| left: 30px; | |||
| } | |||
| div:nth-child(8) { | |||
| top: 50px; | |||
| right: 102px; | |||
| } | |||
| } | |||
| .r-ti3 { | |||
| width: 100%; | |||
| display: flex; | |||
| padding-top: 10px; | |||
| -webkit-box-pack: justify; | |||
| justify-content: space-between; | |||
| } | |||
| .r-ti3-d1 { | |||
| width: 76px; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| .r-ti3-d2 { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div:first-child { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| cursor: pointer; | |||
| } | |||
| div:nth-child(2) { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| right: 0; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| } | |||
| .r-ti4 { | |||
| padding-top: 20px; | |||
| img { | |||
| width: 24px; | |||
| height: 24px; | |||
| position: relative; | |||
| top: 6px; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| .popover-footer { | |||
| width: 100%; | |||
| margin-top: 20px; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,452 @@ | |||
| <template> | |||
| <div class="app-container"> | |||
| <el-row :gutter="20"> | |||
| <el-col :span="4"> | |||
| <div class="qurey"> | |||
| <el-input | |||
| :placeholder="$t('point_mang.PleaseEnterTheContent')" | |||
| v-model="filterText" | |||
| class="input-with-select" | |||
| > | |||
| </el-input> | |||
| </div> | |||
| <el-tree | |||
| :data="treeData" | |||
| :props="defaultProps" | |||
| @node-click="handleNodeClick" | |||
| node-key="devicetypeId" | |||
| ref="tree" | |||
| :filter-node-method="filterNode" | |||
| ></el-tree> | |||
| </el-col> | |||
| <el-col :span="20" v-if="devicetypeId"> | |||
| <div> | |||
| <el-button type="primary" @click="addBtn">{{ | |||
| $t("share.addTo") | |||
| }}</el-button> | |||
| <span>(0/200){{ $t("point_mang.tableHeadMsg") }}</span> | |||
| </div> | |||
| <el-table :data="tableData" max-height="700" style="margin-top: 10px"> | |||
| <el-table-column | |||
| prop="date" | |||
| :label="$t('point_mang.index')" | |||
| width="55" | |||
| type="index" | |||
| align="center" | |||
| ></el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.equipmentClassification')" | |||
| :render-header="addRedStar" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-select | |||
| :placeholder=" | |||
| $t('share.PleaseChoose') + | |||
| $t('point_mang.equipmentClassification') | |||
| " | |||
| v-model="scope.row.componentDevicetypeId" | |||
| > | |||
| <el-option | |||
| :label="item.devicetypeName" | |||
| :value="item.devicetypeId" | |||
| v-for="item in DevicetypeIdOptions" | |||
| :key="item.devicetypeId" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.InspectionStandards')" | |||
| :render-header="addRedStar" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| type="textarea" | |||
| :placeholder=" | |||
| $t('share.PleaseChoose') + $t('point_mang.PleaseEnter') | |||
| " | |||
| v-model="scope.row.patrolContent" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column :label="$t('point_mang.dataFormat')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <!-- multiple | |||
| filterable | |||
| allow-create | |||
| default-first-option --> | |||
| <el-select | |||
| v-model="scope.row.mainDevicetypeId" | |||
| :placeholder=" | |||
| $t('share.PleaseChoose') + $t('point_mang.dataFormat') | |||
| " | |||
| > | |||
| <el-option | |||
| v-for="item in options" | |||
| :key="item.dictValue" | |||
| :label="item.dictLabel" | |||
| :value="item.dictValue" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.IntelligentRecognitionType')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <span | |||
| class="intelligenceType" | |||
| @click="intelligenceTypeBtn(scope.row)" | |||
| >{{ | |||
| scope.row.algSubtypeName ? scope.row.algSubtypeName : "设置" | |||
| }}</span | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column :label="$t('share.operate')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-button size="mini" type="primary"> | |||
| {{ $t("share.copy") }} | |||
| </el-button> | |||
| <el-button | |||
| size="mini" | |||
| type="danger" | |||
| @click="handleDelete(scope.row, scope.$index)" | |||
| >{{ $t("share.delete") }}</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <div class="saveBtn"> | |||
| <el-button type="primary" @click="submitForm">{{ | |||
| $t("share.save") | |||
| }}</el-button> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="20" v-if="!devicetypeId"> | |||
| <div style="line-height: 36px">请先选择左侧点位</div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-dialog | |||
| :title="$t('point_mang.SetIntelligentRecognitionType')" | |||
| :visible.sync="dialogVisible" | |||
| width="50%" | |||
| :before-close="handleClose" | |||
| border | |||
| > | |||
| <el-table | |||
| :data="intelligenceTypeData" | |||
| :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" | |||
| default-expand-all | |||
| row-key="id" | |||
| @selection-change="handleSelectionChangeDialog" | |||
| ref="multipleTable" | |||
| > | |||
| <el-table-column | |||
| type="selection" | |||
| width="55" | |||
| align="center" | |||
| ></el-table-column> | |||
| <el-table-column | |||
| type="index" | |||
| width="55" | |||
| align="center" | |||
| :label="$t('point_mang.index')" | |||
| ></el-table-column> | |||
| <!-- <el-table-column | |||
| prop="algName" | |||
| align="center" | |||
| :label="$t('point_mang.AlgorithmName')" | |||
| ></el-table-column> --> | |||
| <el-table-column :label="$t('patrolpoint.AlgorithmName')"> | |||
| <template slot-scope="scope"> | |||
| {{ | |||
| scope.row.algSubtypeName | |||
| ? scope.row.algSubtypeName | |||
| : scope.row.algName | |||
| }} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="patrolContent" | |||
| align="center" | |||
| :label="$t('point_mang.ThresholdUpperLimit')" | |||
| :render-header="addRedStar" | |||
| > | |||
| <!-- <template slot-scope="scope"> | |||
| <el-input></el-input> | |||
| </template> --> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="mainDevicetypeId" | |||
| align="center" | |||
| :label="$t('point_mang.LowerThresholdLimit')" | |||
| :render-header="addRedStar" | |||
| > | |||
| <!-- <template slot-scope="scope"> | |||
| <el-input></el-input> | |||
| </template> --> | |||
| </el-table-column> | |||
| </el-table> | |||
| <span slot="footer" class="dialog-footer"> | |||
| <el-button @click="handleClose">{{ $t("share.cancel") }}</el-button> | |||
| <el-button type="primary" @click="dialogTableOk">{{ | |||
| $t("share.confirm") | |||
| }}</el-button> | |||
| </span> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import { | |||
| getTreeAreaDeviceSelect, | |||
| cilikList, | |||
| devicetype, | |||
| dataFormat, | |||
| add, | |||
| remove, | |||
| algList, | |||
| subtypeList, | |||
| } from "@/api/point/point_mang"; | |||
| export default { | |||
| data() { | |||
| return { | |||
| treeData: [], | |||
| defaultProps: { | |||
| children: "children", | |||
| label: "devicetypeName", | |||
| }, | |||
| tableData: [], | |||
| DevicetypeIdOptions: [], | |||
| options: [], | |||
| value: [], | |||
| dialogVisible: false, | |||
| intelligenceTypeData: [], | |||
| devicetypeId: null, | |||
| dialogTableSelect: [], | |||
| stdpatrolPointId: null, | |||
| dialogTableSelectName: [], | |||
| filterText: null, | |||
| }; | |||
| }, | |||
| watch: { | |||
| filterText(val) { | |||
| this.$refs.tree.filter(val); | |||
| }, | |||
| }, | |||
| created() {}, | |||
| mounted() { | |||
| this.init(); | |||
| devicetype().then((res) => { | |||
| if (res.code == 200) { | |||
| res.data.forEach((item) => { | |||
| if (item.devicetypeId !== 1) { | |||
| this.DevicetypeIdOptions.push(item); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| dataFormat().then((res) => { | |||
| if (res.code == 200) { | |||
| console.log(this.options, res.data); | |||
| res.data.forEach((item) => { | |||
| item.dictValue = String(item.dictValue); | |||
| }); | |||
| this.options = res.data; | |||
| } | |||
| }); | |||
| }, | |||
| methods: { | |||
| filterNode(value, data) { | |||
| if (!value) return true; | |||
| return data.devicetypeName.indexOf(value) !== -1; | |||
| }, | |||
| init(qurey) { | |||
| getTreeAreaDeviceSelect(qurey).then((res) => { | |||
| this.tableData = []; | |||
| if (res.code == 200) { | |||
| res.data.forEach((item) => { | |||
| if (item.devicetypeId !== 1) { | |||
| this.treeData.push(item); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| // 给表头加必填符号* | |||
| addRedStar(h, { column }) { | |||
| return [ | |||
| h("span", { style: "color: red" }, "*"), | |||
| h("span", " " + column.label), | |||
| ]; | |||
| }, | |||
| intelligenceTypeBtn(row) { | |||
| this.stdpatrolPointId = row.stdpatrolPointId; | |||
| subtypeList().then((res0) => { | |||
| if (res0.code == 200) { | |||
| algList().then((res1) => { | |||
| if (res1.code == 200) { | |||
| let list = res1.rows; | |||
| list.forEach((item) => { | |||
| item.children = []; | |||
| item.id = `${item.algId}_${item.algId}`; | |||
| res0.rows.forEach((i) => { | |||
| i.id = i.algSubtypeId; | |||
| if (item.algId == i.algId && item.algName == i.algName) { | |||
| item.children.push(i); | |||
| } | |||
| }); | |||
| }); | |||
| this.intelligenceTypeData = list; | |||
| this.dialogVisible = true; | |||
| this.$nextTick(() => { | |||
| if (row.alarmThreshold) { | |||
| let data = JSON.parse(row.alarmThreshold); | |||
| let idArr = []; | |||
| data.forEach((item) => { | |||
| idArr.push(item.id.split("_")[1]); | |||
| }); | |||
| idArr.forEach((id) => { | |||
| let show = res0.rows.find( | |||
| (item) => item.algSubtypeId == id | |||
| ); | |||
| if (show) { | |||
| this.$refs.multipleTable.toggleRowSelection(show, true); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| // 给表头加必填符号* | |||
| addRedStar(h, { column }) { | |||
| return [ | |||
| h("span", { style: "color: red" }, "*"), | |||
| h("span", " " + column.label), | |||
| ]; | |||
| }, | |||
| // 树点击 | |||
| handleNodeClick(data) { | |||
| console.log(data, 11111111111); | |||
| this.devicetypeId = data.devicetypeId; | |||
| this.tableData = []; | |||
| this.initClickList(data); | |||
| }, | |||
| initClickList(data) { | |||
| cilikList(data.devicetypeId).then((res) => { | |||
| if (res.code == 200) { | |||
| console.log(res, 111); | |||
| this.tableData = res.rows; | |||
| } | |||
| }); | |||
| }, | |||
| addBtn() { | |||
| if (this.tableData.length < 200) { | |||
| this.tableData.push({}); | |||
| } else { | |||
| this.$message({ | |||
| type: "warning", | |||
| message: "最多添加200条数据!", | |||
| }); | |||
| } | |||
| }, | |||
| // 保存 | |||
| submitForm() { | |||
| if (!this.tableData.length) return; | |||
| let flag = this.tableData.every((item) => { | |||
| if (item.componentDevicetypeId && item.patrolContent) { | |||
| return true; | |||
| } else { | |||
| return false; | |||
| } | |||
| }); | |||
| if (flag) { | |||
| add(this.tableData).then((res) => { | |||
| this.initClickList(this.devicetypeId); | |||
| }); | |||
| } else { | |||
| this.$message({ | |||
| type: "warning", | |||
| message: "必填项不能为空!", | |||
| }); | |||
| } | |||
| }, | |||
| // 删除 | |||
| handleDelete(row, index) { | |||
| if (!row.stdpatrolPointId) { | |||
| this.tableData.splice(index, 1); | |||
| } else { | |||
| remove(row.stdpatrolPointId).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| type: "success", | |||
| message: "删除成功!", | |||
| }); | |||
| this.initClickList(row); | |||
| } | |||
| }); | |||
| } | |||
| return; | |||
| }, | |||
| // 智能识别多选 | |||
| handleSelectionChangeDialog(val) { | |||
| this.dialogTableSelect = []; | |||
| this.dialogTableSelectName = []; | |||
| val.forEach((item) => { | |||
| let data = { | |||
| id: `sub_${item.algSubtypeId}`, | |||
| code: item.algSubtypeCode || "", | |||
| upperValue: item.upperValue || "", | |||
| lowerValue: item.lowerValue || "", | |||
| algSubtypeName: item.algSubtypeName || "", | |||
| }; | |||
| this.dialogTableSelect.push(data); | |||
| this.dialogTableSelectName.push(item.algSubtypeName); | |||
| }); | |||
| }, | |||
| dialogTableOk() { | |||
| this.dialogVisible = false; | |||
| console.log(this.dialogTableSelect, this.stdpatrolPointId); | |||
| this.tableData.forEach((item) => { | |||
| if (item.stdpatrolPointId == this.stdpatrolPointId) { | |||
| item.alarmThreshold = JSON.stringify(this.dialogTableSelect); | |||
| item.algSubtypeName = this.dialogTableSelectName.join(","); | |||
| } | |||
| }); | |||
| }, | |||
| handleClose() { | |||
| this.dialogVisible = false; | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .qurey { | |||
| display: flex; | |||
| margin-bottom: 10px; | |||
| ::v-deep.el-button { | |||
| background-color: #46a6ff !important; | |||
| color: #fff !important ; | |||
| } | |||
| } | |||
| .intelligenceType { | |||
| color: rgb(17, 189, 217); | |||
| cursor: pointer; | |||
| } | |||
| .saveBtn { | |||
| text-align: center; | |||
| margin-top: 10px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,549 @@ | |||
| <template> | |||
| <div> | |||
| <div class="page-container"> | |||
| <el-form | |||
| :model="queryParams" | |||
| ref="queryForm" | |||
| :inline="true" | |||
| label-width="75px" | |||
| > | |||
| <el-form-item label="算法类型" prop="taskType"> | |||
| <el-select | |||
| style="width: 150px;" | |||
| v-model="queryParams.taskType" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option | |||
| v-for="item in listPatroltype" | |||
| :key="item.algId" | |||
| :label="item.algName" | |||
| :value="item.algName" | |||
| /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="算法名称" prop="devType"> | |||
| <el-select | |||
| style="width: 150px;" | |||
| v-model="queryParams.devType" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option label="表记识别算法" value="0" /> | |||
| <el-option label="机器人" value="1" /> | |||
| <el-option label="视频" value="2" /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="算法状态" prop="fileStatus"> | |||
| <el-select | |||
| style="width: 150px;" | |||
| v-model="queryParams.fileStatus" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option label="未归档" value="0" /> | |||
| <el-option label="已归档" value="1" /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="时间"> | |||
| <el-date-picker | |||
| style="width: 200px;border-radius: 5px;border:1px" | |||
| v-model="timeValue" | |||
| type="date" | |||
| clearable | |||
| placeholder="选择时间" | |||
| value-format="yyyy-MM-dd HH:mm:ss" | |||
| :picker-options="pickerOptions0" | |||
| > | |||
| </el-date-picker> | |||
| </el-form-item> | |||
| <el-form-item> | |||
| <el-button | |||
| type="primary" | |||
| icon="el-icon-search" | |||
| size="mini" | |||
| @click="handleQuery" | |||
| >查询</el-button | |||
| > | |||
| <el-button icon="el-icon-refresh" size="mini" @click="resetQuery" | |||
| >重置</el-button | |||
| > | |||
| </el-form-item> | |||
| </el-form> | |||
| <div class="table-card" ref="tableCardRef"> | |||
| <el-table | |||
| class="card-table" | |||
| v-loading="loading" | |||
| :data="dataList" | |||
| height="500" | |||
| border | |||
| stripe | |||
| > | |||
| <el-table-column | |||
| label="序号" | |||
| type="index" | |||
| width="50" | |||
| align="center" | |||
| /> | |||
| <el-table-column label="算法标识" align="center" prop="algSubtypeCode" /> | |||
| <el-table-column label="算法名称" align="center" prop="algSubtypeName" /> | |||
| <el-table-column label="算法类型" align="center" prop="algName" /> | |||
| <!-- <el-table-column label="厂商" align="center" prop="createTime" > | |||
| <template slot-scope="scope"> | |||
| <span>**********</span> | |||
| </template> | |||
| </el-table-column> --> | |||
| <el-table-column label="时间" align="center" prop="createTime" /> | |||
| <el-table-column label="操作" align="center"> | |||
| <template slot-scope="scope"> | |||
| <!-- 只有未归档才能修正 --> | |||
| <el-button v-if="scope.row.delFlag !=1" | |||
| size="mini" | |||
| type="primary" | |||
| @click="archiveInfo(scope.row)" | |||
| >启用 | |||
| </el-button> | |||
| <el-button v-else | |||
| style="background-color: #909399;" | |||
| size="mini" | |||
| type="info" | |||
| @click="lookDetail(scope.row)" | |||
| >停用</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <CardPagination | |||
| v-show="total > 0" | |||
| :total="total" | |||
| :page.sync="queryParams.pageNum" | |||
| :limit.sync="queryParams.pageSize" | |||
| @pagination="getList" | |||
| /> | |||
| </div> | |||
| </div> | |||
| <el-dialog | |||
| title="归档" | |||
| id="dialoga" | |||
| :visible.sync="showContrastEdit" | |||
| :close-on-click-modal="false" | |||
| :close-on-press-escape="false" | |||
| :destroy-on-close="true" | |||
| append-to-body | |||
| custom-class="card-dialog card-page card-dialog-height-auto" | |||
| > | |||
| <el-form | |||
| ref="contrastForm" | |||
| :model="contrastForm" | |||
| :rules="contrastRules" | |||
| label-width="100px" | |||
| label-position="top" | |||
| > | |||
| <el-form-item label="审核人" prop="chechkPerson"> | |||
| <el-input | |||
| v-model="contrastForm.chechkPerson" | |||
| placeholder="请输入审核人" | |||
| /> | |||
| </el-form-item> | |||
| <el-form-item label="巡视结论" prop="taskResult"> | |||
| <el-input | |||
| style="resize: none" | |||
| type="textarea" | |||
| :rows="3" | |||
| v-model="contrastForm.taskResult" | |||
| placeholder="请输入巡视结论" | |||
| /> | |||
| </el-form-item> | |||
| </el-form> | |||
| <div slot="footer" class="dialog-footer"> | |||
| <el-button | |||
| class="card-dialog-cancel-btn" | |||
| @click="() => (showContrastEdit = false)" | |||
| >取 消</el-button | |||
| > | |||
| <el-button | |||
| type="primary" | |||
| class="card-dialog-sure-btn" | |||
| :loading="isArchiving" | |||
| :disable="isLock" | |||
| @click="handleArchiveClicked" | |||
| >确 定</el-button | |||
| > | |||
| </div> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import { | |||
| listPartrolResult, | |||
| } from "@/api/algorithmConfiguration/index"; | |||
| import { | |||
| partrolResultArchive, | |||
| } from "@/api/inspectionDataManage/inspectionArchive"; | |||
| // import InspectionArchiveContrastDialog from "@/views/components/InspectionArchiveContrastDialog.vue"; | |||
| import debounce from "lodash.debounce"; | |||
| import { listPatroltype } from "@/api/algorithmConfiguration/index"; | |||
| import { openDialog } from "../common.js"; | |||
| import CardPagination from "@/components/CardPagination/index.vue"; | |||
| import CardBox from "@/components/cardBox.vue"; | |||
| export default { | |||
| name: "InspectionArchive", | |||
| components: { | |||
| // InspectionArchiveContrastDialog, | |||
| CardPagination, | |||
| CardBox }, | |||
| dicts: [ | |||
| "patrol_result_value_type", | |||
| "patrol_result_recognition_type", | |||
| "patrol_result_valid_type", | |||
| // "patrol_type", | |||
| "device_type", | |||
| ], | |||
| data() { | |||
| return { | |||
| pickerOptions0: { | |||
| disabledDate(time) { | |||
| return time.getTime() < Date.now() - 8.64e7; | |||
| } | |||
| }, | |||
| timeValue:'', | |||
| // 遮罩层 | |||
| loading: true, | |||
| isArchiving: false, // 正在归档 | |||
| isLock: false, | |||
| // 总条数 | |||
| total: 0, | |||
| // 数据 | |||
| dataList: [], | |||
| //时间范围 | |||
| dateRange: [], | |||
| dateRangePickerOptions: { | |||
| disabledDate(selectDate) { | |||
| return new Date().getTime() < selectDate.getTime(); | |||
| }, | |||
| }, | |||
| // 查询参数 | |||
| queryParams: { | |||
| pageNum: 1, | |||
| pageSize: 10, | |||
| taskType: null, | |||
| devType: null, | |||
| fileStatus: null, | |||
| }, | |||
| // 是否显示对比数据 | |||
| showContrast: false, | |||
| // 显示编辑修正 | |||
| showContrastEdit: false, | |||
| contrastForm: { | |||
| chechkPerson: null, | |||
| taskResult: null, | |||
| }, | |||
| contrastRules: { | |||
| chechkPerson: [ | |||
| { required: true, message: "请输入审核人", trigger: "change" }, | |||
| ], | |||
| taskResult: [ | |||
| { required: true, message: "请输入巡视结论", trigger: "change" }, | |||
| ], | |||
| }, | |||
| // 最新详细信息 | |||
| newInfo: null, | |||
| // 原始详细信息 | |||
| originalInfo: null, | |||
| listPatroltype: [], | |||
| }; | |||
| }, | |||
| created() { | |||
| // 防抖 | |||
| this.setTableHeight = debounce(this.setTableHeight, 300); | |||
| window.addEventListener("resize", this.setTableHeight); | |||
| this.getlistPatroltype(); | |||
| this.getList(); | |||
| }, | |||
| mounted() { | |||
| this.setTableHeight(); | |||
| }, | |||
| destroyed() { | |||
| this.setTableHeight.cancel(); | |||
| window.removeEventListener("resize", this.setTableHeight); | |||
| }, | |||
| methods: { | |||
| getlistPatroltype() { | |||
| listPatroltype().then((res) => { | |||
| this.listPatroltype = res.rows; | |||
| }); | |||
| }, | |||
| // 获取巡检任务 | |||
| getPatrolTypeStr(type) { | |||
| const element = this.listPatroltype.find( | |||
| (item) => item.patrolTypeCode == type | |||
| ); | |||
| if (element) { | |||
| return element.patrolTypeName; | |||
| } | |||
| return ""; | |||
| }, | |||
| setTableHeight() { | |||
| this.tableHeight = this.$refs.tableCardRef.clientHeight - 40; | |||
| }, | |||
| /** 获取数据列表 */ | |||
| getList() { | |||
| this.loading = true; | |||
| const params = { ...this.queryParams }; | |||
| // 拍摄时间筛选范围 | |||
| if (this.dateRange && this.dateRange.length === 2) { | |||
| params.beginTime = this.dateRange[0]; | |||
| params.endTime = this.dateRange[1]; | |||
| } | |||
| listPartrolResult(params).then((response) => { | |||
| this.dataList = response.rows; | |||
| this.total = response.total; | |||
| this.loading = false; | |||
| }); | |||
| }, | |||
| /** 搜索按钮操作 */ | |||
| handleQuery() { | |||
| this.queryParams.pageNum = 1; | |||
| this.getList(); | |||
| }, | |||
| /** 重置按钮操作 */ | |||
| resetQuery() { | |||
| this.dateRange = []; | |||
| this.resetForm("queryForm"); | |||
| this.handleQuery(); | |||
| }, | |||
| // 设备类型 | |||
| getDeviceTypeStr(dataType) { | |||
| switch (dataType) { | |||
| case "0": | |||
| return "无人机"; | |||
| case "1": | |||
| return "机器人"; | |||
| case "2": | |||
| return "视频"; | |||
| } | |||
| }, | |||
| // 修正 | |||
| archiveInfo(info) { | |||
| this.contrastForm = { | |||
| lineId: info.lineId, | |||
| chechkPerson: null, | |||
| taskResult: null, | |||
| }; | |||
| this.resetForm("contrastForm"); | |||
| this.showContrastEdit = true; | |||
| }, | |||
| // 查看详情 | |||
| lookDetail(info) { | |||
| this.$router.push({ | |||
| name: "cardInspectionArchivePointInfo", | |||
| params: { | |||
| id: info.lineId, | |||
| }, | |||
| }); | |||
| // // 开发 | |||
| // if (process.env.VUE_APP_DIALOG == "true") { | |||
| // this.$router.push({ | |||
| // name: "cardInspectionArchivePointInfo", | |||
| // params: { | |||
| // id: info.lineId, | |||
| // }, | |||
| // }); | |||
| // } else { | |||
| // sessionStorage.setItem("archiveLineId", JSON.stringify(info.lineId)); | |||
| // openDialog({ | |||
| // sourceCardId: "wuhan@videoMonitor-card-45", | |||
| // targetCardId: "wuhan@videoMonitor-card-46", | |||
| // dialogTitle: "巡视结果归档详情", | |||
| // }); | |||
| // } | |||
| }, | |||
| // 归档 | |||
| handleArchiveClicked() { | |||
| this.$refs["contrastForm"].validate((valid) => { | |||
| if (valid) { | |||
| const params = { ...this.contrastForm }; | |||
| this.isArchiving = true; | |||
| this.isLock = true; | |||
| partrolResultArchive(params) | |||
| .then((res) => { | |||
| this.$modal.msgSuccess("归档成功"); | |||
| this.showContrastEdit = false; | |||
| this.getList(); | |||
| }) | |||
| .finally(() => { | |||
| this.isArchiving = false; | |||
| this.isLock = false; | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .page-content { | |||
| width: 100%; | |||
| height: 856px; | |||
| } | |||
| .page-container { | |||
| height: 100%; | |||
| display: flex; | |||
| flex-direction: column; | |||
| } | |||
| .query-card { | |||
| margin-bottom: 15px; | |||
| ::v-deep .el-form-item { | |||
| margin-bottom: 0; | |||
| } | |||
| } | |||
| .table-card { | |||
| flex: 1; | |||
| height: 0; | |||
| ::v-deep .el-card__body { | |||
| height: 100%; | |||
| } | |||
| } | |||
| // #dialoga { | |||
| // height: 39vh; | |||
| // overflow: auto; | |||
| // } | |||
| </style> | |||
| <style> | |||
| .vue-treeselect__control { | |||
| background-color: rgb(0, 1, 1, 0) !important; | |||
| border: 1px solid #40486a !important; | |||
| } | |||
| .el-tree-node__content:hover { | |||
| /* background: RGBA(23, 37, 51, 1) !important; */ | |||
| } | |||
| .el-tree-node:focus > .el-tree-node__content { | |||
| /* background-color: RGBA(23, 37, 51, 1) !important; */ | |||
| } | |||
| .el-picker-panel { | |||
| /* background: #202f3e !important; | |||
| border: 1px solid #40486a !important; */ | |||
| } | |||
| .el-picker-panel__footer { | |||
| /* background: #202f3e !important; */ | |||
| } | |||
| .el-date-picker__time-header { | |||
| border-bottom: 1px solid #40486a !important; | |||
| } | |||
| .el-date-table th { | |||
| border-bottom: 1px solid #40486a !important; | |||
| } | |||
| .el-picker-panel__footer { | |||
| border-top: 1px solid #40486a !important; | |||
| } | |||
| .el-popper[x-placement^="top"] .popper__arrow::after { | |||
| border-top-color: #40486a !important; | |||
| } | |||
| .el-time-panel__footer { | |||
| border-top: 1px solid #40486a !important; | |||
| } | |||
| .el-button--medium, | |||
| .el-button.is-plain { | |||
| background-color: #247382 !important; | |||
| border: 1px solid #247382 !important; | |||
| } | |||
| .el-time-panel { | |||
| /* background-color: #202f3e !important; | |||
| border: 1px solid #40486a !important; */ | |||
| } | |||
| .el-date-table td.disabled div { | |||
| background: RGBA(23, 37, 51, 1) !important; | |||
| } | |||
| .el-popper[x-placement^="bottom"] .popper__arrow::after { | |||
| border-bottom-color: #40486a !important; | |||
| } | |||
| .el-input-number--medium .el-input-number__increase { | |||
| background-color: rgb(1, 1, 1, 0) !important; | |||
| } | |||
| .el-transfer-panel { | |||
| /* background-color: #202f3e !important; | |||
| border-color: #40486a !important; */ | |||
| /* border: 1px solid red; */ | |||
| width: 300px !important; | |||
| } | |||
| .el-transfer-panel__header { | |||
| /* background-color: #202f3e !important; | |||
| border-color: #40486a !important; */ | |||
| } | |||
| .el-step__head.is-finish { | |||
| color: #37cbd6 !important; | |||
| border-color: #37cbd6 !important; | |||
| } | |||
| .el-message-box { | |||
| /* background-color: #202f3e !important; | |||
| border: 1px solid #40486a !important; */ | |||
| } | |||
| .el-button--small { | |||
| background-color: #247382 !important; | |||
| border: none !important; | |||
| } | |||
| .el-step__title.is-finish { | |||
| color: #37cbd6 !important; | |||
| } | |||
| .el-input__inner { | |||
| border-color: #40486a !important; | |||
| } | |||
| .el-select-dropdown { | |||
| /* background-color: #202f3e !important; | |||
| border: 1px solid #40486a !important; */ | |||
| } | |||
| .el-select-dropdown__item.hover, | |||
| .el-select-dropdown__item:hover { | |||
| background-color: RGBA(23, 37, 51, 1) !important; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,534 @@ | |||
| <template> | |||
| <div class="image-annotation-container"> | |||
| <!-- 控制面板 --> | |||
| <div class="control-panel"> | |||
| <button @click="setMode('point')" :class="{ active: mode === 'point' }"> | |||
| 绘制点 | |||
| </button> | |||
| <button @click="setMode('rect')" :class="{ active: mode === 'rect' }"> | |||
| 绘制矩形 | |||
| </button> | |||
| <button @click="clearAll" class="clear-btn">清除所有</button> | |||
| <div class="config-options" v-if="mode"> | |||
| <label v-if="mode === 'point'"> | |||
| 点大小: | |||
| <input type="range" v-model.number="pointSize" min="3" max="15" /> | |||
| </label> | |||
| <label v-if="mode === 'rect'"> | |||
| 线宽: | |||
| <input type="range" v-model.number="lineWidth" min="1" max="10" /> | |||
| </label> | |||
| <!-- <label> | |||
| 颜色: <input type="color" v-model="drawColor"> | |||
| </label> --> | |||
| </div> | |||
| </div> | |||
| <!-- 图片和画布容器 --> | |||
| <div class="image-wrapper" ref="imageWrapper"> | |||
| <img | |||
| :src="imageSrc" | |||
| alt="标注图片" | |||
| ref="image" | |||
| @load="initCanvas" | |||
| @mousedown="handleMouseDown" | |||
| @mousemove="handleMouseMove" | |||
| @mouseup="handleMouseUp" | |||
| @mouseleave="handleMouseUp" | |||
| /> | |||
| <canvas ref="canvas"></canvas> | |||
| </div> | |||
| <!-- 标注信息面板 --> | |||
| <!-- <div class="annotation-panel"> | |||
| <h3>标注信息 (共{{ annotations.length }}个)</h3> | |||
| <div class="annotation-list"> | |||
| <div | |||
| v-for="(annotation, index) in annotations" | |||
| :key="index" | |||
| class="annotation-item" | |||
| :class="annotation.type" | |||
| @click="highlightAnnotation(index)" | |||
| > | |||
| <div class="annotation-header"> | |||
| <span class="annotation-type"> | |||
| {{ annotation.type === 'point' ? '点' : '矩形' }} {{ index + 1 }} | |||
| </span> | |||
| <button @click.stop="removeAnnotation(index)" class="small-btn"> | |||
| 删除 | |||
| </button> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> --> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| export default { | |||
| name: "ImageAnnotation", | |||
| props: { | |||
| imageSrc: { | |||
| type: String, | |||
| required: true, | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| mode: null, // 当前模式: 'point' 或 'rect' | |||
| isDrawing: false, // 是否正在绘制 | |||
| startX: 0, // 绘制起点X | |||
| startY: 0, // 绘制起点Y | |||
| annotations: [], // 所有标注 | |||
| drawColor: "red", // 绘制颜色 | |||
| pointSize: 6, // 点大小 | |||
| lineWidth: 2, // 线宽 | |||
| canvas: null, // canvas元素 | |||
| ctx: null, // canvas上下文 | |||
| imgElement: null, // img元素 | |||
| all_data: [], | |||
| }; | |||
| }, | |||
| watch: { | |||
| imageSrc() { | |||
| this.clearAll(); | |||
| this.$nextTick(() => { | |||
| if (this.imgElement.complete) { | |||
| this.initCanvas(); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| mounted() { | |||
| // this.annotations = []; | |||
| // this.all_data = []; | |||
| this.imgElement = this.$refs.image; | |||
| this.canvas = this.$refs.canvas; | |||
| this.ctx = this.canvas.getContext("2d"); | |||
| // 如果图片已经加载完成 | |||
| if (this.imgElement.complete) { | |||
| this.initCanvas(); | |||
| } | |||
| }, | |||
| methods: { | |||
| // 初始化画布 | |||
| initCanvas() { | |||
| this.canvas.width = this.imgElement.width; | |||
| this.canvas.height = this.imgElement.height; | |||
| localStorage.setItem( | |||
| "imgElement", | |||
| JSON.stringify({ | |||
| width: this.imgElement.width, | |||
| height: this.imgElement.height, | |||
| }) | |||
| ); | |||
| this.redrawAll(); | |||
| }, | |||
| // 设置绘制模式 | |||
| setMode(mode) { | |||
| this.mode = mode; | |||
| this.imgElement.ondragstart = function () { | |||
| return false; | |||
| }; | |||
| }, | |||
| // 鼠标按下事件 | |||
| handleMouseDown(e) { | |||
| if (!this.mode || e.button !== 0) return; // 只响应左键 | |||
| const rect = this.imgElement.getBoundingClientRect(); | |||
| this.startX = e.clientX - rect.left; | |||
| this.startY = e.clientY - rect.top; | |||
| if (this.mode === "point") { | |||
| this.addPoint(this.startX, this.startY); | |||
| } else if (this.mode === "rect") { | |||
| this.isDrawing = true; | |||
| } | |||
| }, | |||
| // 鼠标移动事件 | |||
| handleMouseMove(e) { | |||
| if (!this.isDrawing) return; | |||
| const rect = this.imgElement.getBoundingClientRect(); | |||
| const currentX = e.clientX - rect.left; | |||
| const currentY = e.clientY - rect.top; | |||
| // 清除并重绘 | |||
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |||
| this.redrawAll(); | |||
| // 绘制当前矩形 | |||
| this.drawRect( | |||
| this.startX, | |||
| this.startY, | |||
| currentX - this.startX, | |||
| currentY - this.startY, | |||
| this.drawColor, | |||
| this.lineWidth, | |||
| true // 临时绘制 | |||
| ); | |||
| }, | |||
| // 鼠标释放事件 | |||
| handleMouseUp(e) { | |||
| if (!this.isDrawing) return; | |||
| this.isDrawing = false; | |||
| const rect = this.imgElement.getBoundingClientRect(); | |||
| const endX = e.clientX - rect.left; | |||
| const endY = e.clientY - rect.top; | |||
| // 确保矩形有一定大小 | |||
| if ( | |||
| Math.abs(endX - this.startX) > 5 && | |||
| Math.abs(endY - this.startY) > 5 | |||
| ) { | |||
| this.addRectangle( | |||
| this.startX, | |||
| this.startY, | |||
| endX - this.startX, | |||
| endY - this.startY, | |||
| endX, | |||
| endY | |||
| ); | |||
| } | |||
| this.redrawAll(); | |||
| }, | |||
| // 添加点 | |||
| addPoint(x, y) { | |||
| var point_object = { firstX: Math.round(x), firstY: Math.round(y) }; | |||
| this.all_data.push(point_object); | |||
| localStorage.setItem("drawData", JSON.stringify(this.all_data)); | |||
| this.annotations.push({ | |||
| type: "point", | |||
| x, | |||
| y, | |||
| color: this.drawColor, | |||
| size: this.pointSize, | |||
| }); | |||
| this.redrawAll(); | |||
| }, | |||
| // 添加矩形 | |||
| addRectangle(x, y, width, height, endX, endY) { | |||
| // 存储矩形的起点和终点 | |||
| var point_object = { | |||
| firstX: Math.round(x), | |||
| firstY: Math.round(y), | |||
| secondX: Math.round(endX), | |||
| secondY: Math.round(endY), | |||
| }; | |||
| this.all_data.push(point_object); | |||
| // 存储数据给父组件用 | |||
| localStorage.setItem("drawData", JSON.stringify(this.all_data)); | |||
| this.annotations.push({ | |||
| type: "rect", | |||
| x, | |||
| y, | |||
| width, | |||
| height, | |||
| color: this.drawColor, | |||
| lineWidth: this.lineWidth, | |||
| }); | |||
| }, | |||
| // 绘制点 | |||
| drawPoint(x, y, color, size) { | |||
| this.ctx.fillStyle = color; | |||
| this.ctx.beginPath(); | |||
| this.ctx.arc(x, y, size, 0, 2 * Math.PI); | |||
| this.ctx.fill(); | |||
| // 添加中心点 | |||
| this.ctx.fillStyle = "red"; | |||
| this.ctx.beginPath(); | |||
| this.ctx.arc(x, y, size / 2, 0, 2 * Math.PI); | |||
| this.ctx.fill(); | |||
| }, | |||
| // 绘制矩形 | |||
| drawRect(x, y, width, height, color, lineWidth, isTemporary = false) { | |||
| this.ctx.strokeStyle = color; | |||
| this.ctx.lineWidth = lineWidth; | |||
| this.ctx.strokeRect(x, y, width, height); | |||
| if (!isTemporary) { | |||
| // 半透明填充 | |||
| this.ctx.fillStyle = "rgba(0, 0, 255, 0)"; //不填充 | |||
| // this.ctx.fillStyle = color.replace(')', ', 0)').replace('rgb', 'rgba'); | |||
| this.ctx.fillRect(x, y, width, height); | |||
| } | |||
| }, | |||
| // 重绘所有标注 | |||
| redrawAll() { | |||
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |||
| this.annotations.forEach((annotation) => { | |||
| if (annotation.type === "point") { | |||
| this.drawPoint( | |||
| annotation.x, | |||
| annotation.y, | |||
| annotation.color, | |||
| annotation.size | |||
| ); | |||
| } else { | |||
| this.drawRect( | |||
| annotation.x, | |||
| annotation.y, | |||
| annotation.width, | |||
| annotation.height, | |||
| annotation.color, | |||
| annotation.lineWidth | |||
| ); | |||
| } | |||
| }); | |||
| }, | |||
| // 删除标注 | |||
| removeAnnotation(index) { | |||
| this.all_data = []; | |||
| this.annotations.splice(index, 1); | |||
| this.redrawAll(); | |||
| }, | |||
| // 高亮标注 | |||
| highlightAnnotation(index) { | |||
| const annotation = this.annotations[index]; | |||
| // 先清除画布 | |||
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |||
| // 绘制其他标注(半透明) | |||
| this.annotations.forEach((item, i) => { | |||
| if (i !== index) { | |||
| const alphaColor = item.color | |||
| .replace(")", ", 0.3)") | |||
| .replace("rgb", "rgba"); | |||
| if (item.type === "point") { | |||
| this.drawPoint(item.x, item.y, alphaColor, item.size); | |||
| } else { | |||
| this.drawRect( | |||
| item.x, | |||
| item.y, | |||
| item.width, | |||
| item.height, | |||
| alphaColor, | |||
| item.lineWidth | |||
| ); | |||
| } | |||
| } | |||
| }); | |||
| // 绘制选中的标注(高亮) | |||
| if (annotation.type === "point") { | |||
| this.drawPoint( | |||
| annotation.x, | |||
| annotation.y, | |||
| annotation.color, | |||
| annotation.size * 1.5 | |||
| ); | |||
| } else { | |||
| this.drawRect( | |||
| annotation.x, | |||
| annotation.y, | |||
| annotation.width, | |||
| annotation.height, | |||
| annotation.color, | |||
| annotation.lineWidth * 2 | |||
| ); | |||
| } | |||
| // 3秒后恢复 | |||
| setTimeout(() => { | |||
| this.redrawAll(); | |||
| }, 3000); | |||
| }, | |||
| // 清除所有标注 | |||
| clearAll() { | |||
| this.annotations = []; | |||
| this.all_data = []; | |||
| this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); | |||
| }, | |||
| // 导出标注数据 | |||
| exportAnnotations() { | |||
| const data = { | |||
| imageWidth: this.imgElement.width, | |||
| imageHeight: this.imgElement.height, | |||
| annotations: this.annotations, | |||
| }; | |||
| return data; | |||
| }, | |||
| // 导入标注数据 | |||
| importAnnotations(data) { | |||
| if ( | |||
| data.imageWidth === this.imgElement.width && | |||
| data.imageHeight === this.imgElement.height | |||
| ) { | |||
| this.annotations = data.annotations; | |||
| this.redrawAll(); | |||
| return true; | |||
| } | |||
| return false; | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style scoped> | |||
| .image-annotation-container { | |||
| font-family: Arial, sans-serif; | |||
| max-width: 1000px; | |||
| height: 550px; | |||
| margin: 0 auto; | |||
| padding: 20px; | |||
| overflow: scroll; | |||
| } | |||
| .control-panel { | |||
| margin: 15px 0; | |||
| padding: 15px; | |||
| /* background: #f5f5f5; */ | |||
| border-radius: 5px; | |||
| display: flex; | |||
| flex-wrap: wrap; | |||
| gap: 10px; | |||
| align-items: center; | |||
| border: 1px solid #555; | |||
| } | |||
| button { | |||
| padding: 8px 15px; | |||
| background: #4caf50; | |||
| color: white; | |||
| border: none; | |||
| border-radius: 4px; | |||
| cursor: pointer; | |||
| transition: background 0.2s; | |||
| } | |||
| button:hover { | |||
| background: #45a049; | |||
| } | |||
| button.active { | |||
| background: #2e7d32; | |||
| box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.2); | |||
| } | |||
| .clear-btn { | |||
| background: #f44336; | |||
| } | |||
| .clear-btn:hover { | |||
| background: #d32f2f; | |||
| } | |||
| .small-btn { | |||
| padding: 3px 8px; | |||
| font-size: 12px; | |||
| background: #f44336; | |||
| } | |||
| .config-options { | |||
| display: flex; | |||
| gap: 15px; | |||
| align-items: center; | |||
| margin-left: auto; | |||
| } | |||
| .config-options label { | |||
| display: flex; | |||
| align-items: center; | |||
| gap: 5px; | |||
| font-size: 14px; | |||
| } | |||
| .image-wrapper { | |||
| position: relative; | |||
| display: inline-block; | |||
| margin-bottom: 20px; | |||
| border: 1px solid #555; | |||
| } | |||
| img { | |||
| display: block; | |||
| max-width: 100%; | |||
| max-height: 100%; | |||
| } | |||
| canvas { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| pointer-events: none; | |||
| /* width: 100%; | |||
| height: 100%; */ | |||
| /* width:780px; | |||
| height:445px; */ | |||
| } | |||
| .annotation-panel { | |||
| border: 1px solid #ddd; | |||
| padding: 15px; | |||
| border-radius: 5px; | |||
| background: #f9f9f9; | |||
| } | |||
| .annotation-list { | |||
| max-height: 300px; | |||
| overflow-y: auto; | |||
| margin-top: 10px; | |||
| } | |||
| .annotation-item { | |||
| padding: 10px; | |||
| margin-bottom: 8px; | |||
| background: white; | |||
| border-radius: 4px; | |||
| border-left: 4px solid #4caf50; | |||
| cursor: pointer; | |||
| transition: transform 0.2s, box-shadow 0.2s; | |||
| } | |||
| .annotation-item:hover { | |||
| transform: translateX(3px); | |||
| box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); | |||
| } | |||
| .annotation-item.point { | |||
| border-left-color: #2196f3; | |||
| } | |||
| .annotation-item.rect { | |||
| border-left-color: #ff9800; | |||
| } | |||
| .annotation-header { | |||
| display: flex; | |||
| justify-content: space-between; | |||
| align-items: center; | |||
| margin-bottom: 5px; | |||
| } | |||
| .annotation-type { | |||
| font-weight: bold; | |||
| } | |||
| .annotation-details { | |||
| font-size: 14px; | |||
| color: #555; | |||
| } | |||
| .empty-message { | |||
| color: #777; | |||
| font-style: italic; | |||
| text-align: center; | |||
| padding: 10px; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,410 @@ | |||
| <template> | |||
| <el-dialog | |||
| :title="alertTitle" | |||
| :visible.sync="visible" | |||
| width="55%" | |||
| @close="handleClose" | |||
| :close-on-click-modal="false" | |||
| append-to-body | |||
| > | |||
| <el-row class="card-page"> | |||
| <el-form | |||
| :model="queryParams" | |||
| ref="queryForm" | |||
| :inline="true" | |||
| label-width="75px" | |||
| > | |||
| <el-form-item label="算法类型" prop="taskType"> | |||
| <el-select | |||
| style="width: 150px" | |||
| v-model="queryParams.taskType" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option | |||
| v-for="item in listPatroltype" | |||
| :key="item.algId" | |||
| :label="item.algName" | |||
| :value="item.algName" | |||
| /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="算法名称" prop="devType"> | |||
| <el-select | |||
| style="width: 150px" | |||
| v-model="queryParams.devType" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option label="表记识别算法" value="0" /> | |||
| <el-option label="机器人" value="1" /> | |||
| <el-option label="视频" value="2" /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="算法状态" prop="fileStatus"> | |||
| <el-select | |||
| style="width: 150px" | |||
| v-model="queryParams.fileStatus" | |||
| placeholder="全部" | |||
| filterable | |||
| clearable | |||
| popper-class="card-select-dropdown" | |||
| > | |||
| <el-option label="未归档" value="0" /> | |||
| <el-option label="已归档" value="1" /> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="时间"> | |||
| <el-date-picker | |||
| style="width: 200px; border-radius: 5px; border: 1px" | |||
| v-model="timeValue" | |||
| type="date" | |||
| clearable | |||
| placeholder="选择时间" | |||
| value-format="yyyy-MM-dd HH:mm:ss" | |||
| :picker-options="pickerOptions0" | |||
| > | |||
| </el-date-picker> | |||
| </el-form-item> | |||
| <el-form-item> | |||
| <el-button | |||
| type="primary" | |||
| icon="el-icon-search" | |||
| size="mini" | |||
| @click="handleQuery" | |||
| >查询</el-button | |||
| > | |||
| <el-button icon="el-icon-refresh" size="mini" @click="resetQuery" | |||
| >重置</el-button | |||
| > | |||
| </el-form-item> | |||
| </el-form> | |||
| <el-form label-width="0px" :model="form" ref="ruleForm"> | |||
| <el-col :span="24"> | |||
| <el-table | |||
| v-loading="loading" | |||
| :data="algList" | |||
| row-key="id" | |||
| border | |||
| default-expand-all | |||
| height="400px" | |||
| :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" | |||
| > | |||
| <el-table-column | |||
| type="selection" | |||
| align="center" | |||
| width="50" | |||
| v-if="!disableCheck" | |||
| > | |||
| <template #header> | |||
| <span></span> | |||
| </template> | |||
| <template slot-scope="scope"> | |||
| <el-checkbox | |||
| :indeterminate="scope.row.isIndeterminate" | |||
| v-model="scope.row.checked" | |||
| @change="handleRowCheckedChange(scope.row)" | |||
| ></el-checkbox> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| type="index" | |||
| align="center" | |||
| label="序号" | |||
| width="50" | |||
| /> | |||
| <el-table-column | |||
| prop="name" | |||
| header-align="center" | |||
| label="算法名称" | |||
| min-width="180" | |||
| > | |||
| </el-table-column> | |||
| <el-table-column label="算法类型" align="center" prop="name" /> | |||
| <el-table-column label="时间" align="center" prop="name" /> | |||
| <el-table-column prop="upperValue" align="center" width="180"> | |||
| <template #header> | |||
| <div>阈值上限 <span style="color: red">*</span></div> | |||
| </template> | |||
| <template slot-scope="scope"> | |||
| <el-form-item | |||
| style="margin-top: 0; margin-bottom: 0" | |||
| v-if="scope.row.upperFlag" | |||
| :prop="'algList[' + scope.$index + '].upperValue'" | |||
| :rules="{ | |||
| required: | |||
| scope.row.upperFlag && scope.row.checked ? true : false, | |||
| message: '必填', | |||
| trigger: 'blur', | |||
| }" | |||
| > | |||
| <el-input | |||
| v-model="scope.row.upperValue" | |||
| :disabled="!scope.row.checked" | |||
| ></el-input> | |||
| <span slot="error"> </span> | |||
| </el-form-item> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column prop="lowerValue" align="center" width="180"> | |||
| <template #header> | |||
| <div>阈值下限 <span style="color: red">*</span></div> | |||
| </template> | |||
| <template slot-scope="scope"> | |||
| <el-form-item | |||
| style="margin-top: 0; margin-bottom: 0" | |||
| v-if="scope.row.lowerFlag" | |||
| :prop="'algList[' + scope.$index + '].lowerValue'" | |||
| :rules="{ | |||
| required: | |||
| scope.row.lowerFlag && scope.row.checked ? true : false, | |||
| message: '必填', | |||
| trigger: 'blur', | |||
| }" | |||
| > | |||
| <el-input | |||
| v-model="scope.row.lowerValue" | |||
| :disabled="!scope.row.checked" | |||
| ></el-input> | |||
| <span slot="error"> </span> | |||
| </el-form-item> | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| </el-col> | |||
| </el-form> | |||
| </el-row> | |||
| <span slot="footer" class="dialog-footer card-page"> | |||
| <el-button @click="eventOk" :disabled="loading" type="primary" | |||
| >确定</el-button | |||
| > | |||
| <el-button @click="visible = false">取消</el-button> | |||
| </span> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import { getAlgList, getAlgPartType } from "@/api/basedata/area/area"; | |||
| import linq from "linq"; | |||
| export default { | |||
| props: { | |||
| show: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| // 数据源json格式 | |||
| alarmThreshold: { | |||
| type: String, | |||
| default: "", | |||
| }, | |||
| // 引用选择框 | |||
| disableCheck: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| // 列表只展示已选算法 | |||
| filterCheckedAlgs: { | |||
| type: Boolean, | |||
| default: false, | |||
| }, | |||
| }, | |||
| watch: { | |||
| show(newVal) { | |||
| this.visible = newVal; | |||
| if (newVal === true) { | |||
| this.loadData(); | |||
| } | |||
| }, | |||
| }, | |||
| data() { | |||
| return { | |||
| loading: false, | |||
| form: { | |||
| algList: [], | |||
| }, | |||
| visible: false, | |||
| algList: [] /* 算法类型 */, | |||
| alertTitle: "设置智能识别类型" /* 弹窗标题 */, | |||
| rules: { | |||
| algId: [{ required: true, message: "必选", trigger: "blur" }], | |||
| algSubtypeId: [{ required: true, message: "必选", trigger: "blur" }], | |||
| upperValue: [{ required: true, message: "必选", trigger: "blur" }], | |||
| lowerValue: [{ required: true, message: "必选", trigger: "blur" }], | |||
| }, | |||
| // 查询参数 | |||
| queryParams: { | |||
| pageNum: 1, | |||
| pageSize: 10, | |||
| taskType: null, | |||
| devType: null, | |||
| fileStatus: null, | |||
| }, | |||
| }; | |||
| }, | |||
| created() {}, | |||
| computed: {}, | |||
| methods: { | |||
| loadData() { | |||
| this.loading = true; | |||
| //算法小类 | |||
| getAlgPartType() | |||
| .then((res) => { | |||
| // 如果开启了已选过滤 | |||
| if (this.filterCheckedAlgs) { | |||
| //筛选数据 | |||
| if (this.alarmThreshold.length > 0) { | |||
| const alarmThreshold = JSON.parse(this.alarmThreshold); | |||
| const chooseIds = linq | |||
| .from(alarmThreshold) | |||
| .select((x) => x.id.replace("sub_", "")) | |||
| .toArray(); | |||
| res.rows = res.rows.filter((x) => | |||
| chooseIds.includes(x.algSubtypeId.toString()) | |||
| ); | |||
| } | |||
| } | |||
| res.rows.forEach((x) => { | |||
| x.hasChildren = false; | |||
| x.children = []; | |||
| }); | |||
| this.loading = false; | |||
| this.loading = true; | |||
| //算法大类 | |||
| getAlgList() | |||
| .then((res1) => { | |||
| const treeData = []; | |||
| res1.rows.forEach((row) => { | |||
| const tmp = { | |||
| id: "alg_" + row.algId, | |||
| name: row.algName, | |||
| sourceId: row.algId, | |||
| checked: false, | |||
| isIndeterminate: false, | |||
| upperValue: "", | |||
| lowerValue: "", | |||
| lowerFlag: row.lowerFlag, | |||
| upperFlag: row.upperFlag, | |||
| code: "", | |||
| parent: null, | |||
| children: null, | |||
| }; | |||
| tmp.children = linq | |||
| .from(res.rows) | |||
| .where((x) => x.algId === row.algId) | |||
| .select((alg) => { | |||
| return { | |||
| sourceId: alg.algSubtypeId, | |||
| id: "sub_" + alg.algSubtypeId, | |||
| name: alg.algSubtypeName, | |||
| checked: false, | |||
| isIndeterminate: false, | |||
| code: alg.algSubtypeCode, | |||
| upperValue: "", | |||
| lowerValue: "", | |||
| lowerFlag: alg.lowerFlag, | |||
| upperFlag: alg.upperFlag, | |||
| parent: tmp, | |||
| }; | |||
| }) | |||
| .toArray(); | |||
| //如果开启了过滤 需要排除 没有子类的大类 | |||
| if (!(this.filterCheckedAlgs && tmp.children.length === 0)) { | |||
| treeData.push(tmp); | |||
| } | |||
| }); | |||
| this.algList = treeData; | |||
| this.form.algList = this.treeToList(treeData); | |||
| this.loading = false; | |||
| this.renderData(); | |||
| }) | |||
| .catch(() => { | |||
| this.loading = false; | |||
| }); | |||
| }) | |||
| .catch(() => { | |||
| this.loading = false; | |||
| }); | |||
| }, | |||
| //回显勾选框 | |||
| renderData() { | |||
| if (this.alarmThreshold.length > 0) { | |||
| const alarmThreshold = JSON.parse(this.alarmThreshold); | |||
| alarmThreshold.forEach((subAlg) => { | |||
| const tmpAlg = this.form.algList.find((c) => c.id === subAlg.id); | |||
| if (tmpAlg) { | |||
| tmpAlg.checked = true; | |||
| tmpAlg.lowerValue = subAlg.lowerValue; | |||
| tmpAlg.upperValue = subAlg.upperValue; | |||
| if (tmpAlg.parent) { | |||
| tmpAlg.parent.checked = linq | |||
| .from(tmpAlg.parent.children) | |||
| .all((x) => x.checked); | |||
| if (!tmpAlg.parent.checked) { | |||
| tmpAlg.parent.isIndeterminate = linq | |||
| .from(tmpAlg.parent.children) | |||
| .any((x) => x.checked); | |||
| } | |||
| } | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| treeToList(nodes) { | |||
| let result = []; | |||
| nodes.forEach((node) => { | |||
| result.push(node); | |||
| if (node.children && node.children.length > 0) { | |||
| result = result.concat(this.treeToList(node.children)); | |||
| } | |||
| }); | |||
| return result; | |||
| }, | |||
| handleRowCheckedChange(row) { | |||
| //我的子类的状态都跟我的状态相同,相当于全选 | |||
| row.children && row.children.forEach((x) => (x.checked = row.checked)); | |||
| if (row.parent) { | |||
| row.parent.checked = linq | |||
| .from(row.parent.children) | |||
| .all((x) => x.checked); | |||
| if (!row.parent.checked) { | |||
| row.parent.isIndeterminate = linq | |||
| .from(row.parent.children) | |||
| .any((x) => x.checked); | |||
| } | |||
| } else { | |||
| if (row.checked) { | |||
| row.isIndeterminate = false; | |||
| } | |||
| } | |||
| }, | |||
| //弹窗关闭事件 | |||
| handleClose() { | |||
| // 重置表单 | |||
| this.resetForm("ruleForm"); | |||
| this.visible = false; | |||
| this.$emit("update:show", false); | |||
| }, | |||
| //选择好智能识别类型后的事件 | |||
| eventOk() { | |||
| const me = this; | |||
| this.$refs.ruleForm.validate((ok) => { | |||
| if (ok) { | |||
| me.visible = false; | |||
| this.$emit( | |||
| "confirm", | |||
| this.form.algList.filter((x) => x.checked) | |||
| ); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| @ -0,0 +1,222 @@ | |||
| <template> | |||
| <el-dialog title="选择巡检设备" :visible.sync="visible" width="55%" style="height:100%" @close="handleClose" :close-on-click-modal="false" append-to-body> | |||
| <el-row class="card-page"> | |||
| <el-form label-width="0px" :model="form" ref="ruleForm"> | |||
| <el-col :span="24"> | |||
| <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px"> | |||
| <el-form-item label="设备类型" prop="type"> | |||
| <el-select v-model="queryParams.type" placeholder="请选择"> | |||
| <el-option v-for="item in dict.type.device_type" :key="item.value" :label="item.label" :value="item.value"> | |||
| </el-option> | |||
| </el-select> | |||
| </el-form-item> | |||
| <el-form-item label="设备名称" prop="patroldeviceName"> | |||
| <el-input v-model="queryParams.patroldeviceName" placeholder="请输入设备名称" clearable @keyup.enter.native="handleQuery" /> | |||
| </el-form-item> | |||
| <el-form-item label="设备编码" prop="patroldeviceCode"> | |||
| <el-input v-model="queryParams.patroldeviceCode" placeholder="请输入设备编码" clearable @keyup.enter.native="handleQuery" /> | |||
| </el-form-item> | |||
| <el-form-item label="生产厂家" prop="manufacturer"> | |||
| <el-input v-model="queryParams.manufacturer" placeholder="请输入生产厂家" clearable @keyup.enter.native="handleQuery" /> | |||
| </el-form-item> | |||
| <el-form-item> | |||
| <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> | |||
| <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> | |||
| </el-form-item> | |||
| </el-form> | |||
| <el-table v-loading="loading" :data="eqpbookList" @row-click="handleCurrentChange" :multiple="false" highlight-current-row> | |||
| <el-table-column label="设备名称" width="100" align="center" prop="patroldeviceName" fixed /> | |||
| <el-table-column label="设备编码" width="100" align="center" prop="patroldeviceCode" fixed /> | |||
| <el-table-column label="视频NVR编码" width="100" align="center" prop="videoNvrCode" fixed /> | |||
| <el-table-column label="生产厂家" width="100" align="center" prop="manufacturer" fixed /> | |||
| <el-table-column label="主系统编号" width="100" align="center" prop="mainSystemCode" fixed /> | |||
| <el-table-column label="变电站名称" width="150" align="center" prop="stationName" /> | |||
| <el-table-column label="变电站编码" width="100" align="center" prop="stationCode" /> | |||
| <el-table-column label="区域名称" width="150" align="center" prop="areaName" /> | |||
| <el-table-column label="设备类型" width="100" align="center" prop="type"> | |||
| <template slot-scope="scope"> | |||
| <dict-tag :options="dict.type.device_type" :value="scope.row.type" /> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="设备型号" width="100" align="center" prop="deviceModel" /> | |||
| <el-table-column label="使用单位" width="100" align="center" prop="useUnit" /> | |||
| <el-table-column label="设备来源" width="100" align="center" prop="deviceSource" /> | |||
| <el-table-column label="生产日期" width="100" align="center" prop="productionDate" /> | |||
| <el-table-column label="出厂编号" width="100" align="center" prop="productionCode" /> | |||
| <el-table-column label="是否轮转" width="100" align="center" prop="istransport"> | |||
| <template slot-scope="scope"> | |||
| <dict-tag :options="dict.type.is_transport" :value="scope.row.istransport" /> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="使用类型" width="100" align="center" prop="useMode"> | |||
| <template slot-scope="scope"> | |||
| <dict-tag :options="dict.type.use_mode" :value="scope.row.useMode" /> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="视频类型" width="100" align="center" prop="videoMode"> | |||
| <template slot-scope="scope"> | |||
| <dict-tag :options="dict.type.video_mode" :value="scope.row.videoMode" /> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column label="所属机器人" width="100" align="center" prop="robotsCode" /> | |||
| <el-table-column label="ip地址" width="200" align="center" prop="ipAddr" /> | |||
| <el-table-column label="端口" width="100" align="center" prop="port" /> | |||
| <el-table-column label="用户" width="100" align="center" prop="user" /> | |||
| <el-table-column label="密码" width="100" align="center" prop="password" /> | |||
| </el-table> | |||
| <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> | |||
| </el-col> | |||
| </el-form> | |||
| </el-row> | |||
| <span slot="footer" class="dialog-footer card-page"> | |||
| <el-button @click="eventOk" :disabled="loading" type="primary">确定</el-button> | |||
| <el-button @click="visible = false">取消</el-button> | |||
| </span> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import { | |||
| listEqpbook | |||
| } from "@/api/basedata/eqpbook/eqpbook"; | |||
| import linq from 'linq' | |||
| export default { | |||
| dicts: ["device_type", "video_mode", "use_mode", "is_transport"], | |||
| props: { | |||
| show: { | |||
| type: Boolean, | |||
| default: false, | |||
| } | |||
| }, | |||
| watch: { | |||
| show (newVal) { | |||
| this.visible = newVal | |||
| if (newVal === true) { | |||
| this.getList(); | |||
| } | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| currentRow: null, | |||
| total: 0, | |||
| loading: false, | |||
| // 基础数据-设备台账主表格数据 | |||
| eqpbookList: [], | |||
| form: { | |||
| algList: [] | |||
| }, | |||
| // 查询参数 | |||
| queryParams: { | |||
| pageNum: 1, | |||
| pageSize: 10, | |||
| stationName: null, | |||
| stationCode: null, | |||
| areaName: null, | |||
| patroldeviceName: null, | |||
| patroldeviceCode: null, | |||
| deviceModel: null, | |||
| manufacturer: null, | |||
| useUnit: null, | |||
| deviceSource: null, | |||
| productionDate: null, | |||
| productionCode: null, | |||
| istransport: null, | |||
| useMode: null, | |||
| videoMode: null, | |||
| place: null, | |||
| positionX: null, | |||
| positionY: null, | |||
| positionZ: null, | |||
| type: null, | |||
| patroldeviceInfo: null, | |||
| robotsCode: null, | |||
| ipAddr: null, | |||
| port: null, | |||
| user: null, | |||
| password: null, | |||
| video_mode: null, | |||
| use_mode: null, | |||
| is_transport: null, | |||
| }, | |||
| // 选中数组 | |||
| ids: [], | |||
| // 非单个禁用 | |||
| single: true, | |||
| // 非多个禁用 | |||
| multiple: true, | |||
| visible: false, | |||
| algList: [],/* 算法类型 */ | |||
| alertTitle: "设置智能识别类型", /* 弹窗标题 */ | |||
| rules: { | |||
| algId: [{ required: true, message: "必选", trigger: "blur" }], | |||
| algSubtypeId: [{ required: true, message: "必选", trigger: "blur" }], | |||
| upperValue: [{ required: true, message: "必选", trigger: "blur" }], | |||
| lowerValue: [{ required: true, message: "必选", trigger: "blur" }], | |||
| } | |||
| } | |||
| }, | |||
| created () { | |||
| }, | |||
| computed: { | |||
| }, | |||
| methods: { | |||
| /** 重置按钮操作 */ | |||
| resetQuery () { | |||
| this.resetForm("queryForm"); | |||
| this.handleQuery(); | |||
| }, | |||
| /** 搜索按钮操作 */ | |||
| handleQuery () { | |||
| this.queryParams.pageNum = 1; | |||
| this.getList(); | |||
| }, | |||
| handleCurrentChange (row) { | |||
| this.currentRow = row; | |||
| }, | |||
| // 多选框选中数据 | |||
| handleSelectionChange (selection) { | |||
| this.ids = selection.map((item) => item.eqpbookId); | |||
| this.single = selection.length !== 1; | |||
| this.multiple = !selection.length; | |||
| }, | |||
| /** 查询基础数据-设备台账主列表 */ | |||
| getList () { | |||
| this.loading = true; | |||
| listEqpbook(this.queryParams).then((response) => { | |||
| this.eqpbookList = response.rows; | |||
| this.total = response.total; | |||
| this.loading = false; | |||
| }); | |||
| }, | |||
| //弹窗关闭事件 | |||
| handleClose () { | |||
| // 重置表单 | |||
| this.resetForm('queryForm'); | |||
| this.visible = false; | |||
| this.$emit('update:show', false) | |||
| }, | |||
| //选择好智能识别类型后的事件 | |||
| eventOk () { | |||
| const me = this; | |||
| if (this.currentRow === null) { | |||
| this.$message({ | |||
| type: 'warning', | |||
| message: '请选中一行数据。' | |||
| }) | |||
| return; | |||
| } | |||
| me.visible = false; | |||
| this.$emit('confirm', this.currentRow) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| @ -0,0 +1,591 @@ | |||
| <template> | |||
| <el-dialog | |||
| :title="pointDialogDataName" | |||
| :visible.sync="pointDialogShow" | |||
| width="70%" | |||
| :before-close="bindingMonitorPointClose" | |||
| > | |||
| <el-row :gutter="20"> | |||
| <el-col :span="5"> | |||
| <div class="bindingMonitorPointTree"> | |||
| <el-tree | |||
| :data="dialogPointTree" | |||
| :props="defaultPropsMonitor" | |||
| @node-click="handleMonitor" | |||
| ></el-tree> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="13"> | |||
| <div class="bindingMonitorPointDiv"> | |||
| <videoPlayer /> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="6"> | |||
| <div style="background: #eee; padding: 5px"> | |||
| {{ $t("site_management.PTZ") }} | |||
| </div> | |||
| <div class="PTZ-content"> | |||
| <img src="@/assets/images/PTZImg.png" alt="" class="PTZImg" /> | |||
| <div class="r-ti2-pos"> | |||
| <div @click="ptzBtn('UP', 'UP_STOP')"></div> | |||
| <div @click="ptzBtn('UP_RIGHT', 'UP_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('RIGHT', 'RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_RIGHT', 'DOWN_RIGHT_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN', 'DOWN_STOP')"></div> | |||
| <div @click="ptzBtn('DOWN_LEFT', 'DOWN_LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('LEFT', 'LEFT_STOP')"></div> | |||
| <div @click="ptzBtn('UP_LEFT', 'UP_LEFT_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3"> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/searchImg.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="ptzBtn('ZOOM_OUT', 'ZOOM_OUT_STOP')"></div> | |||
| <div @click="ptzBtn('ZOOM_IN', 'ZOOM_IN_STOP')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r2Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('nearfocus', 'nearfocusstop')"></div> | |||
| <div @click="fiBtn('farfocus', 'farfocusstop')"></div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti3-d1"> | |||
| <img src="@/assets/images/r3Img.png" alt="" /> | |||
| <div class="r-ti3-d2"> | |||
| <div @click="fiBtn('apertureoff', 'apertureoffstop')"></div> | |||
| <div @click="fiBtn('apertureon', 'apertureonstop')"></div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div class="r-ti4"> | |||
| <div style="display: flex"> | |||
| <el-select | |||
| v-model="presetDotNum" | |||
| :placeholder="$t('site_management.PleaseSelectAPresetPoint')" | |||
| @change="presetDotBtn" | |||
| > | |||
| <el-option | |||
| :label="item.dictLabel" | |||
| :value="item.dictValue" | |||
| v-for="item in listByEqIdAndChanneData" | |||
| :key="item.dictValue" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| <img | |||
| src="@/assets/images/playImg.png" | |||
| @click="editPresetDot1" | |||
| title="编辑预置点名称" | |||
| /> | |||
| <img src="@/assets/images/addImg.png" alt="" @click="popoverOpen" /> | |||
| <el-popover | |||
| placement="top" | |||
| width="300" | |||
| v-model="popovervisible" | |||
| trigger="click" | |||
| > | |||
| <el-input placeholder="请输入内容" v-model="newpresetName" /> | |||
| <div class="popover-footer"> | |||
| <el-button | |||
| size="mini" | |||
| type="primary" | |||
| @click="popovervisibleShow" | |||
| >取消</el-button | |||
| > | |||
| <el-button size="mini" type="primary" @click="setPresetDot1" | |||
| >确定</el-button | |||
| > | |||
| </div> | |||
| </el-popover> | |||
| </div> | |||
| <div style="display: flex; margin-top: 20px"> | |||
| <el-input | |||
| v-model="presetName" | |||
| :placeholder="$t('site_management.PleaseEnterTheContent')" | |||
| ></el-input> | |||
| <img | |||
| src="@/assets/images/setImg.png" | |||
| alt="" | |||
| title="编辑预置点名称" | |||
| @click="editPresetDot2" | |||
| /> | |||
| </div> | |||
| </div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-table | |||
| :data="bindingMonitorPointTableData" | |||
| style="width: 100%" | |||
| @header-click="clickFun" | |||
| > | |||
| <el-table-column :label="$t('site_management.ActionType')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-select v-model="scope.row.actionType"> | |||
| <el-option label="拍照" value="1" /> | |||
| <el-option label="录像" value="2" /> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.RecordingDuration')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.videoTime" | |||
| v-if="scope.row.actionType == 2" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.NumberOfPhotosTaken')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoCount" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| <!-- <span v-if="scope.row.actionType == 1">1</span> --> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('site_management.PhotoInterval')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| v-model="scope.row.photoSeper" | |||
| v-if="scope.row.actionType == 1" | |||
| class="centered-input" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| align="center" | |||
| :render-header="(h, obj) => renderHeader(h, obj, $t('share.addTo'))" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-button | |||
| type="text" | |||
| size="small" | |||
| @click="removeAction(scope.$index)" | |||
| >移除</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <template #footer> | |||
| <div class="add-btn add-bth1 card-page"> | |||
| <el-button type="primary" @click="saveDot1">确定</el-button> | |||
| <el-button @click="bindingMonitorPointClose">取消</el-button> | |||
| </div> | |||
| </template> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import videoPlayer from "@/components/videoPlayer/index.vue"; | |||
| import { | |||
| vl, | |||
| listByEqIdAndChannelId, | |||
| realtime, | |||
| PZT, | |||
| fi, | |||
| goto, | |||
| issue, | |||
| bindingPreset, | |||
| } from "@/api/point/site_management"; | |||
| export default { | |||
| components: { videoPlayer }, | |||
| props: ["pointDialogDataName", "pointDialogShow", "dialogProp"], | |||
| data() { | |||
| return { | |||
| bindingMonitorPointTitle: "绑定可见光检测点", | |||
| // pointDialogShow: false, | |||
| dialogPointTree: [], | |||
| defaultPropsMonitor: { | |||
| children: "children", | |||
| label: "name", | |||
| }, | |||
| listByEqIdAndChanneData: [], | |||
| bindingMonitorPointTableData: [], | |||
| presetDotNum: "", | |||
| PZTData: {}, | |||
| presetName: "", | |||
| popovervisible: false, | |||
| newpresetName: "", | |||
| presetData: { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| presetPointList: [], | |||
| }, | |||
| }; | |||
| }, | |||
| methods: { | |||
| bindingMonitorPointClose() { | |||
| // this.pointDialogShow = false; | |||
| this.$emit("site_videoDialogClose",false); | |||
| }, | |||
| // 绑定可见光监测点点击树事件 | |||
| handleMonitor(e) { | |||
| console.log(e, 111, this.dialogProp); | |||
| if (e.eqpbookId) { | |||
| this.presetData.patrolpointId = this.dialogProp.patrolpointId; | |||
| this.presetData.stdparolPointId = this.dialogProp.stdparolPointId; | |||
| this.presetData.deviceId = this.dialogProp.deviceId; | |||
| this.presetData.eqpbookId = e.eqpbookId; | |||
| this.presetData.channelId = e.channelId; | |||
| this.PZTData = e; | |||
| listByEqIdAndChannelId({ | |||
| channelCode: e.channelCode, | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| this.listByEqIdAndChanneData = res.data; | |||
| } | |||
| }); | |||
| realtime({ | |||
| patroldeviceCode: e.patroldeviceCode, | |||
| channelCode: e.channelCode, | |||
| }).then((res) => { | |||
| if (res.code == 200) { | |||
| // this.bindingMonitorPointTableData=res.data; | |||
| console.log(res, 1111); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| renderHeader(h, { column, $index }, type) { | |||
| let that = this; | |||
| return h("div", [ | |||
| // 列名称 | |||
| h("span", column.label), | |||
| // 按钮 | |||
| h( | |||
| "el-button", | |||
| { | |||
| props: { | |||
| type: "text", | |||
| size: "small", | |||
| }, | |||
| style: "margin-left: 5px;", | |||
| on: { | |||
| click: function () { | |||
| that.clickButton(type); | |||
| }, | |||
| }, | |||
| }, | |||
| this.$t("share.addTo") | |||
| ), | |||
| ]); | |||
| }, | |||
| clickButton(type) { | |||
| // console.log("我点击了" + type + "的列"); | |||
| this.bindingMonitorPointTableData.push({ | |||
| actionType: "", | |||
| videoTime: "", | |||
| photoCount: "1", | |||
| photoSeper: "", | |||
| }); | |||
| }, | |||
| clickFun() {}, | |||
| init() { | |||
| vl().then((res) => { | |||
| if (res.code == 200) { | |||
| this.dialogPointTree = res.data; | |||
| } | |||
| }); | |||
| }, | |||
| ptzBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| PZT(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| PZT(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| fiBtn(start, stop) { | |||
| let startData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: start, | |||
| }; | |||
| let stopData = { | |||
| speed: 5, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| ptzControlType: stop, | |||
| }; | |||
| if (startData.patroldeviceCode && startData.channelCode) { | |||
| fi(startData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "start"); | |||
| } | |||
| }); | |||
| fi(stopData).then((res) => { | |||
| if (res.code) { | |||
| console.log(res, "stop"); | |||
| } | |||
| }); | |||
| } | |||
| }, | |||
| presetDotBtn(value) { | |||
| this.presetData.presetPosCode = value; | |||
| this.listByEqIdAndChanneData.forEach((item) => { | |||
| if (item.dictValue == this.presetDotNum) { | |||
| this.presetName = item.dictLabel; | |||
| } | |||
| }); | |||
| }, | |||
| // 编辑预置点名称 | |||
| editPresetDot1() { | |||
| let data = { | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| channelCode: this.PZTData.channelCode, | |||
| presetDotNum: this.presetDotNum, | |||
| name: this.presetName, | |||
| }; | |||
| goto(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popovervisibleShow() { | |||
| this.popovervisible = false; | |||
| this.newpresetName = ""; | |||
| }, | |||
| setPresetDot1() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.presetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| issue(data).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.popovervisible = false; | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| popoverOpen() { | |||
| this.popovervisible = true; | |||
| }, | |||
| // 设置预设点名称 | |||
| editPresetDot2() { | |||
| let data = { | |||
| presetCode: this.presetDotNum, | |||
| name: this.newpresetName, | |||
| channelCode: this.PZTData.channelCode, | |||
| patroldeviceCode: this.PZTData.patroldeviceCode, | |||
| }; | |||
| }, | |||
| // 表格按钮移除 | |||
| removeAction() { | |||
| this.bindingMonitorPointTableData.splice(index, 1); | |||
| }, | |||
| // 保存 | |||
| saveDot1() { | |||
| this.presetData.presetPosName = this.presetName; | |||
| this.presetData.presetActionList = this.bindingMonitorPointTableData; | |||
| bindingPreset(this.presetData).then((res) => { | |||
| console.log(res, 11111); | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| message: res.msg, | |||
| type: "success", | |||
| }); | |||
| this.presetData = { | |||
| presetPosCode: "", | |||
| channelId: "", | |||
| eqpbookId: "", | |||
| patrolpointId: "", | |||
| stdparolPointId: "", | |||
| deviceId: "", | |||
| presetPosName: "", | |||
| stopTime: "", | |||
| channelImg: "", | |||
| description: "", | |||
| presetActionList: [], | |||
| presetParamList: [], | |||
| }; | |||
| this.pointDialogShow=false; | |||
| this.$emit('site_saveDot1',true) | |||
| } else { | |||
| this.$message.error(res.msg); | |||
| } | |||
| }); | |||
| }, | |||
| }, | |||
| mounted() { | |||
| this.init(); | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .bindingMonitorPointTree { | |||
| width: 100%; | |||
| height: 37vh; | |||
| overflow-y: scroll; | |||
| } | |||
| .bindingMonitorPointDiv { | |||
| width: 100%; | |||
| height: 40vh; | |||
| // background: red; | |||
| } | |||
| .PTZ-content { | |||
| width: 170px; | |||
| margin: 10px auto; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| } | |||
| .r-ti2-pos { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div { | |||
| position: absolute; | |||
| z-index: 999; | |||
| width: 20px; | |||
| height: 15px; | |||
| cursor: pointer; | |||
| } | |||
| div:first-child { | |||
| top: 32px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(2) { | |||
| top: 50px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(3) { | |||
| top: 77px; | |||
| right: 30px; | |||
| } | |||
| div:nth-child(4) { | |||
| bottom: 56px; | |||
| left: 102px; | |||
| } | |||
| div:nth-child(5) { | |||
| bottom: 36px; | |||
| left: 75px; | |||
| } | |||
| div:nth-child(6) { | |||
| bottom: 56px; | |||
| right: 100px; | |||
| } | |||
| div:nth-child(7) { | |||
| bottom: 80px; | |||
| left: 30px; | |||
| } | |||
| div:nth-child(8) { | |||
| top: 50px; | |||
| right: 102px; | |||
| } | |||
| } | |||
| .r-ti3 { | |||
| width: 100%; | |||
| display: flex; | |||
| padding-top: 10px; | |||
| -webkit-box-pack: justify; | |||
| justify-content: space-between; | |||
| } | |||
| .r-ti3-d1 { | |||
| width: 76px; | |||
| position: relative; | |||
| img { | |||
| width: 100%; | |||
| } | |||
| .r-ti3-d2 { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100%; | |||
| height: 100%; | |||
| div:first-child { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| cursor: pointer; | |||
| } | |||
| div:nth-child(2) { | |||
| width: 50%; | |||
| height: 100%; | |||
| position: absolute; | |||
| top: 0; | |||
| right: 0; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| } | |||
| .r-ti4 { | |||
| padding-top: 20px; | |||
| img { | |||
| width: 24px; | |||
| height: 24px; | |||
| position: relative; | |||
| top: 6px; | |||
| cursor: pointer; | |||
| } | |||
| } | |||
| .popover-footer { | |||
| width: 100%; | |||
| margin-top: 20px; | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,171 @@ | |||
| <template> | |||
| <el-dialog :title="title" @close="handleClose" :visible.sync="visible" width="40%" append-to-body | |||
| :close-on-click-modal="false"> | |||
| <el-upload :data="updata" :accept="accept" class="upload-demo" :headers="headers" v-loading="loading" | |||
| :with-credential="true" :action="action" :on-success="handleUploadSuccess" :on-error="handleUploadError" | |||
| :on-preview="handlePreview" :on-remove="handleRemove" :before-remove="beforeRemove" :limit="1" | |||
| :on-exceed="handleExceed" :file-list="fileList"> | |||
| <div class="card-page"> | |||
| <el-button size="small" type="primary">点击上传</el-button> | |||
| </div> | |||
| <!-- list-type="picture" --> | |||
| </el-upload> | |||
| <AsyncImage v-if="pendding" ref="asyncImage" class="xg_image_viewer" @imgload="handleImageLoad" | |||
| @imgloaderror="handleImageLoadError" :src="currentSrc" :srcList="currentSrcList" /> | |||
| <span slot="footer" class="dialog-footer card-page"> | |||
| <el-button type="primary" v-if="showConfirmBtn" @click="handleConfirm">确 定</el-button> | |||
| <el-button @click="visible = false">关 闭</el-button> | |||
| </span> | |||
| </el-dialog> | |||
| </template> | |||
| <script> | |||
| import { getToken } from '@/utils/auth' | |||
| import AsyncImage from '@/components/AsyncImage' | |||
| import linq from 'linq' | |||
| export default { | |||
| components: { | |||
| AsyncImage | |||
| }, | |||
| props: { | |||
| show: { | |||
| type: Boolean, | |||
| default: false | |||
| }, | |||
| filePath: { | |||
| type: String, | |||
| default: "" | |||
| }, | |||
| title: { | |||
| type: String, | |||
| default: "判别图片上传" | |||
| }, | |||
| action: { | |||
| type: String, | |||
| default: process.env.VUE_APP_BASE_API + '/patrol/partrolresult/lasupload' | |||
| }, | |||
| accept: { | |||
| type: String, | |||
| default: '*' | |||
| }, | |||
| updata: { | |||
| type: Object, | |||
| default: function () { | |||
| return {} | |||
| } | |||
| }, | |||
| showConfirmBtn: { | |||
| type: Boolean, | |||
| default: true | |||
| } | |||
| }, | |||
| watch: { | |||
| show: { | |||
| handler (newVal) { | |||
| this.loading = false | |||
| this.visible = newVal | |||
| this.fileList = [] | |||
| if (this.filePath && this.filePath.length > 0) { | |||
| this.fileList = linq.from(this.filePath.split(',')).select(x => { return { name: '缺陷判别图片.jpg', url: x } }).toArray() | |||
| } else { | |||
| this.fileList = [] | |||
| } | |||
| } | |||
| } | |||
| }, | |||
| data () { | |||
| return { | |||
| visible: false, | |||
| fileList: [], | |||
| loading: false, | |||
| currentSrc: "", | |||
| currentSrcList: [], | |||
| pendding: false, | |||
| headers: { 'Authorization': 'Bearer ' + getToken() } | |||
| }; | |||
| }, | |||
| methods: { | |||
| handleConfirm () { | |||
| this.visible = false | |||
| this.$emit('confirm', this.fileList) | |||
| }, | |||
| //上传完成 | |||
| handleUploadSuccess (response, file, fileList) { | |||
| this.fileList = [] | |||
| if (typeof (file.response) !== 'string') { | |||
| if (file.response.code != 200) { | |||
| this.$message.error(`上传失败。消息:${file.response.msg}`) | |||
| return; | |||
| } | |||
| this.fileList.push({ | |||
| name: '机器人点位文件.xml' | |||
| }) | |||
| return; | |||
| } | |||
| this.fileList.push({ | |||
| name: file.name, | |||
| url: file.response | |||
| // name: "微信图片_20220520095815.png" | |||
| // percentage: 100 | |||
| // raw: File | |||
| // response: "/home/xgftp/微信图片_20220520095815.png" | |||
| // size: 699595 | |||
| // status: "success" | |||
| // uid: 1653012695833 | |||
| }) | |||
| console.log(this.fileList) | |||
| // this.$emit('uploadSuccess', response) | |||
| }, | |||
| // 关闭弹窗 | |||
| handleClose () { | |||
| this.visible = false | |||
| this.fileList = [] | |||
| this.$emit('update:show', false) | |||
| }, | |||
| // 上传失败 | |||
| handleUploadError (err, file, fileList) { | |||
| this.$message.error(`上传失败,请检查文件或网络。`) | |||
| }, | |||
| handleRemove (file, fileList) { | |||
| this.fileList = [] | |||
| console.log(file, fileList); | |||
| }, | |||
| handlePreview (file) { | |||
| this.pendding = false | |||
| this.$nextTick(() => { | |||
| this.pendding = true | |||
| this.currentSrc = file.url | |||
| this.currentSrcList = [file.url] | |||
| this.loading = true | |||
| }) | |||
| }, | |||
| handleImageLoad () { | |||
| this.loading = false; | |||
| this.$refs.asyncImage.$el.querySelector("img").click(); | |||
| }, | |||
| handleImageLoadError () { | |||
| this.loading = false; | |||
| }, | |||
| handleExceed (files, fileList) { | |||
| this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`); | |||
| }, | |||
| beforeRemove (file, fileList) { | |||
| return this.$confirm(`确定移除 ${file.name}?`); | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .xg_image_viewer { | |||
| position: fixed; | |||
| bottom: 0; | |||
| left: 0; | |||
| width: 50px; | |||
| height: 50px; | |||
| display: none; | |||
| } | |||
| </style> | |||
| @ -0,0 +1,531 @@ | |||
| el-button<template> | |||
| <div class="app-container"> | |||
| <el-row :gutter="20"> | |||
| <el-col :span="4"> | |||
| <div class="qurey"> | |||
| <el-input | |||
| :placeholder="$t('point_mang.PleaseEnterTheContent')" | |||
| v-model="filterText" | |||
| class="input-with-select" | |||
| > | |||
| </el-input> | |||
| </div> | |||
| <el-tree | |||
| :data="treeDataNew" | |||
| :props="defaultProps" | |||
| @node-click="handleNodeClick" | |||
| node-key="devicetypeId" | |||
| ref="tree" | |||
| :filter-node-method="filterNode" | |||
| ></el-tree> | |||
| </el-col> | |||
| <el-col :span="20" v-if="devicetypeId"> | |||
| <div> | |||
| <el-button type="primary" @click="addBtn">{{ | |||
| $t("share.addTo") | |||
| }}</el-button> | |||
| <span>(0/200){{ $t("point_mang.tableHeadMsg") }}</span> | |||
| </div> | |||
| <el-table :data="tableData" style="margin-top: 10px"> | |||
| <el-table-column | |||
| prop="date" | |||
| :label="$t('point_mang.index')" | |||
| width="55" | |||
| type="index" | |||
| align="center" | |||
| ></el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.equipmentClassification')" | |||
| :render-header="addRedStar" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <treeselect | |||
| v-model="scope.row.componentDevicetypeId" | |||
| :options="DevicetypeIdOptions" | |||
| :normalizer="normalizer" | |||
| :clearable="false" | |||
| /> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.InspectionStandards')" | |||
| :render-header="addRedStar" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <el-input | |||
| type="textarea" | |||
| :placeholder=" | |||
| $t('share.PleaseChoose') + $t('point_mang.PleaseEnter') | |||
| " | |||
| v-model="scope.row.patrolContent" | |||
| ></el-input> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column :label="$t('point_mang.dataFormat')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-select | |||
| v-model="scope.row.mainDevicetypeId" | |||
| :placeholder=" | |||
| $t('share.PleaseChoose') + $t('point_mang.dataFormat') | |||
| " | |||
| > | |||
| <el-option | |||
| v-for="item in options" | |||
| :key="item.dictValue" | |||
| :label="item.dictLabel" | |||
| :value="item.dictValue" | |||
| > | |||
| </el-option> | |||
| </el-select> | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| :label="$t('point_mang.IntelligentRecognitionType')" | |||
| align="center" | |||
| > | |||
| <template slot-scope="scope"> | |||
| <span | |||
| class="intelligenceType" | |||
| @click="intelligenceTypeBtn(scope.row)" | |||
| >{{ | |||
| scope.row.algSubtypeName ? scope.row.algSubtypeName : "设置" | |||
| }}</span | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column :label="$t('share.operate')" align="center"> | |||
| <template slot-scope="scope"> | |||
| <el-button | |||
| size="mini" | |||
| type="primary" | |||
| @click="handleCopy(scope.row)" | |||
| > | |||
| {{ $t("share.copy") }} | |||
| </el-button> | |||
| <el-button | |||
| size="mini" | |||
| type="danger" | |||
| @click="handleDelete(scope.row, scope.$index)" | |||
| >{{ $t("share.delete") }}</el-button | |||
| > | |||
| </template> | |||
| </el-table-column> | |||
| </el-table> | |||
| <div class="saveBtn"> | |||
| <el-button type="primary" @click="submitForm">{{ | |||
| $t("share.save") | |||
| }}</el-button> | |||
| </div> | |||
| </el-col> | |||
| <el-col :span="20" v-if="!devicetypeId"> | |||
| <div style="line-height: 36px">请先选择左侧点位</div> | |||
| </el-col> | |||
| </el-row> | |||
| <el-dialog | |||
| :title="$t('point_mang.SetIntelligentRecognitionType')" | |||
| :visible.sync="dialogVisible" | |||
| width="50%" | |||
| :before-close="handleClose" | |||
| style="height: 70vh" | |||
| border | |||
| > | |||
| <el-table | |||
| :data="intelligenceTypeData" | |||
| :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" | |||
| default-expand-all | |||
| row-key="id" | |||
| @selection-change="handleSelectionChangeDialog" | |||
| ref="multipleTable" | |||
| height="45vh" | |||
| > | |||
| <el-table-column | |||
| type="selection" | |||
| width="55" | |||
| align="center" | |||
| ></el-table-column> | |||
| <el-table-column | |||
| type="index" | |||
| width="55" | |||
| align="center" | |||
| :label="$t('point_mang.index')" | |||
| ></el-table-column> | |||
| <!-- <el-table-column | |||
| prop="algName" | |||
| align="center" | |||
| :label="$t('point_mang.AlgorithmName')" | |||
| ></el-table-column> --> | |||
| <el-table-column :label="$t('patrolpoint.AlgorithmName')"> | |||
| <template slot-scope="scope"> | |||
| {{ | |||
| scope.row.algSubtypeName | |||
| ? scope.row.algSubtypeName | |||
| : scope.row.algName | |||
| }} | |||
| </template> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="patrolContent" | |||
| align="center" | |||
| :label="$t('point_mang.ThresholdUpperLimit')" | |||
| :render-header="addRedStar" | |||
| > | |||
| <!-- <template slot-scope="scope"> | |||
| <el-input></el-input> | |||
| </template> --> | |||
| </el-table-column> | |||
| <el-table-column | |||
| prop="mainDevicetypeId" | |||
| align="center" | |||
| :label="$t('point_mang.LowerThresholdLimit')" | |||
| :render-header="addRedStar" | |||
| > | |||
| <!-- <template slot-scope="scope"> | |||
| <el-input></el-input> | |||
| </template> --> | |||
| </el-table-column> | |||
| </el-table> | |||
| <span slot="footer" class="dialog-footer"> | |||
| <el-button @click="handleClose">{{ $t("share.cancel") }}</el-button> | |||
| <el-button type="primary" @click="dialogTableOk">{{ | |||
| $t("share.confirm") | |||
| }}</el-button> | |||
| </span> | |||
| </el-dialog> | |||
| </div> | |||
| </template> | |||
| <script> | |||
| import { | |||
| getTreeAreaDeviceSelect, | |||
| cilikList, | |||
| devicetype, | |||
| dataFormat, | |||
| add, | |||
| remove, | |||
| algList, | |||
| subtypeList, | |||
| } from "@/api/point/point_mang"; | |||
| import Treeselect from "@riophae/vue-treeselect"; | |||
| import "@riophae/vue-treeselect/dist/vue-treeselect.css"; | |||
| // import treeSelect from "./components/treeSelect.vue"; | |||
| export default { | |||
| components: { | |||
| Treeselect, | |||
| // treeSelect, | |||
| }, | |||
| data() { | |||
| return { | |||
| treeDataNew: [], | |||
| defaultProps: { | |||
| children: "children", | |||
| label: "devicetypeName", | |||
| }, | |||
| tableData: [], | |||
| DevicetypeIdOptions: [], | |||
| options: [], | |||
| value: [], | |||
| dialogVisible: false, | |||
| intelligenceTypeData: [], | |||
| devicetypeId: null, | |||
| dialogTableSelect: [], | |||
| stdpatrolPointId: null, | |||
| dialogTableSelectName: [], | |||
| filterText: null, | |||
| normalizer(node) { | |||
| return { | |||
| id: node.devicetypeId, | |||
| label: node.devicetypeName, | |||
| children: node.children, | |||
| }; | |||
| }, | |||
| }; | |||
| }, | |||
| watch: { | |||
| filterText(val) { | |||
| this.$refs.tree.filter(val); | |||
| }, | |||
| }, | |||
| created() {}, | |||
| mounted() { | |||
| this.init(); | |||
| // devicetype().then((res) => { | |||
| // if (res.code == 200) { | |||
| // res.data.forEach((item) => { | |||
| // if (item.devicetypeId !== 1) { | |||
| // this.DevicetypeIdOptions.push(item); | |||
| // } | |||
| // }); | |||
| // } | |||
| // }); | |||
| dataFormat().then((res) => { | |||
| if (res.code == 200) { | |||
| console.log(this.options, res.data); | |||
| res.data.forEach((item) => { | |||
| item.dictValue = Number(item.dictValue); | |||
| }); | |||
| this.options = res.data; | |||
| } | |||
| }); | |||
| }, | |||
| methods: { | |||
| filterNode(value, data) { | |||
| if (!value) return true; | |||
| return data.devicetypeName.indexOf(value) !== -1; | |||
| }, | |||
| init(qurey) { | |||
| devicetype(qurey).then((res) => { | |||
| this.treeDataNew = []; | |||
| this.tableData = []; | |||
| if (res.code == 200) { | |||
| res.data.forEach((item) => { | |||
| if (item.devicetypeId !== 1) { | |||
| this.treeDataNew.push(item); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| // 给表头加必填符号* | |||
| addRedStar(h, { column }) { | |||
| return [ | |||
| h("span", { style: "color: red" }, "*"), | |||
| h("span", " " + column.label), | |||
| ]; | |||
| }, | |||
| intelligenceTypeBtn(row) { | |||
| this.stdpatrolPointId = row.stdpatrolPointId; | |||
| subtypeList().then((res0) => { | |||
| if (res0.code == 200) { | |||
| algList().then((res1) => { | |||
| if (res1.code == 200) { | |||
| let list = res1.rows; | |||
| list.forEach((item) => { | |||
| item.children = []; | |||
| item.id = `${item.algId}_${item.algId}`; | |||
| res0.rows.forEach((i) => { | |||
| i.id = i.algSubtypeId; | |||
| if (item.algId == i.algId && item.algName == i.algName) { | |||
| item.children.push(i); | |||
| } | |||
| }); | |||
| }); | |||
| this.intelligenceTypeData = list; | |||
| this.dialogVisible = true; | |||
| this.$nextTick(() => { | |||
| if (row.alarmThreshold) { | |||
| let data = JSON.parse(row.alarmThreshold); | |||
| let idArr = []; | |||
| data.forEach((item) => { | |||
| idArr.push(item.id.split("_")[1]); | |||
| }); | |||
| idArr.forEach((id) => { | |||
| let show = res0.rows.find( | |||
| (item) => item.algSubtypeId == id | |||
| ); | |||
| if (show) { | |||
| this.$refs.multipleTable.toggleRowSelection(show, true); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| } | |||
| }); | |||
| }, | |||
| // 给表头加必填符号* | |||
| addRedStar(h, { column }) { | |||
| return [ | |||
| h("span", { style: "color: red" }, "*"), | |||
| h("span", " " + column.label), | |||
| ]; | |||
| }, | |||
| // 树点击 | |||
| handleNodeClick(data) { | |||
| console.log(data, 11111111111); | |||
| this.devicetypeId = data.devicetypeId; | |||
| this.tableData = []; | |||
| this.initClickList(data); | |||
| }, | |||
| initClickList(data) { | |||
| cilikList(data.devicetypeId).then((res) => { | |||
| if (res.code == 200) { | |||
| console.log(res, 111); | |||
| this.tableData = res.rows; | |||
| } | |||
| }); | |||
| getTreeAreaDeviceSelect(data.devicetypeId).then((res) => { | |||
| console.log(res, 11111111); | |||
| if (res.code == 200) { | |||
| let obj = []; | |||
| res.data.forEach((item) => { | |||
| if ( | |||
| item.devicetypeId !== 1 && | |||
| item.devicetypeId && | |||
| item.powerMainEquFlag == "Yes" | |||
| ) { | |||
| // obj.push(item); | |||
| if(item.devicetypeId==907){ | |||
| console.log(item.devicetype,"测试") | |||
| } | |||
| } | |||
| }); | |||
| this.DevicetypeIdOptions = this.removeDuplicateNodes(obj); | |||
| } | |||
| }); | |||
| }, | |||
| removeDuplicateNodes(nodes) { | |||
| const map = new Map(); | |||
| const result = []; | |||
| function traverse(nodeList) { | |||
| for (const node of nodeList) { | |||
| if (!map.has(node.devicetypeId)) { | |||
| map.set(node.devicetypeId, true); | |||
| result.push(node); | |||
| if (node.children) { | |||
| traverse(node.children); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| traverse(nodes); | |||
| return result; | |||
| }, | |||
| areaNormalizer(node) { | |||
| return { | |||
| id: node.devicetypeId, | |||
| label: node.devicetypeName, | |||
| children: node.children, | |||
| }; | |||
| }, | |||
| addBtn() { | |||
| if (this.tableData.length < 200) { | |||
| this.tableData.push({ | |||
| componentDevicetypeId: null, | |||
| patrolContent: "", | |||
| mainDevicetypeId: null, | |||
| }); | |||
| } else { | |||
| this.$message.warning("最多添加200条数据!"); | |||
| } | |||
| }, | |||
| // 保存 | |||
| submitForm() { | |||
| if (!this.tableData.length) return; | |||
| let flag = this.tableData.every((item) => { | |||
| if (item.componentDevicetypeId && item.patrolContent) { | |||
| return true; | |||
| } else { | |||
| return false; | |||
| } | |||
| }); | |||
| if (flag) { | |||
| add(this.tableData).then((res) => { | |||
| this.initClickList(this.devicetypeId); | |||
| this.$message({ | |||
| type: "success", | |||
| message: "保存成功", | |||
| }); | |||
| }); | |||
| } else { | |||
| this.$message({ | |||
| type: "warning", | |||
| message: "必填项不能为空!", | |||
| }); | |||
| } | |||
| }, | |||
| // 删除 | |||
| handleDelete(row, index) { | |||
| if (!row.stdpatrolPointId) { | |||
| this.tableData.splice(index, 1); | |||
| } else { | |||
| remove(row.stdpatrolPointId).then((res) => { | |||
| if (res.code == 200) { | |||
| this.$message({ | |||
| type: "success", | |||
| message: "删除成功!", | |||
| }); | |||
| this.initClickList(row); | |||
| } | |||
| }); | |||
| } | |||
| return; | |||
| }, | |||
| // 智能识别多选 | |||
| handleSelectionChangeDialog(val) { | |||
| this.dialogTableSelect = []; | |||
| this.dialogTableSelectName = []; | |||
| val.forEach((item) => { | |||
| let data = { | |||
| id: `sub_${item.algSubtypeId}`, | |||
| code: item.algSubtypeCode || "", | |||
| upperValue: item.upperValue || "", | |||
| lowerValue: item.lowerValue || "", | |||
| algSubtypeName: item.algSubtypeName || "", | |||
| }; | |||
| this.dialogTableSelect.push(data); | |||
| this.dialogTableSelectName.push(item.algSubtypeName); | |||
| }); | |||
| }, | |||
| dialogTableOk() { | |||
| this.dialogVisible = false; | |||
| console.log(this.dialogTableSelect, this.stdpatrolPointId); | |||
| this.tableData.forEach((item) => { | |||
| if (item.stdpatrolPointId == this.stdpatrolPointId) { | |||
| item.alarmThreshold = JSON.stringify(this.dialogTableSelect); | |||
| item.algSubtypeName = this.dialogTableSelectName.join(","); | |||
| } | |||
| }); | |||
| }, | |||
| handleClose() { | |||
| this.dialogVisible = false; | |||
| }, | |||
| // 复制 | |||
| handleCopy(row) { | |||
| let { stdpatrolPointId, ...newObj } = row; | |||
| console.log(newObj, 111); | |||
| newObj.patrolContent = row.patrolContent + "_复制"; | |||
| this.tableData.push(newObj); | |||
| }, | |||
| handleNodeClickOption(data) { | |||
| console.log(data, 111); | |||
| }, | |||
| }, | |||
| }; | |||
| </script> | |||
| <style lang="scss" scoped> | |||
| .qurey { | |||
| display: flex; | |||
| margin-bottom: 10px; | |||
| ::v-deep.el-button { | |||
| background-color: #46a6ff !important; | |||
| color: #fff !important ; | |||
| } | |||
| } | |||
| .intelligenceType { | |||
| color: rgb(17, 189, 217); | |||
| cursor: pointer; | |||
| } | |||
| .saveBtn { | |||
| text-align: center; | |||
| margin-top: 10px; | |||
| } | |||
| // .tree-select { | |||
| // position: absolute; | |||
| // z-index: 9999999; | |||
| // width: 100%; | |||
| // max-height: 200px; | |||
| // overflow-y: auto; | |||
| // border: 1px solid #dcdfe6; | |||
| // border-radius: 4px; | |||
| // background: #fff; | |||
| // box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); | |||
| // } | |||
| </style> | |||