|
|
@@ -407,38 +407,42 @@
|
|
|
<div class="joblogCon">
|
|
|
<!--顶部日志内容-->
|
|
|
<div class="joblogTop">
|
|
|
-<!-- <p v-for="(item, index) in joblogList" :key="index">filteredJoblogList-->
|
|
|
<p v-for="(item, index) in filteredJoblogList" :key="index">
|
|
|
<span v-html="renderLogContent(item.operationContent)"></span>
|
|
|
</p>
|
|
|
-
|
|
|
</div>
|
|
|
- <!-- 底部查询条件-->
|
|
|
+ <!-- 底部过滤条件-->
|
|
|
<div class="bottomCheck">
|
|
|
-<!-- <el-checkbox :indeterminate="isIndeterminate" v-model="checkjobCheckAll" @change="handleCheckAllChange" class="big-checkbox">全选</el-checkbox>-->
|
|
|
-<!-- <div style="margin: 15px 0 15px 15px;"></div>-->
|
|
|
-<!-- <el-checkbox-group v-model="checkedJoblogs" @change="handleCheckedJoblogsChange" class="big-checkbox">-->
|
|
|
-<!-- <el-checkbox v-for="jobLogtype in jobLogtypes" :label="jobLogtype" :key="jobLogtype" class="big-checkbox">{{jobLogtype}}</el-checkbox>-->
|
|
|
-<!-- </el-checkbox-group>-->
|
|
|
- <el-checkbox-group v-model="checkedJoblogs" @change="handleCheckedJoblogsChange" class="big-checkbox">
|
|
|
+ <el-checkbox
|
|
|
+ :indeterminate="isIndeterminate"
|
|
|
+ :checked="checkAlljoblog"
|
|
|
+ @change="handleCheckAllChange"
|
|
|
+ style="margin:3px 25px;font-size: 16px"
|
|
|
+
|
|
|
+ >
|
|
|
+ 全部
|
|
|
+ </el-checkbox>
|
|
|
+
|
|
|
+ <!-- 多选项 -->
|
|
|
+ <el-checkbox-group
|
|
|
+ v-model="checkedJoblogs"
|
|
|
+ @change="handleCheckedJoblogsChange"
|
|
|
+ class="big-checkbox"
|
|
|
+ >
|
|
|
<el-checkbox
|
|
|
v-for="item in jobLogtypes"
|
|
|
- :label="item.dictValue"
|
|
|
- :key="item.dictValue"
|
|
|
+ :label="item.value"
|
|
|
+ :key="item.value"
|
|
|
class="big-checkbox"
|
|
|
>
|
|
|
- {{ item.dictLabel }}
|
|
|
+ {{ item.label }}
|
|
|
</el-checkbox>
|
|
|
</el-checkbox-group>
|
|
|
-
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
</el-tab-pane>
|
|
|
</el-tabs>
|
|
|
-
|
|
|
-
|
|
|
<el-button style="float: right" type="primary" @click="finshJobticket"
|
|
|
>结束作业
|
|
|
</el-button>
|
|
|
@@ -449,10 +453,21 @@
|
|
|
>取消作业
|
|
|
</el-button>
|
|
|
</el-card>
|
|
|
-
|
|
|
-
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <!-- 作业日志检索内容中未选中类型的新消息-->
|
|
|
+ <el-dialog
|
|
|
+ :visible.sync="JoblogdialogVisible"
|
|
|
+ title="新日志提醒"
|
|
|
+ width="50%"
|
|
|
+ :close-on-click-modal="true"
|
|
|
+ >
|
|
|
+ <div class="joblogTop1">
|
|
|
+ <p>
|
|
|
+ <span v-html="renderLogContent(dialogLog.operationContent)"></span>
|
|
|
+ </p>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
<!-- 添加或修改外部人员对话框 -->
|
|
|
<el-dialog :visible.sync="open" width="1400px" append-to-body>
|
|
|
<div slot="title" class="dialog-title">
|
|
|
@@ -904,6 +919,8 @@ import { selectIsMapById } from '@/api/system/mapconfig'
|
|
|
import { getIsMapPointPage } from '@/api/system/mappoint'
|
|
|
import { getIsSystemAttributeByKey } from '@/api/system/configuration'
|
|
|
import { getDicts } from '@/api/system/dict/data'
|
|
|
+import {connectWebsocket} from "@/utils/websocket";
|
|
|
+import { nextTick } from 'vue';
|
|
|
const joblogsOptions = [];
|
|
|
export default {
|
|
|
name: 'NewSop',
|
|
|
@@ -991,14 +1008,16 @@ export default {
|
|
|
loading: false,
|
|
|
LoadStatus: '',//给LockDetail加弹窗加载
|
|
|
activeName: 'eightSteps', // 默认展示“八大步骤”
|
|
|
+ joblogList:[],//原始作业日志数据列表
|
|
|
+ filteredJoblogList: [], // 过滤后日志
|
|
|
// 作业日志底部查询
|
|
|
- checkJobCheckAll: false,
|
|
|
- isIndeterminate: true,
|
|
|
+ isIndeterminate: false,
|
|
|
checkedJoblogs: [],
|
|
|
jobLogtypes: [],
|
|
|
- labelToValueMap: {},
|
|
|
- joblogList:[]
|
|
|
-
|
|
|
+ joblogsOptions: [], // 只存所有 dictValue,用于全选逻辑,
|
|
|
+ checkAlljoblog: true,
|
|
|
+ JoblogdialogVisible: false,
|
|
|
+ dialogLog: '',
|
|
|
}
|
|
|
},
|
|
|
computed: {
|
|
|
@@ -1006,11 +1025,6 @@ export default {
|
|
|
const stepFour = this.EightStepForm.find((step) => step.stepIndex == '4')
|
|
|
return stepFour && stepFour.stepStatus === '1'
|
|
|
},
|
|
|
- // 日志过滤方式
|
|
|
- filteredJoblogList() {
|
|
|
- return this.joblogList.filter(log => this.checkedJoblogs.includes(log.operationType?.toString()));
|
|
|
- }
|
|
|
-
|
|
|
},
|
|
|
watch: {
|
|
|
tabPosition: function(val, oldVal) {
|
|
|
@@ -1032,12 +1046,18 @@ export default {
|
|
|
this.handlelockerChage(val)
|
|
|
console.log('我制定了')
|
|
|
}
|
|
|
+ },
|
|
|
+ "ticketId": function(val) {
|
|
|
+ if(val){
|
|
|
+ console.log(this.ticketId,val,'JIANRT')
|
|
|
+ this.initWebSocket()
|
|
|
+
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
|
|
|
mounted() {
|
|
|
this.getList()
|
|
|
-
|
|
|
},
|
|
|
|
|
|
|
|
|
@@ -1629,59 +1649,152 @@ export default {
|
|
|
})
|
|
|
}
|
|
|
},
|
|
|
+ // 作业日志连接socket获取数据
|
|
|
+ initWebSocket(){
|
|
|
+ const code= this.ticketId;
|
|
|
+ const address='sys.websocket.address'
|
|
|
+ getIsSystemAttributeByKey(address).then((res) => {
|
|
|
+ // console.log(res, 'websocket地址');
|
|
|
+ this.websocketAddress = res.data.sysAttrValue
|
|
|
+ const isLocalDev = window.location.hostname === 'localhost'
|
|
|
+
|
|
|
+ const baseAddress = isLocalDev
|
|
|
+ ? 'ws://192.168.0.10:9190'
|
|
|
+ : this.websocketAddress;
|
|
|
+ connectWebsocket(
|
|
|
+ `${baseAddress}/websocket/jobTicketLog/${code}`,
|
|
|
+ { w: 'S' },
|
|
|
+ async (res) => {
|
|
|
+ console.log(res, 'websocket接收服务器的作业日志数据');
|
|
|
+ if (res !== 'heartbeat') {
|
|
|
+ // 判断是否需要弹窗显示
|
|
|
+ await this.onNewSocketLog(res); // 👈传入最新的 WebSocket 消息
|
|
|
+ await this.getJoblogs(); // 抽出专用接口函数
|
|
|
+ }
|
|
|
+ },
|
|
|
+ (err) => {
|
|
|
+ console.log('断开重连');
|
|
|
+ }
|
|
|
+ );
|
|
|
+ }).catch(err => {
|
|
|
+ console.error('获取WebSocket地址失败:', err);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
|
|
|
- // 作业日志tab点击事件
|
|
|
- handleTabClick(tab) {
|
|
|
+ // 查询作业日志接口获取
|
|
|
+ async getJoblogs() {
|
|
|
+ const joblogdata = {
|
|
|
+ ticketId: this.ticketId,
|
|
|
+ current: 1,
|
|
|
+ size: -1,
|
|
|
+ };
|
|
|
+ const res = await getIsTicketOperLogPage(joblogdata);
|
|
|
+ // console.log('接口返回日志:', res.data.records);
|
|
|
+ this.joblogList = res.data.records;
|
|
|
+ // ✨强制刷新筛选后的列表
|
|
|
+ this.filterJoblogs();
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // 作业日志tab点击事件
|
|
|
+ async handleTabClick(tab) {
|
|
|
if (tab.name === 'jobLogs') {
|
|
|
- const joblogdata = {
|
|
|
- ticketId: this.ticketId,
|
|
|
- current:1,
|
|
|
- size:-1
|
|
|
- }
|
|
|
- getIsTicketOperLogPage(joblogdata).then((res) => {
|
|
|
- this.joblogList=res.data.records
|
|
|
- console.log(res,'查看作业日志',this.joblogList,'赋值成功了吗')
|
|
|
- })
|
|
|
- console.log(this.ticketId,'是否拿到了作业id')
|
|
|
+ await this.getJoblogs()
|
|
|
}
|
|
|
- getDicts('job_log_type').then(res => {
|
|
|
- console.log(res, '字典值');
|
|
|
- this.jobLogtypes = res.data;
|
|
|
- // 初始化时默认选中全部(或部分)
|
|
|
- this.checkedJoblogs = res.data.map(item => item.dictValue);
|
|
|
- });
|
|
|
|
|
|
+ const dictRes = await getDicts('job_log_type');
|
|
|
+ const dicts = dictRes.data.map(item => ({
|
|
|
+ label: item.dictLabel,
|
|
|
+ value: String(item.dictValue), // 确保是字符串类型
|
|
|
+ }));
|
|
|
+
|
|
|
+ this.jobLogtypes = dicts;
|
|
|
+ this.joblogsOptions = dicts.map(item => item.value);
|
|
|
+ this.checkedJoblogs = [...this.joblogsOptions]; // 初始化全选
|
|
|
+ console.log(this.checkAlljoblog,'选中状态');
|
|
|
+ this.checkAlljoblog = true;
|
|
|
+ console.log(this.checkAlljoblog,'是否选中');
|
|
|
+ this.isIndeterminate = false;
|
|
|
+ this.filterJoblogs();
|
|
|
},
|
|
|
|
|
|
// 作业日志页面数据展示样式分割
|
|
|
renderLogContent(content) {
|
|
|
if (!content) return ''
|
|
|
-
|
|
|
// 第一步:先处理 <url>[label] 为 <img> + label
|
|
|
content = content.replace(/<([^>]+)>\[([^\]]+)\]/g, (match, url, label) => {
|
|
|
return `<img src="${url}" style="height: 25px; vertical-align: middle;"> <span style="color:#007BFF;margin: 0 3px">${label}</span>`
|
|
|
})
|
|
|
-
|
|
|
// 第二步:处理剩下的 [label],转成蓝色字体
|
|
|
content = content.replace(/\[([^\]]+)\]/g, '<span style="color:#007BFF;margin: 0 5px">$1</span>')
|
|
|
-
|
|
|
return content
|
|
|
-
|
|
|
},
|
|
|
|
|
|
-
|
|
|
// 作业日志底部筛选功能
|
|
|
+ handleCheckedJoblogsChange(val) {
|
|
|
+ const checkedCount = val.length;
|
|
|
+ this.checkAlljoblog = checkedCount === this.joblogsOptions.length;
|
|
|
+ this.isIndeterminate = checkedCount > 0 && checkedCount < this.joblogsOptions.length;
|
|
|
+
|
|
|
+ this.filterJoblogs();
|
|
|
+ },
|
|
|
handleCheckAllChange(val) {
|
|
|
- this.checkedJoblogs = val ? joblogsOptions : [];
|
|
|
+ this.checkedJoblogs = val ? [...this.joblogsOptions] : [];
|
|
|
this.isIndeterminate = false;
|
|
|
+ this.filterJoblogs();
|
|
|
},
|
|
|
- handleCheckedJoblogsChange(value) {
|
|
|
- let checkedCount = value.length;
|
|
|
- this.checkjobCheckAll = checkedCount === this.jobLogtypes.length;
|
|
|
- this.isIndeterminate = checkedCount > 0 && checkedCount < this.jobLogtypes.length;
|
|
|
- }
|
|
|
|
|
|
+ // 实际日志筛选逻辑
|
|
|
+ filterJoblogs() {
|
|
|
+ if (this.checkedJoblogs.includes('ALL')) {
|
|
|
+ this.filteredJoblogList = this.joblogList;
|
|
|
+ } else {
|
|
|
+ this.filteredJoblogList = this.joblogList.filter(log =>
|
|
|
+ this.checkedJoblogs.includes(String(log.operationType))
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
|
|
|
+ // 作业日志弹框
|
|
|
+ parseLogString(logStr) {
|
|
|
+ const obj = {};
|
|
|
+ const match = logStr.match(/^[^(]+?\((.*)\)$/);
|
|
|
+ if (!match) return obj;
|
|
|
+ const keyValuePairs = match[1].split(/,\s*(?=\w+=)/); // 处理 "key=value" 中的逗号
|
|
|
+ keyValuePairs.forEach(pair => {
|
|
|
+ const [key, value] = pair.split('=');
|
|
|
+ if (value === 'null') {
|
|
|
+ obj[key] = null;
|
|
|
+ } else if (!isNaN(value)) {
|
|
|
+ obj[key] = Number(value);
|
|
|
+ } else {
|
|
|
+ obj[key] = value;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return obj;
|
|
|
+},
|
|
|
+
|
|
|
+// 判断某条日志是否在当前筛选之外(即是否未被选中)
|
|
|
+ async onNewSocketLog(rawLogStr) {
|
|
|
+ // 1. 将字符串解析为对象
|
|
|
+ const newLog = this.parseLogString(rawLogStr);
|
|
|
+
|
|
|
+ // 2. 获取当前勾选的类型(都转成字符串)
|
|
|
+ const selectedTypes = this.checkedJoblogs.map(String);
|
|
|
+ const newLogType = String(newLog.operationType);
|
|
|
+ // console.log('新日志类型:', newLogType, '勾选类型:', selectedTypes);
|
|
|
+ // 3. 判断是否未被选中 → 弹窗
|
|
|
+ if (!selectedTypes.includes(newLogType)) {
|
|
|
+ this.dialogLog = newLog;
|
|
|
+ this.JoblogdialogVisible = true;
|
|
|
+ // console.log('弹框内容:', newLog);
|
|
|
+ } else {
|
|
|
+ this.JoblogdialogVisible = false;
|
|
|
+ // console.log('该类型已勾选,不弹框');
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
}
|