This commit is contained in:
2025-08-27 17:58:02 +08:00
47 changed files with 4087 additions and 300 deletions

121
package-lock.json generated
View File

@ -22582,6 +22582,12 @@
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
},
"@types/raf": {
"version": "3.4.3",
"resolved": "https://registry.npmmirror.com/@types/raf/-/raf-3.4.3.tgz",
"integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
"optional": true
},
"@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
@ -23971,8 +23977,7 @@
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg=="
},
"autoprefixer": {
"version": "9.8.8",
@ -24159,6 +24164,11 @@
"integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
"dev": true
},
"base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ=="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@ -24472,6 +24482,11 @@
"update-browserslist-db": "^1.0.5"
}
},
"btoa": {
"version": "1.2.1",
"resolved": "https://registry.npmmirror.com/btoa/-/btoa-1.2.1.tgz",
"integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
},
"buffer": {
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
@ -24686,6 +24701,22 @@
"integrity": "sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==",
"dev": true
},
"canvg": {
"version": "3.0.11",
"resolved": "https://registry.npmmirror.com/canvg/-/canvg-3.0.11.tgz",
"integrity": "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA==",
"optional": true,
"requires": {
"@babel/runtime": "^7.12.5",
"@types/raf": "^3.4.0",
"core-js": "^3.8.3",
"raf": "^3.4.1",
"regenerator-runtime": "^0.13.7",
"rgbcolor": "^1.0.1",
"stackblur-canvas": "^2.0.0",
"svg-pathdata": "^6.0.3"
}
},
"case-sensitive-paths-webpack-plugin": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz",
@ -25745,6 +25776,14 @@
}
}
},
"css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"requires": {
"utrie": "^1.0.2"
}
},
"css-loader": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz",
@ -26488,8 +26527,7 @@
"dompurify": {
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.10.tgz",
"integrity": "sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g==",
"dev": true
"integrity": "sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g=="
},
"domready": {
"version": "1.0.8",
@ -27772,6 +27810,11 @@
"websocket-driver": ">=0.5.1"
}
},
"fflate": {
"version": "0.4.8",
"resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz",
"integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
},
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@ -28760,6 +28803,15 @@
}
}
},
"html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"requires": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
}
},
"htmlparser2": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz",
@ -29821,6 +29873,21 @@
"graceful-fs": "^4.1.6"
}
},
"jspdf": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz",
"integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
"requires": {
"@babel/runtime": "^7.14.0",
"atob": "^2.1.2",
"btoa": "^1.2.1",
"canvg": "^3.0.6",
"core-js": "^3.6.0",
"dompurify": "^2.2.0",
"fflate": "^0.4.8",
"html2canvas": "^1.0.0-rc.5"
}
},
"jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
@ -31683,8 +31750,7 @@
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
"dev": true
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
"picocolors": {
"version": "1.0.0",
@ -33304,6 +33370,15 @@
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
"integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
},
"raf": {
"version": "3.4.1",
"resolved": "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz",
"integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
"optional": true,
"requires": {
"performance-now": "^2.1.0"
}
},
"randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@ -33731,6 +33806,12 @@
"integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg==",
"dev": true
},
"rgbcolor": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/rgbcolor/-/rgbcolor-1.0.1.tgz",
"integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
"optional": true
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
@ -34633,6 +34714,12 @@
"integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
"dev": true
},
"stackblur-canvas": {
"version": "2.7.0",
"resolved": "https://registry.npmmirror.com/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
"integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
"optional": true
},
"stackframe": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
@ -35135,6 +35222,12 @@
}
}
},
"svg-pathdata": {
"version": "6.0.3",
"resolved": "https://registry.npmmirror.com/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
"integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
"optional": true
},
"svg-sprite-loader": {
"version": "6.0.11",
"resolved": "https://registry.npmjs.org/svg-sprite-loader/-/svg-sprite-loader-6.0.11.tgz",
@ -35396,6 +35489,14 @@
"resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-6.0.0.tgz",
"integrity": "sha512-1Qncm/9oKM7xgrQXZXNB+NRh19qiXGhxlrR8EwFbK5SaUbPZnS5OMtP/ghtqfd23hsr1ZvZbZjeuAGcMxd/ooA=="
},
"text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"requires": {
"utrie": "^1.0.2"
}
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -36012,6 +36113,14 @@
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"dev": true
},
"utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"requires": {
"base64-arraybuffer": "^1.0.2"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",

View File

@ -30,7 +30,9 @@
"file-saver": "^2.0.5",
"fzui-fengqun-vue": "^1.0.1",
"gifler": "^0.1.0",
"html2canvas": "^1.4.1",
"image-compressor.js": "^1.1.4",
"jspdf": "^2.5.1",
"lodash": "^4.17.21",
"mitt": "^3.0.0",
"moment": "^2.30.1",

135
src/api/semanticAnalysis.js Normal file
View File

@ -0,0 +1,135 @@
import request from "@/utils/request";
const api = "/mosty-api/mosty-gsxt";
const v1 = "/v1"
/**
* 警情列分页查询
* @param {*} params
* @returns
*/
export const lzJcjPjdbSelectPage = (params) => {
return request({
url: api + "/lzJcjPjdb/selectPage",
method: "GET",
params
});
};
//
/**
* 语义分析分页查询
* @param {*} params
* @returns
*/
export const yyfxSelectPage = (params) => {
return request({
url: api + "/yyfx/selectPage",
method: "GET",
params
});
};
/**
* 身份标签
* @param {*} params
* @returns
*/
export const tbGsxtBqglSelect = (params) => {
return request({
url: api + "/tbGsxtBqgl/selectList",
method: "GET",
params
});
};
/**
* 新增
* @param {*} params
* @returns
*/
export const yyfxAdd = (data) => {
return request({
url: api + "/yyfx/add",
method: "POST",
data
});
};
export const completions = (data) => {
return request({
url: v1 + "/completions",
method: "POST",
data
});
};
// /
// 分析报告-地域维度统计
export const fxbgDywdtj = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgDywdtj",
method: "GET",
params
});
};
// 警情类别接口
export const getDictItem = (params) => {
return request({
url: api + "/lzJcjPjdb/getDictItem",
method: "GET",
params
});
}
// 分析报告 - 警情类型统计
export const fxbgJqlxtj = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgJqlxtj",
method: "GET",
params
});
}
// 警情来源统计
export const fxbgJqlytj = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgJqlytj",
method: "GET",
params
});
}
// 分析报告
export const fxbgTj = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgTj",
method: "GET",
params
});
}
// 分析报告-时间维度-月分析
export const fxbgYdfx = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgYdfx",
method: "GET",
params
});
}
// 分析报告-时间维度-24小时分析
export const fxbgXsfx = (params) => {
return request({
url: api + "/lzJcjPjdb/fxbgXsfx",
method: "GET",
params
});
}
// 分析报告 - 处理结果分析
export const fxgbCljgf = (params) => {
return request({
url: api + "/lzJcjPjdb/fxgbCljgfx",
method: "GET",
params
});
}
// 分析报告-处置率分析
export const fxgbCzlfx = (params) => {
return request({
url: api + "/lzJcjPjdb/fxgbCzlfx",
method: "GET",
params
});
}

View File

@ -2,6 +2,8 @@ import request from "@/utils/request";
import axios from "axios";
import qs from 'qs'; // 或者使用 URLSearchParams
const api = "/bpm";
const flowApproval = "/flowApproval";
const orgOrganization = '/orgOrganization'
// 解析数据
export function ParsingText(data, fun) {
axios({
@ -16,6 +18,7 @@ export function ParsingText(data, fun) {
//get 请求
export const splFlvGet = (params = {}, url) => {
return request({
url: url,
@ -53,6 +56,7 @@ export const splPut = (data = {}, url) => {
//put 请求
export const splDelete = (data = {}, url) => {
return request({
url: api + url,
method: "delete",
data
@ -96,5 +100,35 @@ export const queryProcess = (data) => {
});
};
export const queryUserListByRule = (params) => {
return request({
url: flowApproval + '/queryUserListByRule',
method: 'get',
params
});
};
export const queryListByEntity = (params) => {
return request({
url: orgOrganization + '/queryListByEntity',
method: 'get',
params
});
};
export const querysingleByEntity = (params) => {
return request({
url: orgOrganization + '/querySingleByEntity',
method: 'get',
params
});
};
export const queryUporgsByEntity = (params) => {
return request({
url: orgOrganization + '/queryUpOrgsByEntity',
method: 'get',
params
});
};

View File

@ -5,17 +5,19 @@ header {
display: flex;
justify-content: space-between;
align-items: center;
.logo{
.logo {
white-space: nowrap;
padding-left: 8px;
font-size:55px;
font-size: 55px;
letter-spacing: 1px;
font-family: "YSBTH";
background: linear-gradient(180deg, #FFFFFF 52.4658203125%, #89AFCF 100%);
-webkit-background-clip: text;
-webkit-text-fill-color:transparent ;
text-shadow: 4px 4px 4px rgba(255,255,255,0.15);
-webkit-text-fill-color: transparent;
text-shadow: 4px 4px 4px rgba(255, 255, 255, 0.15);
}
.right {
display: flex;
height: 100%;
@ -23,9 +25,11 @@ header {
z-index: 1999;
position: relative;
padding-right: 10px;
.detail {
display: flex;
cursor: pointer;
.hd {
white-space: nowrap;
color: #ffffff;
@ -102,6 +106,7 @@ header {
color: #333;
padding: 20px;
box-sizing: border-box;
.head_box {
height: 48px;
border-bottom: 1px solid #F1F4F8;
@ -109,10 +114,12 @@ header {
display: flex;
justify-content: space-between;
align-items: center;
.title{
.title {
position: relative;
padding-left: 10px;
&::before{
&::before {
position: absolute;
content: '';
top: 0;
@ -125,7 +132,7 @@ header {
}
}
.form_cnt{
.form_cnt {
padding-top: 10px;
box-sizing: border-box;
height: calc(100vh - 223px);
@ -180,6 +187,10 @@ header {
box-sizing: border-box;
background: #e9edf6;
.tabDataBox {
border-radius: 4px;
}
.titleBox {
height: 50px;
display: flex;
@ -211,6 +222,7 @@ header {
background: #fff;
border-radius: 4px;
height: calc(100vh - 327px);
.el-table--fit {
width: calc(100% - 20px) !important;
position: absolute;
@ -220,6 +232,7 @@ header {
height: calc(100% - 100px);
overflow: auto;
}
.fenye {
background: #fff;
border-width: 0 1px 1px 1px;
@ -227,7 +240,8 @@ header {
right: 0px;
left: 0px;
padding-right: 10px;
.el-pagination{
.el-pagination {
display: flex;
align-items: center;
justify-content: flex-end;
@ -275,22 +289,27 @@ header {
}
}
.content-box-sun{
.content-box-sun {
display: flex;
.org-box{
.org-box {
flex: 1;
.org-content-box {
width: 95%;
.org-search-box {
display: flex;
}
.tree-box{
.tree-box {
height: 750px;
overflow: auto;
}
}
}
.right-box-sun{
.right-box-sun {
flex: 4;
}
}
@ -301,6 +320,7 @@ header {
justify-content: space-between;
position: relative;
z-index: 2;
.title {
height: 60px;
line-height: 60px;

Binary file not shown.

After

Width:  |  Height:  |  Size: 389 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

View File

@ -267,8 +267,14 @@ const changeRadio = (val) =>{
texts.value = [];
image.value = '';
fjmc.value = '';
if(val == '图片解析'){
if(!imgIsLoad) proxy.$message({ type: "error", message: "加载失败,请刷新页面" });
if (val == '图片解析') {
if (!imgIsLoad) {
proxy.$message({ type: "error", message: "加载失败,请刷新页面" })
// frashJs()
};
}
}

View File

@ -46,15 +46,11 @@ const mMap = ref(null); //地图对象
const mapUtil = ref(null); //地图工具对象
const zoomTarget = ref(6);
// 定义组件发出的事件
const emit = defineEmits(['mapLoaded'])
const props = defineProps({
mapid: {
type: String,
default: "mapDiv"
},
//是否显示可以切换地图底图
isShow: {
type: Boolean,
@ -110,17 +106,48 @@ onMounted(() => {
}
});
// window.map = map;
// map.mapboxGLMap.on("load", () => {
// map.addGaudLayer({
// url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
// })
// zoomTarget.value = map.mapboxGLMap.getZoom();
// // 地图加载完成后发出事件
// emit('mapLoaded')
// });
// mapUtil.value = new MapUtil(map);
map = new EliMap({
id: props.mapid,
crs: "EPSG:4490",
style: {
glyphs: "./fonts/{fontstack}/{range}.pbf",
center: [94.36057012, 29.64276831],
zoom: 15
},
minZoom: 7,
maxZoom: 18,
});
window.map = map;
map.mapboxGLMap.on("load", () => {
map.addGaudLayer({
url: 'http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}',
})
map.addWMTSLayer(
"/PGIS_S_TileMapServer/Maps/XZDJ_SL/EzMap"
,
{
Service: "getImage",
Type: "RGB",
ZoomOffset: "0",
V: "0.3",
Zoom: "{z}",
Row: "{y}",
Col: "{x}"
},
{
tileSize: 300
}
);
zoomTarget.value = map.mapboxGLMap.getZoom();
// 地图加载完成后发出事件
emit('mapLoaded')
});
mapUtil.value = new MapUtil(map);
mapUtil.value.Drawplot(); //初始化加载绘制工具
// 设置地图中心点及图层

View File

@ -19,7 +19,7 @@
:highlight-current-row="getConfiger.showSelectType === 'radio'"
:row-style="{ height: getConfiger.rowHeight === 'auto' ? getConfiger.rowHeight : getConfiger.rowHeight + 'px'}"
>
<el-table-column type="selection" width="55" />
<el-table-column style="width: 55px" type="selection" width="55" v-if="getConfiger.showSelectType === 'radio' ? 'tabBoxRadio' : ''" />
<el-table-column
type="index"
label="序号"

View File

@ -1,34 +1,35 @@
<template>
<div class="smallTitle">审批信息</div>
<div class="ww100">
<el-steps :active="0" space="500" finish-status="success" direction="vertical" status=''>
<el-step :title="item.eventType == '0' ? '发起申请' : item.eventType == '1' ? '审批结束' : item.nodeName"
v-for="(item, index) in workflow" :key="index">
<template #description>
<div class="ww100 mt10 mb20 nodeBox" v-if="item.eventType == '0'||item.eventType == '1'">
<div class="nodeorgNameTg">{{ item.xtLrrbm }}</div>
<div class="flex just-between nameTag">
<div>{{ item.log.userName }}</div>
<div class="fontColor">{{ item.eventType == '0' ? '发起' : '结束' }}</div>
</div>
<div>{{ item.log.xtLrsj }}</div>
<div class="smallTitle">审批信息</div>
<div class="ww100">
<el-steps :active="0" space="500" finish-status="success" direction="vertical" status=''>
<el-step :title="item.eventType == '0' ? '发起申请' : item.eventType == '1' ? '审批结束' : item.nodeName"
v-for="(item, index) in workflow" :key="index">
<template #description>
<div class="ww100 mt10 mb20 nodeBox" v-if="item.eventType == '0' || item.eventType == '1'">
<div class="nodeorgNameTg">{{ item.xtLrrbm }}</div>
<div class="flex just-between nameTag">
<div>{{ item.xtLrrxm}}</div>
<div class="fontColor">{{ item.eventType == '0' ? '发起' : '结束' }}</div>
</div>
<div>{{ item.xtLrsj }}</div>
</div>
<div v-else class="ww100 mt10 mb20 nodeBox">
<div :class="item.taskStatus == '2' ? 'nodeorgNameTg' : 'nodeorgNameDd'">{{ item.nodeName }}</div>
<!-- <div v-for="(items, indexs) in item.log" :key="indexs"> -->
<div class="flex just-between nameTag">
<div>{{ item.logNode.userName }}</div>
<div :class="item.taskStatus == '2' ? 'fontColor' : 'fontColorDd'">
{{ item.taskStatus == '2' ? '已审批' : '审批中' }}
</div>
<div v-else class="ww100 mt10 mb20 nodeBox">
<div :class="item.taskStatus=='2'?'nodeorgNameTg':'nodeorgNameDd'">{{ item.orgNameData.orgname }}</div>
<div v-for="(items, indexs) in item.log" :key="indexs">
<div class="flex just-between nameTag" >
<div>{{ items.userName }}</div>
<div :class="item.taskStatus=='2'?'fontColor':'fontColorDd'">审批中</div>
</div>
<div>{{ items.xtLrsj }}</div>
</div>
</div>
<div>{{ item.logNode.xtZhxgsj }}</div>
<!-- </div> -->
</div>
</template>
</el-step>
</div>
</template>
</el-step>
</el-steps>
</div>
</el-steps>
</div>
</template>
<script setup>
@ -42,97 +43,57 @@ const getWorkflow = async (id) => {
const process = await queryProcess(promes)
const proNode = await queryProcessNode(promes)
const proNodeLog = await queryProcessNodeLog(promes)
const sortedNodes = sortNodesWithNoPreviousFirst(proNode.rows)
workflow.value = sortedNodes.map(item => {
const log = proNodeLog.rows.filter(items => item.nodeId == items.nodeId)
if (item.eventType == '0') {
console.log(item);
return {
...item,
log: {
// userData: JSON.parse(item.userData),
// xtLrrbm:process.rows[0].xtLrrbm,
userName: process.rows[0].userName,
xtLrsj: process.rows[0].xtLrsj,
processStatus: process.rows[0].processStatus,
}
}
} else {
return {
...item,
orgNameData: JSON.parse(log[0].userData),
log: log
}
let newProNode = proNode.rows.filter(item => item.eventType == '0')
const decisionPNodeId = proNode.rows.map(item => {
const log = proNodeLog.rows.find(items => items.nodeId == item.nodeId)
return {
...item,
logNode: log ? log : ""
}
})
};
workflow.value = sortNodesByFlow(decisionPNodeId)
console.log(workflow.value);
function sortProcessNodes(nodes) {
// 1. 创建节点映射表和子节点关系图
const nodeMap = {};
const childrenMap = {}; // 存储每个节点的子节点
}
// 初始化
nodes.forEach(node => {
nodeMap[node.nodeId] = node;
childrenMap[node.nodeId] = [];
});
// 2. 构建子节点关系
nodes.forEach(node => {
if (node.prevPNodeId && nodeMap[node.prevPNodeId]) {
childrenMap[node.prevPNodeId].push(node.nodeId);
}
});
// 3. 找到所有开始节点没有prevPNodeId或prevPNodeId不在节点列表中的节点
const startNodes = nodes.filter(node =>
!node.prevPNodeId || !nodeMap[node.prevPNodeId]
);
// 4. 深度优先遍历生成排序列表
const sortedNodes = [];
const visited = new Set();
function traverse(nodeId) {
if (visited.has(nodeId)) return;
visited.add(nodeId);
// 添加当前节点
sortedNodes.push(nodeMap[nodeId]);
// 获取所有子节点相同prevPNodeId的节点
const children = childrenMap[nodeId];
// 对子节点按某种规则排序(如按创建时间)
const sortedChildren = [...children].sort((a, b) => {
return new Date(nodeMap[a].xtLrsj) - new Date(nodeMap[b].xtLrsj);
});
// 递归处理每个子节点
sortedChildren.forEach(childId => {
traverse(childId);
});
function sortNodesByFlow(nodes) {
// 找到首节点eventType为0的节点
const startNode = nodes.find(node => node.eventType === "0");
if (!startNode) {
console.error("未找到首节点");
return nodes;
}
// 从每个开始节点开始遍历
startNodes.forEach(node => {
traverse(node.nodeId);
});
// 创建排序后的节点数组
const sortedNodes = [startNode];
// 5. 处理可能的孤立节点(不应该存在,但作为保护)
// 使用Map提高查找效率
const nodeMap = new Map();
nodes.forEach(node => {
if (!visited.has(node.nodeId)) {
sortedNodes.push(node);
if (node.pNodeId) {
nodeMap.set(node.pNodeId, node);
}
});
// 当前节点指针
let currentNode = startNode;
// 循环查找下一个节点
while (true) {
// 查找下一个节点prevPNodeId等于当前节点的pNodeId
const nextNode = nodes.find(node => node.prevPNodeId === currentNode.pNodeId);
if (!nextNode) {
break; // 没有下一个节点,结束循环
}
sortedNodes.push(nextNode);
currentNode = nextNode;
}
return sortedNodes;
}
function sortNodesWithNoPreviousFirst(nodes) {
if (!Array.isArray(nodes)) {
console.error('参数必须是一个数组');
@ -147,7 +108,7 @@ function sortNodesWithNoPreviousFirst(nodes) {
if (node && node.nodeId) {
map[node.nodeId] = node;
}
console.log(node,"xxxxxx");
console.log(node, "xxxxxx");
return map;
}, {});
@ -250,9 +211,11 @@ defineExpose({
color: #000000 !important;
border-color: #000000 !important;
}
::v-deep .el-step__description{
::v-deep .el-step__description {
padding: 0 !important;
}
::v-deep .el-step__description.is-wait {
color: #000000 !important;
@ -296,7 +259,9 @@ defineExpose({
.fontColor {
color: #1abe20;
} .fontColorDd {
}
.fontColorDd {
color: #18a2dd;
}
}

View File

@ -0,0 +1,533 @@
<template>
<el-dialog class="dialog-container" :model-value="modelValue" :title="titles" :before-close="close">
<div v-loading="loading">
<div class="dialog-header" v-if="showModel">
<div class="flex align-center">下一节点
<el-checkbox-group v-model="checkList" @change="handleCheckAllChange">
<el-checkbox v-model="showNode" :label="item.nodeId" size="large" v-for="(item, index) in modelData"
:key="index">{{ item.nodeName }}</el-checkbox>
</el-checkbox-group>
</div>
<!-- <div> <el-button type="success" :icon="Plus" @click="newAdditions" /></div> -->
</div>
<div class="container-box">
<div v-for="(item, index) in userList" :key="item.id">
<div v-if="checkList.includes(item.nodeId)">
<el-divider content-position="left">{{ item.nodeName }}</el-divider>
<div class="reloBox">
<div class="orgName">{{ item.userList.name }}</div>
<el-checkbox-group v-model="item.checkList">
<el-checkbox :label="items.userid" v-for="(items, index) in item.userList.users" :key="items.id">{{
items.username }}</el-checkbox>
</el-checkbox-group>
</div>
</div>
</div>
</div>
</div>
<!-- <div v-if="showNode && showModel">
<div v-if="flwsNode.flwsUserNode?.role.length == 0">
<div class="row" v-for="(item, index) in nodeData" :key="index">
<MOSTY.Department filterable v-model="item.deptId" width="100%"
@getDepValue="(obj) => changePostList(index, obj)" clearable placeholder="请选择所属部门" />
<el-select class="select-user" v-model="item.userId" filterable placeholder="选择审批人"
@change="changeUser(index)">
<el-option v-for="item in item.listData" :key="item.id" :label="item.userName" :value="item.id" />
</el-select>
<div>
<el-button type="danger" @click="newDelitions(index)">删除</el-button>
</div>
</div>
</div>
<div v-else>
</div>
</div> -->
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="qcckPostList">
确认
</el-button>
</div>
</template>
</el-dialog>
</template>
<script>
</script>
<script setup>
import { ref, getCurrentInstance, reactive, watch } from 'vue'
import { qcckGet, qcckPost } from '@/api/qcckApi'
import { splGet, splPost, submitProcess, queryUserListByRule } from '@/api/spl'
import { getItem } from '@/utils/storage'
import { Plus } from '@element-plus/icons-vue'
import * as MOSTY from "@/components/MyComponents/index";
const { proxy } = getCurrentInstance();
const props = defineProps({
modelValue: {
type: Boolean,
required: true
}, title: {
type: String,
default: '发起流程'
},
createProcess: {
type: Object,
default: () => { }
}, radioData: {
type: String,
default: ''
}, path: {
type: Object,
default: {
byMeansOf: '',
nobyMeansOf: '',
clueVerification: "",
recycle: ""
}
}, userData: {
type: Object,
default: () => {
return {
ajmc: "",
flowType: ""
}
}
}
})
const emit = defineEmits(['update:modelValue', 'close', 'getList'])
const titles = ref(props.title)
const showNode = ref(true)
// const InterfaceAddress = 'http://155.24.22.30:2109/mosty-api/mosty-gsxt/'
const InterfaceAddress = 'http://192.168.0.231:8006/mosty-api/mosty-gsxt/'
// 新增
const nodeData = ref([
{
deptId: '',
userId: '',
userData: {},
orgData: {},
}
])
//新增表单
const newAdditions = () => {
nodeData.value.push({
deptId: '',
userId: '',
userData: {},
orgData: {},
listData: []
})
}
// 删除表单
const newDelitions = (item) => {
nodeData.value.splice(item, 1)
}
const chageIndex = ref(0)
// 选取角色
const changeUser = (index) => {
chageIndex.value = index
let obj = nodeData.value[index].listData.find(item => { return item.id == nodeData.value[index].userId })
nodeData.value[index].userData = {
userId: obj.userId,
userName: obj.userName,
sfzh: obj.idEntityCard,
userData: {
// id: '41fbffaf92a34b31bde6302004277486',
// orgid: '41fbffaf92a34b31bde6302004277486',
id: orgId.value,
orgid: orgId.value,
orgcode: obj.deptCode,
orgname: obj.deptName
}
}
}
//选取部门
const orgId = ref()
const changePostList = (index, e) => {
orgId.value = e.fzOrgId
chageIndex.value = index
nodeData.value[chageIndex.value].id = e.id
nodeData.value[chageIndex.value].orgData = {
id: orgId.value,
orgid: orgId.value,
// id: '41fbffaf92a34b31bde6302004277486',
// orgid: '41fbffaf92a34b31bde6302004277486',
orgcode: e.orgCode,
orgname: e.orgName
}
getUser()
}
const newUserData = ref({})
const transformData = (nodeData) => {
const { userList, checkList } = nodeData;
const { id: orgid, code: orgcode, name: orgname, users } = userList;
const checkListSet = new Set(checkList);
const filteredUsers = users.filter(user => checkListSet.has(user.userid));
return filteredUsers.map(user => {
newUserData.value = JSON.stringify({
id: user.id,
orgid,
orgcode,
orgname
})
return {
userId: user.userid,
userName: user.username,
userData: newUserData.value
}
}
)
};
const checkListData = ref()
// 删除
const handleCheckAllChange = (e) => {
const checkListSet = new Set(e);
checkListData.value = userList.value.filter(item => checkListSet.has(item.nodeId));
}
// 提交
const qcckPostList = async () => {
const data = {}
const listError = []
for (let i = 0; i < checkListData.value.length; i++) {
if (checkListData.value[i].checkList && checkListData.value[i].checkList.length > 0) {
data[checkListData.value[i].nodeId] = transformData(checkListData.value[i]);
} else {
listError.push(checkListData.value[i].nodeName)
}
}
if (listError.length > 0) {
proxy.$message({ type: "warning", message: listError.join('、') + '请选择审批人' });
return
}
const submitData = {
...props.createProcess,
flowType: "ZyCompany",
callback: {
"START": "",//流程开始
"APPROVE": "",//节点审批通过
"BACK": "",//退回上一节点
"REVOKE": "",//撤回审批
"DONE": `${InterfaceAddress}${props.path.byMeansOf}?id=${props.createProcess.processData.rwbh}&bkZt=05`,//流程审批通过
"ABORT": `${InterfaceAddress}${props.path.nobyMeansOf}?id=${props.createProcess.processData.rwbh}&bkZt=06`,//审批不通过
"RECOVER": "",//流程回收
"AGAIN": `${InterfaceAddress}${props.path.recycle}?id=${props.createProcess.processData.rwbh}&bkZt=07`//流程退回初始
},
decision: JSON.stringify({
...data,
services: [],
events: [],
userData: newUserData.value,
})
}
console.log(submitData);
submitData.processData = JSON.stringify(submitData.processData)
submitData.callback = JSON.stringify(submitData.callback)
await submitProcess({ ...submitData }).then(res => {
proxy.$message({ type: "success", message: "提交审批成功" });
sendMessage(res.rows[0])
})
// await emit('getList')
// emit('close')
// close()
}
// const deptId = getItem('deptId')
// let users = nodeData.value.map(item => {
// return {
// userId: item.userData.userId,
// // userId: '540422200010197495',
// userName: item.userData.userName,
// userData: JSON.stringify(item.userData.userData)
// // ...item.userData
// }
// })
// let userData = {
// id: deptId[0].fzOrgId,
// orgid: deptId[0].fzOrgId,
// // id: '41fbffaf92a34b31bde6302004277486',
// // orgid: '41fbffaf92a34b31bde6302004277486',
// orgcode: deptId[0].deptCode,
// orgname: deptId[0].deptName,
// }
// const promes = {
// ...props.createProcess,
// // processData: { ...props.createProcess.processData.sqrw, orgNameData: userData },
// flowType: "ZyCompany",
// // iframe: `/#/${props.path.clueVerification}?id=${props.createProcess.processData.rwbh}`,
// callback: {
// "START": "",//流程开始
// "APPROVE": "",//节点审批通过
// "BACK": "",//退回上一节点
// "REVOKE": "",//撤回审批
// "DONE": `${InterfaceAddress}${props.path.byMeansOf}?id=${props.createProcess.processData.rwbh}&bkZt=05`,//流程审批通过
// "ABORT": `${InterfaceAddress}${props.path.nobyMeansOf}?id=${props.createProcess.processData.rwbh}&bkZt=06`,//审批不通过
// "RECOVER": "",//流程回收
// "AGAIN": `${InterfaceAddress}${props.path.recycle}?id=${props.createProcess.processData.rwbh}&bkZt=07`//流程退回初始
// },
// decision: JSON.stringify({
// [modelData.value.nodeId]: {
// users: users,
// services: [],
// events: [],
// userData: JSON.stringify(userData)
// }
// })
// }
// promes.processData = JSON.stringify(promes.processData)
// promes.callback = JSON.stringify(promes.callback)
// console.log(promes);
// await submitProcess({ ...promes }).then(res => {
// proxy.$message({ type: "success", message: "提交审批成功" });
// sendMessage(res.rows[0])
// })
// await emit('getList')
// emit('close')
// close()
//获取角色
const getUser = () => {
const promes = {
size: 200, current: 1,
deptId: nodeData.value[chageIndex.value].id
}
qcckGet(promes, '/mosty-base/sysUser/selectPage').then(res => {
nodeData.value[chageIndex.value].listData = res.records
})
}
const showModel = ref(true)
//查询模板
const modelData = ref({})
const modelMsg = ref()
const nodeDetails = ref({})
const loading = ref(false)
const flwsNode = ref({})
const userList = ref()
//节点审核人
const checkList = ref()
const endpoints = [
'/modelVersion/queryModelVersion',
'/modelVersion/queryModelNode',
'/modelVersion/queryModelSequenceFlow',
'/modelVersion/queryModelReachability'
]
const queryModel = async () => {
try {
loading.value = true
const prrmes = {
modelId: props.radioData,
modelStatus: 1
}
const res = await splPost(prrmes, '/model/queryModel')
if (res.rows.length > 0) {
const resData = await Promise.all(endpoints.map(item => {
return splPost({ modelVersionId: res.rows[0].currentVersionId }, item)
}))
const rootNode = resData[1].rows.find(item => item.eventType == '0')
const sequenceNode = resData[2].rows.find(item => item.sourceNodeId == rootNode.nodeId)
const eventNode = resData[1].rows.find(item => item.nodeType == '1' && item.nodeId == sequenceNode.targetNodeId)
// 如果是事件节点
if (eventNode) {
console.log(eventNode);
const nodeExtension = JSON.parse(eventNode.nodeExtension)
console.log(nodeExtension);
modelData.value = [eventNode]
checkList.value = modelData.value.map(item => {
return item.nodeId
})
const res = await queryUserListByRule({ roles: '', posts: "", orgid: "eebefa725cb546118d6b2d17c8657ef3" })
checkListData.value = userList.value = modelData.value.map((item, index) => {
return { ...item, userList: res.rows[0] }
})
} else {
const targetNodeId = resData[2].rows.filter(item => item.sourceNodeId == sequenceNode.targetNodeId).map(item => item.targetNodeId)
console.log(targetNodeId);
const targetIdSet = new Set(targetNodeId);
modelData.value = resData[1].rows.filter(item => targetIdSet.has(item.nodeId));
checkList.value = modelData.value.map(item => {
return item.nodeId
})
const nodeExtension = modelData.value.map(item => {
return JSON.parse(item.nodeExtension)
})
const roles = nodeExtension.map(item => {
return queryUserListByRule({ roles: '', posts: "", orgid: "eebefa725cb546118d6b2d17c8657ef3" })
})
const a = await Promise.all(roles)
checkListData.value = userList.value = modelData.value.map((item, index) => {
return { ...item, userList: a[index].rows[0] }
})
}
// const targetIdSet = new Set(targetNodeId);
// modelData.value = resData[1].rows.filter(item => targetIdSet.has(item.nodeId));
// checkList.value = modelData.value.map(item => {
// return item.nodeId
// })
// console.log( modelData.value);
// const nodeExtension = modelData.value.map(item => {
// console.log(item);
// return JSON.parse(item.nodeExtension)
// })
// const roles = nodeExtension.map(item => {
// return queryUserListByRule({ roles: '', posts: "", orgid: "eebefa725cb546118d6b2d17c8657ef3" })
// })
// console.log(roles);
// const a = await Promise.all(roles)
// checkListData.value = userList.value = modelData.value.map((item, index) => {
// return { ...item, userList: a[index].rows[0] }
// })
} else {
proxy.$message({ type: "error", message: "模板不存在" });
showModel.value = false
}
} catch (error) {
} finally {
loading.value = false
}
}
// queryModelVersion(res.rows[0].currentVersionId)
// queryModelNode(res.rows[0].currentVersionId)
// modelMsg.value = versionRes.rows[0]
// const nodeRes = await splPost({ modelVersionId: res.rows[0].currentVersionId }, '/modelVersion/queryModelNode')
// if (versionRes.rows.length > 0) {
// modelData.value = nodeRes.rows.filter(item => item.nodeType == '1')[0]
// }
//发消息
const sendMessage = (gzlid) => {
const bkshrSfzh = nodeData.value.map(item => {
return {
bkshrXm: item.userData.userName,
bkshrSfzh: item.userData.sfzh,
bkshrSsbmmc: item.userData.userData.orgname,
bkshrSsbmdm: item.userData.userData.orgcode,
}
})
const promes = {
xxly: '005',
gzlid: gzlid,
list: bkshrSfzh,
versionId: modelMsg.value.modelVersionId,
id: props.createProcess.processData.rwbh
}
switch (props.userData.flowType) {
case 'BKSP':
qcckPost(promes, '/mosty-gsxt/tbGsxtBk/updateBkgzl').then(res => {
console.log(res);
})
break;
case 'ZDRYSDFJDP':
qcckPost(promes, '/mosty-gsxt/tbGsxtRqfjRy/updateBkgzl').then(res => {
console.log(res);
})
break;
case 'XSSJCJSP':
qcckPost(promes, '/mosty-gsxt/qbcj/updateBkgzl').then(res => {
console.log(res);
})
break;
}
}
watch(() => props.modelValue, (val) => {
if (val) {
queryModel()
}
})
const close = () => {
nodeData.value = [
{
deptId: '',
userId: '',
userData: {},
orgData: {},
}
]
emit('update:modelValue', false)
}
</script>
<style lang="scss" scoped>
@import "@/assets/css/homeScreen.scss";
::v-deep .el-dialog__body {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.container-box {
// height: 300px;
min-height: 300px;
overflow: auto;
// border: 1px solid rgba(172, 172, 172, 0.479);
padding: 10px;
max-height: 500px;
// border-radius: 5px;
.row {
margin-top: 10px;
align-items: center;
display: flex;
margin-right: 10px;
.select-user {
margin: 0 10px;
}
}
.reloBox {
position: relative;
padding: 0 10px;
border: 1px solid rgba(192, 192, 192, 0.426);
border-radius: 5px;
min-height: 100px;
margin-bottom: 20px;
.orgName {
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
padding: 0 10px;
background-color: #fff;
}
}
}
</style>

View File

@ -1,31 +1,65 @@
<template>
<el-dialog class="dialog-container" :model-value="modelValue" :title="titles" :before-close="handleClose">
<div class="dialog-header">
<div class="flex align-center">下一节点
<el-checkbox v-model="showNode" :label="modelData.nodeName" size="large" />
<el-dialog class="dialog-container" :model-value="modelValue" :title="titles" :before-close="close">
<div v-loading="loading">
<div class="dialog-header" v-if="showModel">
<div class="flex align-center">下一节点
<el-checkbox-group v-model="checkList" @change="handleCheckAllChange">
<el-checkbox v-model="showNode" :label="item.nodeId" size="large" v-for="(item, index) in modelData"
:key="index">{{ item.nodeName }}</el-checkbox>
</el-checkbox-group>
</div>
<div> <el-button type="success" :icon="Plus" @click="newAdditions" v-if="optional"/></div>
</div>
<div> <el-button type="success" :icon="Plus" @click="newAdditions" /></div>
</div>
<div class="container-box">
<div v-if="showNode">
<el-divider content-position="left">节点</el-divider>
<div>
<div class="row" v-for="(item, index) in nodeData" :key="index">
<MOSTY.Department filterable v-model="item.deptId" width="100%"
@getDepValue="(obj) => changePostList(index, obj)" clearable placeholder="请选择所属部门" />
<el-select class="select-user" v-model="item.userId" filterable placeholder="选择审批人"
@change="changeUser(index)">
<el-option v-for="item in item.listData" :key="item.id" :label="item.userName" :value="item.id" />
</el-select>
<div>
<el-button type="danger" @click="newDelitions(index)">删除</el-button>
<div v-if="optional" class="container-box">
<!-- <div v-if="flwsNode.flwsUserNode?.role.length == 0"> -->
<div class="row" v-for="(item, index) in nodeData" :key="index">
<MOSTY.Department filterable v-model="item.deptId" width="100%"
@getDepValue="(obj) => changePostList(index, obj)" clearable placeholder="请选择所属部门" />
<el-select class="select-user" v-model="item.userId" filterable placeholder="选择审批人"
@change="changeUser(index)">
<el-option v-for="item in item.listData" :key="item.id" :label="item.userName" :value="item.id" />
</el-select>
<div>
<el-button type="danger" @click="newDelitions(index)">删除</el-button>
</div>
</div>
<!-- </div> -->
</div>
<div class="container-box" v-else>
<div v-for="(item, index) in userList" :key="item.id">
<div v-if="checkList.includes(item.nodeId)">
<el-divider content-position="left">{{ item.nodeName }}</el-divider>
<template v-if="Array.isArray(item.userList)">
<div class="reloBox" v-for="items in item.userList">
<div class="orgName">{{ items.name }}</div>
<el-checkbox-group v-model="items.checkList">
<el-checkbox :label="it.userid" v-for="(it, index) in items.users" :key="it.id">{{
it.username }}</el-checkbox>
</el-checkbox-group>
</div>
</template>
<template v-else>
<div class="reloBox">
<div class="orgName">{{ item.userList.name }}</div>
<el-checkbox-group v-model="item.checkList">
<el-checkbox :label="it.userid" v-for="(it, index) in item.userList.users" :key="it.id">{{
it.username }}</el-checkbox>
</el-checkbox-group>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
<div v-if="showNode && showModel">
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
@ -42,7 +76,7 @@
<script setup>
import { ref, getCurrentInstance, reactive, watch } from 'vue'
import { qcckGet, qcckPost } from '@/api/qcckApi'
import { splGet, splPost, submitProcess } from '@/api/spl'
import { splGet, splPost, submitProcess, queryUserListByRule, queryListByEntity, querysingleByEntity, queryUporgsByEntity } from '@/api/spl'
import { getItem } from '@/utils/storage'
import { Plus } from '@element-plus/icons-vue'
import * as MOSTY from "@/components/MyComponents/index";
@ -83,7 +117,6 @@ const props = defineProps({
const emit = defineEmits(['update:modelValue', 'close', 'getList'])
const titles = ref(props.title)
const showNode = ref(true)
const InterfaceAddress = 'http://155.2422.30:2109/mosty-api/mosty-gsxt/'
// 新增
const nodeData = ref([
@ -128,14 +161,14 @@ const changeUser = (index) => {
}
}
//选取部门
const orgId=ref()
const orgId = ref()
const changePostList = (index, e) => {
orgId.value=e.fzOrgId
orgId.value = e.fzOrgId
chageIndex.value = index
nodeData.value[chageIndex.value].id = orgId.value
nodeData.value[chageIndex.value].id = e.id
nodeData.value[chageIndex.value].orgData = {
id:orgId.value,
orgid:orgId.value,
id: orgId.value,
orgid: orgId.value,
// id: '41fbffaf92a34b31bde6302004277486',
// orgid: '41fbffaf92a34b31bde6302004277486',
orgcode: e.orgCode,
@ -143,56 +176,114 @@ const changePostList = (index, e) => {
}
getUser()
}
const newUserData = ref({})
const transformData = (nodeData) => {
console.log(nodeData);
const { userList, checkList } = nodeData;
if (Array.isArray(userList)) {
const result = [];
// 遍历所有组织
for (const org of userList) {
// 遍历组织中的用户
for (const user of org.users) {
// 创建用户数据对象
const userData = {
id: user.id,
orgid: org.id,
orgcode: org.code,
orgname: org.name
};
// 创建结果对象
const transformedUser = {
userId: user.userid,
userName: user.username,
userData: JSON.stringify(userData)
};
result.push(transformedUser);
}
}
return result;
} else {
const { id: orgid, code: orgcode, name: orgname, users } = userList;
const checkListSet = new Set(checkList);
const filteredUsers = users.filter(user => checkListSet.has(user.userid));
return filteredUsers.map(user => {
newUserData.value = JSON.stringify({
id: user.id,
orgid,
orgcode,
orgname
})
return {
userId: user.userid,
userName: user.username,
userData: newUserData.value
}
}
)
}
};
const checkListData = ref()
// 删除
const handleCheckAllChange = (e) => {
const checkListSet = new Set(e);
checkListData.value = userList.value.filter(item => checkListSet.has(item.nodeId));
}
// 提交
const qcckPostList = async () => {
const deptId = getItem('deptId')
let users = nodeData.value.map(item => {
return {
userId: item.userData.userId,
// userId: '540422200010197495',
userName: item.userData.userName,
userData: JSON.stringify(item.userData.userData)
// ...item.userData
}
})
let userData = {
id:deptId[0].fzOrgId,
orgid:deptId[0].fzOrgId,
// id: '41fbffaf92a34b31bde6302004277486',
// orgid: '41fbffaf92a34b31bde6302004277486',
orgcode: deptId[0].deptCode,
orgname: deptId[0].deptName,
}
const promes = {
...props.createProcess,
// processData: { ...props.createProcess.processData.sqrw, orgNameData: userData },
flowType: "ZyCompany",
iframe: `${props.path.clueVerification}?id=${props.createProcess.processData.rwbh}`,
callback: {
"START": "",//流程开始
"APPROVE": "",//节点审批通过
"BACK": "",//退回上一节点
"REVOKE": "",//撤回审批
"DONE": `${InterfaceAddress}${props.path.byMeansOf}?id=${props.createProcess.rwbh}&bkZt=05`,//流程审批通过
"ABORT": `${InterfaceAddress}${props.path.nobyMeansOf}?id=${props.createProcess.rwbh}&bkZt=06`,//审批不通过
"RECOVER": "",//流程回收
"AGAIN": `${InterfaceAddress}${props.path.recycle}?id=${props.createProcess.rwbh}&bkZt=07`//流程退回初始
const data = {}
const listError = []
for (let i = 0; i < checkListData.value.length; i++) {
},
decision: JSON.stringify({
[modelData.value.nodeId]: {
users: users,
services: [],
events: [],
userData: JSON.stringify(userData)
if (Array.isArray(checkListData.value[i].userList)) {
for (let j = 0; j < checkListData.value[i].userList.length; j++) {
const item = checkListData.value[i].userList[j]
if (item.checkList && item.checkList.length > 0) {
data[checkListData.value[i].nodeId] = {
users: transformData(checkListData.value[i])
}
} else {
listError.push(checkListData.value[i].nodeName)
}
continue
}
} else {
if (checkListData.value[i].checkList && checkListData.value[i].checkList.length > 0) {
data[checkListData.value[i].nodeId] = {
users: transformData(checkListData.value[i])
}
} else {
listError.push(checkListData.value[i].nodeName)
}
}
}
if (modelData.value.length !== checkList.value.length) {
proxy.$message({ type: "warning", message: '环节' + listError.join('、') + '中有需要勾选的项' });
return
}
if (listError.length > 0) {
proxy.$message({ type: "warning", message: listError.join('、') + '请选择审批人' });
return
}
const submitData = {
...props.createProcess,
decision: JSON.stringify({
...data,
services: [],
events: [],
userData: newUserData.value,
})
}
promes.processData = JSON.stringify(promes.processData)
promes.callback = JSON.stringify(promes.callback)
console.log(promes);
await submitProcess({ ...promes }).then(res => {
submitData.processData = JSON.stringify(submitData.processData)
await submitProcess({ ...submitData }).then(res => {
proxy.$message({ type: "success", message: "提交审批成功" });
sendMessage(res.rows[0])
})
@ -200,6 +291,7 @@ const qcckPostList = async () => {
emit('close')
close()
}
//获取角色
const getUser = () => {
const promes = {
@ -210,38 +302,268 @@ const getUser = () => {
nodeData.value[chageIndex.value].listData = res.records
})
}
const showModel = ref(true)
//查询模板
const modelData = ref({})
const modelMsg = ref()
const loading = ref(false)
const userList = ref()
//节点审核人
const checkList = ref()
const endpoints = [
'/modelVersion/queryModelVersion',
'/modelVersion/queryModelNode',
'/modelVersion/queryModelSequenceFlow',
'/modelVersion/queryModelReachability'
]
const queryModel = async () => {
const prrmes = {
modelId: props.radioData,
modelStatus: 1
}
const res = await splPost(prrmes, '/model/queryModel')
const versionRes = await splPost({ modelVersionId: res.rows[0].currentVersionId }, '/modelVersion/queryModelVersion')
modelMsg.value = versionRes.rows[0]
const nodeRes = await splPost({ modelVersionId: res.rows[0].currentVersionId }, '/modelVersion/queryModelNode')
if (versionRes.rows.length > 0) {
modelData.value = nodeRes.rows.filter(item => item.nodeType == '1')[0]
try {
loading.value = true
// 查询模型信息
const params = {
modelId: props.radioData,
modelStatus: 1
}
const modelRes = await splPost(params, '/model/queryModel')
if (modelRes.rows.length === 0) {
proxy.$message({ type: "error", message: "模板不存在" })
showModel.value = false
return
}
// 并行获取模型相关数据
const resData = await Promise.all(endpoints.map(item => {
return splPost({ modelVersionId: modelRes.rows[0].currentVersionId }, item)
}))
// 解析节点数据
const rootNode = resData[1].rows.find(item => item.eventType === '0')
const sequenceNode = resData[2].rows.find(item => item.sourceNodeId === rootNode.nodeId)
const eventNode = resData[1].rows.find(item =>
item.nodeType === '1' && item.nodeId === sequenceNode.targetNodeId
)
const orgId = 'a8aa5ed229724b278faa7abd0f0cceb6'
// getItem('userOrg').parentid
if (eventNode) {
// 处理事件节点
await handleEventNode(eventNode, orgId)
} else {
// 处理普通节点
await handleNormalNodes(resData, sequenceNode, orgId)
}
} catch (error) {
console.error('查询模型失败:', error)
proxy.$message({ type: "error", message: "查询模型失败,请重试" })
} finally {
loading.value = false
}
}
const optional=ref(false)
// 处理事件节点
const handleEventNode = async (eventNode, orgId) => {
const nodeExtension = JSON.parse(eventNode.nodeExtension)
modelData.value = [eventNode]
checkList.value = [eventNode.nodeId]
let userRes
let orgData
const roles = nodeExtension.flwsUserNode.role[0] ? nodeExtension.flwsUserNode.role[0] : ''
const promes = {
posts: "",
orgid: ""
}
if (nodeExtension.flwsUserNode.orgType == 'brothers') {
orgData = await queryListByEntity({ id: orgId })
} else if (nodeExtension.flwsUserNode.orgType == 'parent') {
orgData = await querysingleByEntity({ id: orgId })
} else if (nodeExtension.flwsUserNode.orgType == 'parents') {
orgData = await queryUporgsByEntity({ id: orgId })
} else if (nodeExtension.flwsUserNode.orgType == 'appoint') {
// orgData = await queryUporgsByEntity({ orgcode: orgId })
}
if (nodeExtension.flwsUserNode.orgType == 'appoint') {
promes.roles = roles
promes.orgcode = nodeExtension.flwsUserNode.orgcode
userRes = await queryUserListByRule(promes)
checkListData.value = userList.value = [{
...eventNode,
userList: userRes.rows[0]
}]
}
if (nodeExtension.flwsUserNode.orgType == 'current') {
promes.roles = roles
promes.orgid = orgId
userRes = await queryUserListByRule(promes)
checkListData.value = userList.value = [{
...eventNode,
userList: userRes.rows[0]
}]
} else if (nodeExtension.flwsUserNode.orgType == 'optional') {
optional.value=true
} else {
const parentids = orgData.rows.map(item => item.parentid)
const userListPromises = parentids.map((item) => {
const promes = {
roles: roles,
posts: "",
orgid: item
}
return queryUserListByRule(promes)
}
)
const userListResults = await Promise.all(userListPromises)
checkListData.value = userList.value = modelData.value.map((item, index) => ({
...item,
userList: userListResults[index]?.rows[0]
}))
}
console.log(checkListData.value);
}
// 处理普通节点
const handleNormalNodes = async (resData, sequenceNode, orgId) => {
const targetNodeIds = resData[2].rows
.filter(item => item.sourceNodeId === sequenceNode.targetNodeId)
.map(item => item.targetNodeId)
const targetIdSet = new Set(targetNodeIds)
modelData.value = resData[1].rows.filter(item => targetIdSet.has(item.nodeId))
checkList.value = modelData.value.map(item => item.nodeId)
// 并行获取用户列表
let promesList = {}
for (let i = 0; i < modelData.value.length; i++) {
const str = JSON.parse(modelData.value[i].nodeExtension)
let res = {}
let list = []
if (str.flwsUserNode.orgType == 'brothers') {
res = await queryListByEntity({ parentid: orgId })
list = res.rows.map(item => {
return {
orgid: item.id,
posts: str.flwsUserNode.post[0] ? str.flwsUserNode.post[0] : '',
roles: str.flwsUserNode.role[0] ? str.flwsUserNode.role[0] : '',
}
})
promesList[modelData.value[i].nodeId] = list
} else if (str.flwsUserNode.orgType == 'parent') {
res = await querysingleByEntity({ id: orgId })
list = res.rows.map(item => {
return {
orgid: item.id,
posts: str.flwsUserNode.post[0] ? str.flwsUserNode.post[0] : '',
roles: str.flwsUserNode.role[0] ? str.flwsUserNode.role[0] : '',
}
})
promesList[modelData.value[i].nodeId] = list
} else if (str.flwsUserNode.orgType == 'parents') {
res = await queryUporgsByEntity({ id: orgId })
list = res.rows.map(item => {
return {
orgid: item.id,
posts: str.flwsUserNode.post[0] ? str.flwsUserNode.post[0] : '',
roles: str.flwsUserNode.role[0] ? str.flwsUserNode.role[0] : '',
}
})
promesList[modelData.value[i].nodeId] = list
} else if (str.flwsUserNode.orgType == 'appoint') {
list = [{
posts: str.flwsUserNode.post[0] ? str.flwsUserNode.post[0] : '',
roles: str.flwsUserNode.role[0] ? str.flwsUserNode.role[0] : '',
orgcode: str.flwsUserNode.orgcode
}]
promesList[modelData.value[i].nodeId] = list
} else {
list = [{
posts: str.flwsUserNode.post[0] ? str.flwsUserNode.post[0] : '',
roles: str.flwsUserNode.role[0] ? str.flwsUserNode.role[0] : '',
orgid: orgId
}]
promesList[modelData.value[i].nodeId] = list
}
}
const listByRule = {}
for (const key in promesList) {
console.log(promesList[key]);
listByRule[key] = promesList[key].map(item => {
return queryUserListByRule(item)
})
}
const userListByRule = {}
for (const key in listByRule) {
userListByRule[key] = await Promise.all(listByRule[key])
}
const model = {}
for (const key in userListByRule) {
model[key] = userListByRule[key].flatMap(item => item.rows)
}
checkListData.value = userList.value = modelData.value.map((item, index) => {
return {
...item,
userList: model[item.nodeId] ? model[item.nodeId] : []
}
})
}
function filterUsersWithOrgInfo(orgsData, checkList) {
const result = [];
// 如果没有数据或检查列表为空,返回空数组
if (!orgsData || !Array.isArray(orgsData) || !checkList || checkList.length === 0) {
return result;
}
// 将checkList转换为Set以提高查找效率
const checkSet = new Set(checkList);
// 遍历所有组织
for (const org of orgsData) {
// 检查组织是否有用户数据
if (org.users && Array.isArray(org.users)) {
// 筛选匹配的用户
for (const user of org.users) {
if (checkSet.has(user.userid)) {
// 创建带组织信息的用户对象
const userWithOrgInfo = {
...user, // 保留所有原始用户属性
orgCode: org.code, // 添加组织code
orgName: org.name, // 添加组织name
orgId: org.id // 添加组织id
};
result.push(userWithOrgInfo);
}
}
}
}
return result;
}
//发消息
const sendMessage = (gzlid) => {
const bkshrSfzh = nodeData.value.map(item => {
return {
bkshrXm: item.userData.userName,
bkshrSfzh: item.userData.sfzh,
bkshrSsbmmc: item.userData.userData.orgname,
bkshrSsbmdm: item.userData.userData.orgcode,
let letDataCheck = []
let userList = []
console.log(checkListData.value);
for (let i = 0; i < checkListData.value.length; i++) {
letDataCheck = [...letDataCheck, ...checkListData.value[i].checkList]
userList.push(checkListData.value[i].userList)
}
console.log(letDataCheck);
console.log(userList);
const bkshrSfzh = filterUsersWithOrgInfo(userList, letDataCheck).map(item => {
return {
bkshrXm: item.username,
bkshrSfzh: item.userid,
bkshrSsbmmc: item.orgName,
bkshrSsbmdm: item.orgCode,
}
})
const promes = {
xxly: '005',
gzlid: gzlid,
list: bkshrSfzh,
versionId: modelMsg.value.modelVersionId,
versionId: checkListData.value[0].modelVersionId,
id: props.createProcess.processData.rwbh
}
switch (props.userData.flowType) {
@ -251,13 +573,12 @@ const sendMessage = (gzlid) => {
})
break;
case 'ZDRYSDFJDP':
qcckPost(promes, '/mosty-gsxt/tbGsxtRqfjRy/updateBkgzl').then(res => {
console.log(res);
})
break;
case 'XSSJCJSP':
qcckPost(promes, '/mosty-gsxt/qbcj/updateBkgzl').then(res => {
qcckPost(promes, '/mosty-gsxt/qbcj/updateBkgzl').then(res => {
console.log(res);
})
break;
@ -278,6 +599,7 @@ const close = () => {
orgData: {},
}
]
optional.value=false
emit('update:modelValue', false)
}
</script>
@ -299,9 +621,14 @@ const close = () => {
}
.container-box {
height: 300px;
// height: 300px;
min-height: 300px;
overflow: auto;
// border: 1px solid rgba(172, 172, 172, 0.479);
padding: 10px;
max-height: 500px;
// border-radius: 5px;
.row {
margin-top: 10px;
align-items: center;
@ -312,5 +639,22 @@ const close = () => {
margin: 0 10px;
}
}
.reloBox {
position: relative;
padding: 0 10px;
border: 1px solid rgba(192, 192, 192, 0.426);
border-radius: 5px;
min-height: 100px;
margin-bottom: 20px;
.orgName {
position: absolute;
transform: translate(-50%, -50%);
left: 50%;
padding: 0 10px;
background-color: #fff;
}
}
}
</style>

View File

@ -1,5 +1,6 @@
<template>
<el-dialog class="dialog-container" :model-value="modelValue" :title="title" :before-close="close">
<div style="height: 300px;overflow: auto" v-infinite-scroll="load">
<el-radio-group v-model="radio" @change="changeRadio" v-if="lyquery.rows.length > 0">
<el-radio :label="item.modelId" v-for="(item) in lyquery.rows" :key="item.id">
@ -7,10 +8,9 @@
</el-radio>
</el-radio-group>
<div class="ww100 flex just-center">
<MOSTY.Empty :show="lyquery.rows.length == 0"></MOSTY.Empty>
</div>
<MOSTY.Empty :show="lyquery.rows.length == 0"></MOSTY.Empty>
</div>
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
@ -21,8 +21,8 @@
</template>
</el-dialog>
<SelectingPeople v-model="showDialog"
:createProcess="createProcess" @close="close" :radioData="radioData" :path="path" @getList="emit('getList')" :userData="userData"/>
<SelectingPeople v-model="showDialog" :createProcess="createProcess" @close="close" :radioData="radioData"
:path="path" @getList="emit('getList')" :userData="userData" />
</template>
<script setup>
@ -30,6 +30,8 @@ import { ref, getCurrentInstance, reactive, watch } from 'vue'
import SelectingPeople from './SelectingPeople.vue';
import * as MOSTY from "@/components/MyComponents/index";
import { splGet, splPost } from '@/api/spl'
import { qcckGet } from '@/api/qcckApi'
import { getItem,setItem } from '@/utils/storage'
const props = defineProps({
modelValue: {
type: Boolean,
@ -55,15 +57,17 @@ const props = defineProps({
})
const showDialog = ref(false)
const emit = defineEmits(['update:modelValue','getList'])
const emit = defineEmits(['update:modelValue', 'getList'])
const titles = ref(props.title)
const deptId=getItem('deptId')
const lyquery = reactive({
rows: [],
total: 0,
promes: {
page: 1,
rows: 100,
modelName:props.userData.modelName
// orgCode:deptId[0].orgCode
modelName: props.userData.modelName
}
})
@ -78,13 +82,28 @@ const qcckGetList = () => {
lyquery.total = res.total
})
}
const Sfzh = getItem('idEntityCard')
const qcckGetCount = () => {
if (!getItem('cookie') ) {
qcckGet({ sfzh: Sfzh },'/mosty-base/fzmsg/getCokie').then(res => {
document.cookie = res.cookie
setItem('userOrg',res.userOrg)
qcckGetList()
})
}
}
watch(() => props.modelValue, (newVal) => {
if (newVal) {
qcckGetList()
qcckGetCount()
}
})
const createProcess = ref({})
const radioData = ref('')
// const InterfaceAddress = 'http://192.168.0.231:8006/mosty-api/mosty-gsxt/'
// const InterfaceAddress = 'http://192.168.0.231:8006/mosty-api/mosty-gsxt/'
// const InterfaceAddress = 'http://155.540.22.30:50037/mosty-api/mosty-gsxt/'
const InterfaceAddress = 'http://192.168.1.32:8006/mosty-api/mosty-gsxt/'
const changeRadio = (e) => {
radioData.value = e
const item = lyquery.rows.find(item => item.modelId == e)
@ -92,14 +111,26 @@ const changeRadio = (e) => {
createProcess.value = {
modelId: e,
processName: item.modelName ? item.modelName : '',
processType:1,
processType: 1,
processData:
{
iframe: `${props.path.clueVerification}?id=${props.data.id}`,
iframe: `#/${props.path.clueVerification}?id=${props.data.id}`,
hostPrefix: "sgxtPath",
rwbh: props.data.id,
flowType: 'SGSP',
sqrw: props.data,
ajmc: props.userData.ajmc,
// flowType: "ZyCompany",
callback: {
"START": "",//流程开始
"APPROVE": "",//节点审批通过
"BACK": "",//退回上一节点
"REVOKE": "",//撤回审批
"DONE": `${InterfaceAddress}${props.path.byMeansOf}?id=${props.data.id}&bkZt=05`,//流程审批通过
"ABORT": `${InterfaceAddress}${props.path.nobyMeansOf}?id=${props.data.id}&bkZt=06`,//审批不通过
"RECOVER": "",//流程回收
"AGAIN": `${InterfaceAddress}${props.path.recycle}?id=${props.data.id}&bkZt=07`//流程退回初始
},
}
}
@ -120,7 +151,7 @@ const load = () => {
}
const close = () => {
radio.value=''
radio.value = ''
emit('update:modelValue', false)
}
</script>

View File

@ -1,12 +1,15 @@
import router from './router'
import store from './store'
import {
unifiedLogin
} from "@/api/user-manage";
import {
setItem,
getItem,
removeAllItem
} from "@/utils/storage";
// 白名单
const whiteList = ['/login','/oatuh_login','/404', '/401']
const whiteList = ['/login', '/oatuh_login', '/404', '/401', '/focusExploration', '/clueVerification', '/deploymentApproval']
/**
* 路由前置守卫
* to 去哪里
@ -46,7 +49,8 @@ router.beforeEach(async (to, from, next) => {
next()
} else {
if (isOatuh) {
next('/oatuh_login')
const idEntityCard = getItem('idEntityCard')
next(`/oatuh_login?token=${Base64.encode(idEntityCard)}`)
} else {
next('/login')
}

View File

@ -132,6 +132,11 @@ export const publicRoutes = [
}
]
},
{
path: "/oatuh_login",
name: "oatuh_login",
component: () => import("@/views/login/oatuh_login")
},
{
path: "/login",
name: "login",
@ -231,6 +236,17 @@ export const publicRoutes = [
title: "重点人员预警模型",
icon: "article"
}
}, {
path: "/policeReport",
name: "policeReport",
component: () =>
import(
"@/views/backOfficeSystem/policeReport/index.vue"
),
meta: {
title: "警情管理",
icon: "article"
}
},
]
},
@ -300,6 +316,7 @@ export const publicRoutes = [
icon: "article"
}
},
{
path: "/IntelligenceManagement",
name: "IntelligenceManagement",
@ -588,7 +605,26 @@ export const publicRoutes = [
title: "经验分享",
icon: "article"
}
}
}, {
path: "/ssemanticAnalysis",
name: "semanticAnalysis",
component: () =>
import(
"@/views/backOfficeSystem/SemanticAnalysis/index.vue"
),
meta: {
title: "语义分析",
icon: "article"
}
}, {
path: "/analysisReport",
name: "AnalysisReport",
component: () => import("@/views/backOfficeSystem/AnalysisReport/index"),
meta: {
title: "分析报告",
icon: "article"
}
},
]
}
]

View File

@ -84,6 +84,7 @@ export default {
*/
login(ctx, userInfo) {
const { userName, password, kaptcha } = userInfo;
return new Promise((resolve, reject) => {
login({ userName, password: Base64.encode(password), kaptcha }).then((data) => {
if (data.deptList.length === 1) {
@ -126,7 +127,7 @@ export default {
oatuhLogin(ctx, userInfo) {
const { token, systemId, } = userInfo;
return new Promise((resolve, reject) => {
unifiedLogin({ token, systemId, }).then((data) => {
unifiedLogin({ token, systemId }).then((data) => {
if (data.deptList.length === 1) {
this.commit("user/setToken", data.jwtToken);

View File

@ -6,6 +6,7 @@ import { saveAs } from 'file-saver'
import { tansParams, blobValidate } from "@/utils/ruoyi";
let downloadLoadingInstance;
const service = axios.create({
withCredentials: true,
baseURL: process.env.VUE_APP_BASE_API,
timeout: 100000
});
@ -66,6 +67,8 @@ service.interceptors.response.use(
error.response.data &&
error.response.data.code === 401
) {
console.log("Xxxxx");
store.dispatch('user/logout');
}
}

View File

@ -15,6 +15,10 @@ export const setItem = (key, value) => {
export const getItem = (key) => {
const data = window.localStorage.getItem(key);
try {
if (typeof data === 'string' && /^\d+$/.test(data) && data.length > 15) {
// 如果是长数字字符串,直接返回,不进行 JSON.parse
return data;
}
return JSON.parse(data);
} catch (err) {
return data;

View File

@ -90,6 +90,18 @@ export function timeValidate(date, type) {
if (type == 'md') {
return `${MM}.${dd}`
}
if (type == 'td') {
return `${yyyy}${MM}${dd}`
}
if (type == 'yd') {
return `${yyyy}`
}
if (type == 'mm') {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`
}
if (type == 'ydm') {
return `${yyyy}${MM}${dd}${hh}${mm}${ss}`
}
return `${yyyy}-${MM}-${dd} ${hh}:${mm}:${ss}`
}

View File

@ -0,0 +1,78 @@
// import jsPDF from 'jspdf';
// import html2canvas from 'html2canvas';
// export function useExportToPDF() {
// const exportToImage = async (element, filename = 'screenshot.png') => {
// const canvas = await html2canvas(element, {
// scale: 2,
// useCORS: true,
// });
// // 转换为图片并下载
// const link = document.createElement('a');
// link.download = filename;
// link.href = canvas.toDataURL('image/png');
// link.click();
// };
// // 将div导出为PDF的方法
// const exportDivToPDF = async (element, filename = 'document.pdf') => {
// try {
// // 使用html2canvas将div转换为canvas
// const canvas = await html2canvas(element, {
// scale: 2, // 提高清晰度
// useCORS: true, // 允许跨域图片
// logging: false, // 关闭日志
// width: element.offsetWidth,
// height: element.offsetHeight,
// windowWidth: element.scrollWidth,
// windowHeight: element.scrollHeight,
// backgroundColor: '#ffffff' // 设置背景色为白色
// });
// // 获取canvas的宽高
// const imgWidth = 210; // A4纸宽度(mm)
// const pageHeight = 297; // A4纸高度(mm)
// const imgHeight = canvas.height * imgWidth / canvas.width;
// let heightLeft = imgHeight;
// let position = 0;
// // 创建PDF文档
// const pdf = new jsPDF({
// orientation: 'portrait',
// unit: 'mm',
// format: 'a4'
// });
// // 将canvas转换为图片并添加到PDF
// const imgData = canvas.toDataURL('image/png');
// pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
// heightLeft -= pageHeight;
// // 如果内容超出一页,添加新页面
// while (heightLeft > 0) {
// position = heightLeft - imgHeight;
// pdf.addPage();
// pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight);
// heightLeft -= pageHeight;
// }
// // 下载PDF
// pdf.save(filename);
// } catch (error) {
// console.error('导出PDF失败:', error);
// alert('导出PDF失败请稍后重试');
// }
// };
// return {
// exportToImage,
// exportDivToPDF
// };
// }
// exportToImage
// };
// }
export function exportDivToPDF(divId, filename) {
}

View File

@ -0,0 +1,129 @@
<template>
<div class="box" ref="chartDom"></div>
</template>
<script setup>
import { ref, onMounted,watch } from "vue";
import * as echarts from "echarts";
let chartDom = ref(null); //注意变量名 和 ref名字要对应
const props = defineProps({
title: {
type: String,
default: '2023年1月1日至2023年12月31日'
},
xAxisData: {
type: Array,
default: () => ['A', 'B', 'C', 'D', 'E', 'F']
},
seriesData: {
type: Array,
default: () => [[2549], [12421], [2637],[ 3146],[ 15189], [9562]]
},
// yAxisData: {
// type: Array,
// default: () => [2549, 12421, 2637, 3146, 15189, 9562]
// },
})
const chartInstance = ref(null);
onMounted(() => {
initChart();
});
watch([
() => props.seriesData,
() => props.xAxisData,
], () => {
initChart();
});
const initChart = () => {
chartInstance.value = props.seriesData.map((item, index) => {
console.log(item,"xxxxxxxx");
return {
name: props.xAxisData[index],
data: item,
type: "bar",
barWidth: "20",
// barGap: 20, // 系列之间的间距
barCategoryGap: 100, // 类别之间的间距
label: {
show: true,
position: 'top',
formatter: function (params) {
// 值为0或null时不显示
if (params.value === 0 || params.value === null) {
return '';
}
// 格式化数值显示
return params.value.toLocaleString();
},
color: '#2c3e50',
fontSize: 12,
fontWeight: 'bold',
distance: 10 // 标签与柱子的距离
},
}
})
console.log(chartInstance.value);
var myChart = echarts.init(chartDom.value);
var option = {
title: {
text: props.title,
left: 'center'
},
tooltip: {
// 鼠标悬浮提示数据
trigger: "axis",
backgroundColor: "rgba(32, 33, 36,.7)",
borderColor: "rgba(32, 33, 36,0.20)",
borderWidth: 15,
textStyle: {
// 文字提示样式
color: "#fff",
fontSize: "12",
},
axisPointer: {
// 坐标轴虚线
type: "cross",
label: {
backgroundColor: "#6a7985",
},
},
},
legend: {
right: 0
},
// },
grid: {
// 控制图表的位置
left: "5%",
right: "5%",
top: "18%",
bottom: "5%",
containLabel: true,
},
xAxis: {
data: props.xAxisData,
},
yAxis: {
// axisLabel: {
// // y轴线 标签修改
// textStyle: {
// color: "white", //坐标值得具体的颜色
// },
// },
// data: props.xAxisData,
},
series: chartInstance.value
};
option && myChart.setOption(option);
};
</script>
<style scoped>
.box {
width: 100%;
height: 60vh;
/* background-color: #031a67; */
}
</style>

View File

@ -0,0 +1,200 @@
<template>
<!-- 将固定id改为ref引用 -->
<div ref="chartContainer" style="height: 100%;"></div>
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted, onUnmounted, ref, watch, defineProps } from 'vue';
// 定义组件的属性,使其可复用
const props = defineProps({
// 图表数据
chartData: {
type: Array,
default: () => [
{ value: 40, name: 'rose 1' },
{ value: 38, name: 'rose 2' },
{ value: 32, name: 'rose 3' },
{ value: 30, name: 'rose 4' },
{ value: 28, name: 'rose 5' },
{ value: 26, name: 'rose 6' },
{ value: 22, name: 'rose 7' },
{ value: 18, name: 'rose 8' }
]
},
// 图表标题
chartName: {
type: String,
default: 'Nightingale Chart'
},
// 是否显示工具箱
showToolbox: {
type: Boolean,
default: true
},
// 是否显示图例
showLegend: {
type: Boolean,
default: true
},
// 内半径
innerRadius: {
type: Number,
default: 0
},
// 外半径
outerRadius: {
type: Number,
default: 200
},
// 扇形间距
padAngle: {
type: Number,
default: 0
},
title: {
type: Object,
default: () => ({
text: 'Nightingale Chart',
left: 'center'
})
},
roseType: {
type: String,
default: 'radius'
}
});
// 图表容器引用
const chartContainer = ref(null);
// 图表实例引用
const chartInstance = ref(null);
// 初始化图表
const initChart = () => {
const chartDom = chartContainer.value;
if (!chartDom) return;
// 如果已经存在实例,先销毁
if (chartInstance.value) {
chartInstance.value.dispose();
}
// 创建新实例
chartInstance.value = echarts.init(chartDom);
// 设置图表选项
const option = {
title: props.title,
legend: props.showLegend ? {
top: 'bottom'
} : false,
toolbox: props.showToolbox ? {
show: true,
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
} : false,
series: [
{
name: props.chartName,
type: 'pie',
radius: [props.innerRadius, props.outerRadius],
center: ['50%', '50%'],
roseType: props.roseType,
// 在 ECharts 5.3.3 中,当 roseType 为 'area' 时padAngle 需要特殊处理
// 为了确保间距生效我们需要添加一个小的非零值来替代0
// padAngle: props.padAngle === 0 ? 0.1 : props.padAngle,
itemStyle: {
borderColor: '#fff',
borderWidth:props.padAngle
},
// 显示百分比
label: {
show: true,
formatter: function(params) {
// 对于值为0的项显示0%而不是极小值计算出的百分比
if (props.chartData.find(d => d.name === params.name && d.value === 0)) {
return params.name + ': 0%';
}
return params.name + ': ' + params.percent + '%';
}
},
// 鼠标悬停时的样式
emphasis: {
label: {
show: true,
fontSize: '16',
fontWeight: 'bold',
formatter: function(params) {
// 对于值为0的项显示0%而不是极小值计算出的百分比
if (props.chartData.find(d => d.name === params.name && d.value === 0)) {
return params.name + ': 0%';
}
return params.name + ': ' + params.percent + '%';
}
}
},
// 处理数据确保值为0的项也能显示
data: props.chartData.map(item => ({
...item,
// 对于值为0的数据设置一个极小值来确保它在饼图中显示
value: item.value === 0 ? 0.0000001 : item.value
}))
}
]
};
// 应用选项
chartInstance.value.setOption(option);
};
// 处理窗口大小变化,自动调整图表大小
const handleResize = () => {
if (chartInstance.value) {
chartInstance.value.resize();
}
};
// 组件挂载时初始化图表
onMounted(() => {
initChart();
window.addEventListener('resize', handleResize);
});
// 组件卸载时销毁图表实例并移除事件监听
onUnmounted(() => {
if (chartInstance.value) {
chartInstance.value.dispose();
}
window.removeEventListener('resize', handleResize);
});
// 监听数据变化,更新图表
watch(() => props.chartData, () => {
initChart();
}, { deep: true });
// 监听其他配置变化,更新图表
watch([
() => props.chartName,
() => props.showToolbox,
() => props.showLegend,
() => props.innerRadius,
() => props.outerRadius,
() => props.padAngle,
()=> props.roseType,
], () => {
initChart();
});
</script>
<style scoped>
:deep(div) {
width: 100%;
height: 100%;
/* min-height: 400px; */
}
</style>

View File

@ -0,0 +1,500 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="警情分析报告">
<el-button type="primary" @click="generatePDF()">
<el-icon style="vertical-align: middle">
<CirclePlus />
</el-icon>
<span style="vertical-align: middle">导出</span>
</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch">
<template #defaultSlot>
<!-- -->
<el-select v-model="bjlbList" placeholder="请选择情报类型" multiple collapse-tags>
<el-option v-for="item in dictItemList" :key="item.dm" :label="item.zdmc" :value="item.dm" />
</el-select>
</template>
</Search>
</div>
<div style="background-color: #fff;color: black;padding: 15px;overflow: auto;" :style="{ height: tabHeight + 'px' }"
ref="tableBox">
<div style="border-bottom: 1px #ccc solid;padding-bottom: 30px;">
<h1 class="headline">{{ nd }}年度西藏公安执法数据分析</h1>
<div style="display: flex;align-items: center;justify-content: space-between; color: red;margin-top: 30px;padding: 0 30px;">
<div>{{ deptId.name }}</div>
<div>{{ deptId?.ord }}</div>
<div>{{ deptId?.time }}</div>
</div>
</div>
<p>为全面客观准确掌握全区公安机关的执法状况自治区
公安厅基于数据统计对全区公安机关{{ nd }}年度的执法状况作
了客观分析</p>
<h2>执法状况总体分析</h2>
<h2>1.接处警情况</h2>
<h2>1.1接报警情</h2>
<p>
{{ timeValidate(TimeValue.startTime, 'td') }}{{ timeValidate(TimeValue.endTime, 'td') }}
全区公安机关共
接报各类警情{{ dataList.XsfxTj.total }},同比{{ `${dataList.XsfxTj.tbbsb > 0 ? "下降" : "上升"}
${dataList.XsfxTj.tbbsb}%,同比${dataList.XsfxTj.tbbsb > 0 ? "下降" : "上升"}${dataList.XsfxTj.tbbsb}%` }}</p>
<h2>1.1.1类型维度</h2>
<p>
从警情类型来看{{ sortingRatioValue.Ydfx[0]?.name }}警情最多占到{{ sortingRatioValue.Ydfx[0]?.ratio }}其次为{{
sortingRatioValue.Ydfx[1]?.name }}警情占到{{ sortingRatioValue.Ydfx[1]?.ratio }}
</p>
<MaleNightingalePicture roseType="area" style="height: 550px;" :title="{ text: '接警情类型', left: 'center' }"
:chartData="dataList.jqlxTj" :chartName="'接警情类型'" :innerRadius="0" :padAngle="4" />
<h2>1.1.2来源维度</h2>
<p>
从警情来源来看{{ sortingRatioValue.Jqlx[0]?.name }}警情最多占到{{ sortingRatioValue.Jqlx[0]?.ratio }}其次为{{
sortingRatioValue.Jqlx[1]?.name }}警情占到{{ sortingRatioValue.Jqlx[1]?.ratio }}
</p>
<MaleNightingalePicture roseType="area" :title="{ text: '警情来源', left: 'center' }" style="height: 550px;"
:chartData="dataList.jqlyTj" :innerRadius="50" :outerRadius="150" :padAngle="4" />
<h2>1.1.3地域维度</h2>
<p>从地市分布地市来看{{ sortingRatioValue.Dywdtj[0]?.ssbm }}警情量最大占到全区警情总
量的{{ sortingRatioValue.Dywdtj[0]?.ratio }}
<span v-if="sortingRatioValue.Dywdtj.length > 1">
其次为{{ sortingRatioValue.Dywdtj[1]?.ssbm }}
<span v-if="sortingRatioValue.Dywdtj.length > 2">
<span v-if="sortingRatioValue.Dywdtj.length > 3">
{{ sortingRatioValue.Dywdtj[3]?.ssbm }}两市警情量较为接近
</span>
<span>
警情量最少的为{{ sortingRatioValue.Dywdtj[sortingRatioValue.Dywdtj.length - 1]?.ssbm }}
</span>
</span>
</span>
</p>
<Histogram title="地市分布" :xAxisData="dataList.dyTj.xAxisData" :seriesData="dataList.dyTj.seriesData" />
<h2>1.1.4时间维度</h2>
<p>
我们将所有警情按照月份划分进行统计发现每月警情分布
较为平均最高月份为
{{ sortingRatioValue.Ydfx[0]?.month }}占到{{ sortingRatioValue.Ydfx[0]?.ratio }}
<span v-if="sortingRatioValue.Ydfx.length > 1">
最低月份为{{ sortingRatioValue.Ydfx[sortingRatioValue.Ydfx.length - 1]?.month }}
占到{{ sortingRatioValue.Ydfx[sortingRatioValue.Ydfx.length - 1]?.ratio }}
考虑是因为{{ sortingRatioValue.Ydfx[0]?.month }}月为我区传统旅游旺季进藏人员较多
<!-- {{sortingRatioValue.Ydfx[sortingRatioValue.Ydfx.length-1]?.month}}月一般春节及藏历新年期间在藏人员较少 -->
</span>
</p>
<MaleNightingalePicture :title="{ text: '警情分布', left: 'center' }" style="height: 550px;"
:chartData="dataList.ydTj" :innerRadius="10" :outerRadius="150" :padAngle="2" />
<!-- <p>
按照24小时每小时时段进行划分后发现警情多发时段集
中在9时至20时每小时均在1000起以上
</p> -->
<h2>1.2警情处置</h2>
<h2>1.2.1结果维度</h2>
<p>
从警情处置结果来看
<span v-for="(item, index) in sortingRatioValue.Cljgf">
{{ `${item.name}占到${item.ratio}` }}
</span>
<!--
{{sortingRatioValue.Cljgf[0]?.name}}占到{{sortingRatioValue.Cljgf[0]?.ratio}}拟作行
政案件处理的占比17.63%拟作刑事案件处理的占到6.39% -->
</p>
<MaleNightingalePicture :title="{ text: '警情处置', left: 'center' }" style="height: 550px;"
:chartData="dataList.CljgfTj" :innerRadius="0" :outerRadius="150" :padAngle="2" />
<h2>1.2.2效率维度</h2>
<p>从处警效率来看{{ sortingRatioValue.Czlfx[1]?.name }}处警的占到{{ sortingRatioValue.Czlfx[0]?.ratio
}}表明我区公安机关在接警之后能够在第一时间处警
</p>
<MaleNightingalePicture :title="{ text: '效率维度', left: 'center' }" style="height: 550px;"
:chartData="dataList.withinTj" :innerRadius="0" :outerRadius="150" :padAngle="0" />
</div>
</div>
<AddForm ref="addForm" :dict="{ D_GS_XS_LX }" />
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
// import { useExportToPDF } from './components/a.js';
import Search from "@/components/aboutTable/Search.vue";
import html2canvas from 'html2canvas';
import jsPDF from 'jspdf';
import MaleNightingalePicture from './components/maleNightingalePicture.vue'
import Histogram from './components/histogram.vue'
import { timeValidate } from '@/utils/tools.js'
import { getItem, setItem } from '@/utils/storage'
import { fxbgDywdtj, getDictItem, fxbgJqlxtj, fxbgJqlytj, fxbgYdfx, fxbgXsfx, fxgbCljgf, fxgbCzlfx, fxbgTj } from '@/api/semanticAnalysis'
// import AddForm from './components/a/addForm.vue'
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
// import ItemXs from './components/itemXs/itemXs.vue'
import { reactive, ref, onMounted, getCurrentInstance, nextTick, computed, watch } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_XS_LX } = proxy.$dict("D_GS_XS_LX"); //获取字典数据
const dictItemList = ref([])
const searchConfiger = reactive([
{
label: "时间",
showType: "daterange",
prop: "startTime",
placeholder: "请输入警情名称",
},
{
showType: "defaultSlot",
// prop: "bjlbList",
placeholder: "请选择情报类型",
label: "警情类别"
},
])
const bjlbList = ref([])
onMounted(() => {
tabHeightFn()
})
const tabHeight = ref(0)
// 表格高度计算
const tabHeightFn = () => {
tabHeight.value = window.innerHeight - 300
window.onresize = function () {
tabHeightFn();
};
};
const pageData = reactive({
parameter: {},
total: 0,
loading: false,
tableData: []
})
const onSearch = (val) => {
const promes = {
startTime: val.startTime ? val.startTime[0] : '',
endTime: val.startTime ? val.startTime[1] : '',
}
const bjlbLists = bjlbList.value ? bjlbList.value.join(',') : ""
pageData.parameter = { bjlbList: bjlbLists, ...promes }
funAll()
}
// 数据处理
const dataList = reactive({
dyTj: {
xAxisData: [],
seriesData: [],
},
jqlxTj: [],
jqlyTj: [],
CljgfTj: [],
XsfxTj: [],
})
const sortingRatioValue = reactive({
Dywdtj: [],
Ydfx: [],
Cljgf: [],
Czlfx: [],
Lyfx: [],
Jqlx: []
})
const sortingRatio = (data) => {
// 提取所有number值
// 计算总数
const total = data.reduce((sum, item) => sum + item.number, 0);
// 找出第一大和第二大的值及其对应的name
const sortedData = [...data].sort((a, b) => b.number - a.number);
const dataValue = sortedData.map(item => {
return {
...item,
ratio: total > 0 ? (item.number / total * 100).toFixed(2) + '%' : '0%',
}
})
return dataValue
}
// 地域统计
const getfxbgDywdtj = () => {
let params = {
...pageData.parameter,
}
fxbgDywdtj(params).then(res => {
dataList.dyTj.xAxisData = res.map(it => it.ssbm)
dataList.dyTj.seriesData = [];
for (let i = 0; i < res.length; i++) {
dataList.dyTj.seriesData[i] = [];
for (let j = 0; j < res.length; j++) {
dataList.dyTj.seriesData[i][j] = 0;
}
}
for (let i = 0; i < dataList.dyTj.seriesData.length; i++) {
dataList.dyTj.seriesData[i][i] = res[i].number
}
sortingRatioValue.Dywdtj = sortingRatio(res)
})
}
// 警情类型统计
const getfxbgJqlxtj = () => {
let params
if (pageData.parameter.bjlbList) {
params = {
...pageData.parameter,
}
} else {
params = {
...pageData.parameter,
bjlbList: dictItemList.value.map(item => item.dm).join(',')
}
}
fxbgJqlxtj(params).then(res => {
sortingRatioValue.Jqlx = sortingRatio(res)
dataList.jqlxTj = res.map(item => {
return {
name: item.name,
value: item.number
}
})
})
}
// 警情来源统计
const getfxbgJqlytj = () => {
let params = {
...pageData.parameter,
}
fxbgJqlytj(params).then(res => {
sortingRatioValue.Lyfx = sortingRatio(res)
dataList.jqlyTj = res.map(item => {
return {
name: item.name,
value: item.number
}
})
})
}
//分析报告-时间维度-月分析
const getfxbgYdfx = () => {
let params = {
...pageData.parameter,
}
fxbgYdfx(params).then(res => {
sortingRatioValue.Ydfx = sortingRatio(res)
dataList.ydTj = res.map(item => {
return {
name: item.month,
value: item.number
}
})
})
}
// 分析报告-处理结果分析
const getfxgbCljgf = () => {
let params = {
...pageData.parameter,
}
fxgbCljgf(params).then(res => {
sortingRatioValue.Cljgf = sortingRatio(res)
dataList.CljgfTj = res.map(item => {
return {
name: item.name,
value: item.number
}
})
})
}
// 分析报告-处置率分析
const getfxgbCzlfx = () => {
let params = {
...pageData.parameter,
}
fxgbCzlfx(params).then(res => {
dataList.withinTj = [{
name: "超时分流(超过24小时)",
value: res.within24h ? res.within24h : 0
}, {
name: "按时分流(24小时内)",
value: res.over24h ? res.over24h : 0
}]
sortingRatioValue.Czlfx = sortingRatio(dataList.withinTj)
})
}
const getfxbgTj = () => {
let params = {
...pageData.parameter,
}
fxbgTj(params).then(res => {
console.log(res, "xxx");
dataList.XsfxTj = res
})
}
const TimeValue = ref({
startTime: '',
endTime: ''
})
const nd = ref()
watch(() => pageData.parameter, (newVal) => {
if (newVal.startTime) {
TimeValue.value.startTime = newVal.startTime
TimeValue.value.endTime = newVal.endTime
if (timeValidate(newVal.startTime, 'yd') == timeValidate(newVal.endTime, 'yd')) {
nd.value = timeValidate(newVal.startTime, 'yd')
} else {
nd.value = `${timeValidate(newVal.startTime, 'yd')}${timeValidate(newVal.endTime, 'yd')}`
}
}
}, { deep: true })
const deptId = ref({
name: ''
})
const Time = () => {
const currentYear = new Date().getFullYear();
const startOfYear = new Date(currentYear, 0, 1); // 今年1月1日
const endOfYear = new Date(currentYear, 11, 31, 23); // 今年12月31日23:59:59.999
const year = startOfYear.getFullYear();
const month = String(startOfYear.getMonth() + 1).padStart(2, '0');
const day = String(startOfYear.getDate()).padStart(2, '0');
const endYear = endOfYear.getFullYear();
const endMonth = String(endOfYear.getMonth() + 1).padStart(2, '0');
const endDay = String(endOfYear.getDate()).padStart(2, '0');
const devt = getItem('deptId')
deptId.value.name = devt[0].deptName
nd.value = timeValidate('', 'yd')
deptId.value.time = timeValidate('', 'ydm')
deptId.value.ord=timeValidate('', 'mm')+ Math.floor(Math.random() * 90000) + 10000;
TimeValue.value.startTime = `${year}-${month}-${day}`
TimeValue.value.endTime = `${endYear}-${endMonth}-${endDay}`
}
Time()
const funAll = () => {
getfxbgDywdtj()
getfxbgJqlxtj()
getfxbgJqlytj()
getfxgbCljgf()
getfxbgYdfx()
getfxgbCzlfx()
getfxbgTj()
}
const getDictItemList = () => {
const promes = {
dictCode: "00000000"
}
getDictItem(promes).then(res => {
dictItemList.value = res
funAll()
})
}
const data = ref()
watch(() => dictItemList.value, (val) => {
data.value = val
}, { deep: true })
getDictItemList()
const tableBox = ref(null);
async function generatePDF(filename = 'document.pdf') {
// try {
const element = tableBox.value;
console.log();
// // 保存原始滚动位置和样式
// const originalScrollTop = element.scrollTop;
// const originalOverflow = element.style.overflow;
// // 临时允许元素滚动并获取完整高度
// element.style.overflow = 'visible';
// const canvas = await html2canvas(element, {
// scale: 2, // 提高清晰度
// useCORS: true, // 允许跨域图片
// logging: false, // 关闭日志
// scrollY: 0, // 禁止窗口滚动
// scrollX: 0,
// windowWidth: element.scrollWidth, // 设置窗口大小为元素大小
// windowHeight: element.scrollHeight,
// width: element.scrollWidth, // 设置canvas大小为元素大小
// height: element.scrollHeight
// });
// // 恢复原始样式和滚动位置
// element.style.overflow = originalOverflow;
// element.scrollTop = originalScrollTop;
// const imgData = canvas.toDataURL('image/png');
// const pdf = new jsPDF('p', 'mm', 'a4');
// const imgProps = pdf.getImageProperties(imgData);
// const pdfWidth = pdf.internal.pageSize.getWidth();
// const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
// // 计算需要多少页
// const pageHeight = pdf.internal.pageSize.getHeight();
// let heightLeft = pdfHeight;
// let position = 0;
// // 添加第一页
// pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight);
// heightLeft -= pageHeight;
// // 添加更多页(如果需要)
// while (heightLeft > 0) {
// position = -heightLeft;
// pdf.addPage();
// pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, pdfHeight);
// heightLeft -= pageHeight;
// }
// pdf.save(filename);
// } catch (error) {
// console.error('生成PDF时出错:', error);
// alert('生成PDF时出错请查看控制台获取详细信息');
// }
}
</script>
<style lang="scss" scoped>
.headline {
text-align: center;
color: red;
}
p {
text-indent: 2em;
/* 首行缩进2个汉字 */
margin: 1em 0;
/* 段落间距 */
line-height: 1.6;
/* 行高 */
font-size: 16px;
/* 字体大小 */
text-align: justify;
/* 两端对齐 */
}
/* 特殊情况处理 */
p.no-indent {
text-indent: 0;
/* 不需要缩进的段落 */
}
p.first-no-indent:first-of-type {
text-indent: 0;
/* 第一个段落不缩进 */
}
</style>

View File

@ -163,7 +163,7 @@ onMounted(() => {
.lable {
font-size: 14px;
width: 13%;
width: 110px;
font-weight: 700;
}
}

View File

@ -155,7 +155,7 @@ onMounted(() => {
.lable {
font-size: 14px;
width: 13%;
width: 110px;
font-weight: 700;
}
}

View File

@ -136,7 +136,7 @@ onMounted(() => {
.lable {
font-size: 14px;
width: 13%;
width: 110px;
font-weight: 700;
}
}

View File

@ -97,6 +97,8 @@ const rules = reactive({
ryXm: [{ required: true, message: "请输入姓名", trigger: "blur" }],
...rule.identityCardRule({ validator: true },'rySfzh'), //身份证校验
...rule.phoneRule({ validator: true }, "ryLxdh"), // 是否必填 是否进行校验,
rySfzh: [{ required: true, message: "请输入身份证号", trigger: "blur" }],
ryLxdh: [{ required: true, message: "请输入联系电话", trigger: "blur" }],
ryXb: [{ required: true, message: "请选择性别", trigger: "change" }],
ryMz: [{ required: true, message: "请选择民族", trigger: "change" }],
ryCsrq: [{ required: true, message: "请选择出生日期", trigger: "change" }],
@ -282,7 +284,12 @@ const delDictItem = (bqId) => {
// 提交
const submit = () => {
elform.value.submit((data) => {
console.log("xxxxx");
console.log(data);
data.zdrSjjz = data.zdrSjjz.join(",");
let url = title.value == "新增" ? "/mosty-gsxt/tbGsxtZdry/save" : "/mosty-gsxt/tbGsxtZdry/update";
let params = { ...data };

View File

@ -237,7 +237,11 @@ const init = (type, row) => {
tableDate.tableConfiger.haveControls = true;
disabled.value = false;
listQuery.value.bkfqrXm = getItem("USERNAME");
console.log(getItem("USERNAME"));
listQuery.value.bkfqrSfzh = getItem("idEntityCard");
console.log( getItem("USERID"));
console.log( getItem("idEntityCard"));
listQuery.value.bkfqrSsbmmc = getItem("deptId")[0].deptName;;
listQuery.value.bkfqrSsbmdm = getItem("deptId")[0].deptCode;;
}

View File

@ -0,0 +1,80 @@
<template>
<div class="searchTool">
<div class="searchToolTitle">
语义分析类别选择
</div>
<div class="searchToolContent flex align-center">
</div>
</div>
</template>
<script setup>
import { onMounted, computed, ref } from 'vue'
import emitter from "@/utils/eventBus.js";
const props = defineProps({
dict: {
type: Object,
default: () => { }
}
})
const selectedValues = ref([]);
const endProps = {
children: "itemList",
value: "zdmc",
label: "zdmc",
checkStrictly: false,
multiple: true,
};
const handleChange = (val) => {
const obj = val.map(item => {
return item[item.length - 1]
})
emitter.emit('changeTab', obj)
}
</script>
<style lang="scss" scoped>
.searchTool {
background-color: #fff;
color: #000;
padding: 16px 20px;
border-radius: 5px;
.searchToolTitle {
font-size: 18px;
font-family: 'verdana';
position: relative;
}
.searchToolContent {
margin-top: 16px;
.searchToolContentTitle {
width: 70px;
}
.searchToolContentSelect {
width: 100%;
//
}
}
.searchToolTitle::after {
content: "";
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 80px;
border-radius: 5px;
height: 4px;
background-color: #0386fb;
background: linear-gradient(90deg, #0aa1ff 2%, #ffffff 100%);
}
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<el-form ref="elform" :model="listQuery" :label-width="props.labelWidth" :rules="props.rules" :inline="props.inline"
label-position="left" :disabled="props.disabled">
<el-form-item v-for="(item, idx) in props.formList" :style="item.width && { width: item.width }" :prop="item.prop"
:label="item.label" :label-width="item.labelWidth" :key="idx">
<el-input v-model="listQuery[item.prop]" :placeholder="`请输入${item.label}`" :disabled="item.disabled" />
</el-form-item>
</el-form>
</template>
<script setup>
import { ref, defineProps, defineEmits, defineExpose, watch, watchEffect } from "vue";
const props = defineProps({
//循环的值
formList: {
default: [],
type: Array
},
rules: {
default: {},
type: Object
},
labelWidth: {
default: "140px",
type: String
},
modelValue: {
type: Object,
default: {}
},
inline: {
type: Boolean,
default: true
},
disabled: {
type: Boolean,
default: false
}
});
const elform = ref();
const listQuery = ref({});
const emits = defineEmits(["update:modelValue"]);
// 提交
const submit = (resfun) => {
elform.value.validate((valid) => {
if (!valid) return false;
resfun(listQuery.value);
});
};
const getdep = (e, val) => {
if (val) listQuery.value[val] = e ? e.orgName : '';
}
const reset = () => {
elform.value.resetFields()
}
// 修改这里的watch逻辑避免无限循环
let isUpdatingFromProps = false;
watch(() => listQuery.value, (newVal) => {
if (newVal && !isUpdatingFromProps) {
emits("update:modelValue", newVal);
}
}, { deep: true });
watch(() => props.modelValue, (newVal) => {
// 只有在新值确实变化时才更新(避免空值覆盖)
if (newVal && Object.keys(newVal).length > 0) {
isUpdatingFromProps = true;
listQuery.value = { ...newVal };
setTimeout(() => {
isUpdatingFromProps = false;
}, 0);
}
}, { immediate: true, deep: true });
defineExpose({ submit, reset });
</script>
<style lang="scss" scoped>
::v-deep .el-form-item__label {
background-color: #f5f7fa;
border: 1px solid #e4e7ed;
flex: 0 0 auto;
text-align: center;
line-height: 32px;
padding: 0 12px 0 0;
box-sizing: border-box;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
::v-deep .el-form-item {
margin-right: 0;
}
::v-deep .el-input__inner{
height: 34px;
line-height: 34px;
border-radius: 0;
}
</style>

View File

@ -0,0 +1,156 @@
<template>
<div class="listBox">
<div class="titleBar">
历史分析
<div class="barSearch">
<el-input v-model="titleName" placeholder="请输入分析名称" :suffix-icon="Search" />
</div>
</div>
<div class="list" v-infinite-scroll="load" :infinite-scroll-disabled="disabled.disabled">
<div v-for="(item,index) in yyDataList.list " :key="index" @click="handleChange(item,index)">
<div class=" flex align-center " :class="index==classIndex?'listItem':'listItemNotHover'">
<el-icon class="icon" >
<Finished />
</el-icon>
<div class="listItemTitle ">{{ item.fxmc }}</div>
</div>
</div>
</div>
<div class="establishBut">
<el-button type="primary" style="width: 100%;" @click="changeValue(value)">创建新的情报语义分析 </el-button>
</div>
</div>
<popupWindows v-model="showPopup"/>
</template>
<script setup>
import { ref,reactive, onMounted,onUnmounted } from 'vue'
import { Search } from '@element-plus/icons-vue'
import popupWindows from './popupWindows.vue'
import { yyfxSelectPage } from '@/api/semanticAnalysis'
import { Finished } from '@element-plus/icons-vue'
import emitter from "@/utils/eventBus.js";
const titleName = ref('')
const showPopup = ref(false)
const changeValue = (value) => {
emitter.emit('showDetails', true)
showPopup.value = true
}
const classIndex=ref(0)
const handleChange = (val,index) => {
classIndex.value=index
emitter.emit('getlistData', val.tqjg)
emitter.emit('showDetails', false)
}
const queryParams = reactive({
pageCurrent: 1,
pageSize: 10,
fxmc: titleName.value
})
const yyDataList = reactive({
list: [],
total:0
})
const disabled = reactive({
disabled: false,
loading: false
})
const getYyfxSelectPage = () => {
disabled.loading=true
yyfxSelectPage(queryParams).then(res => {
yyDataList.list = queryParams.pageCurrent==1?res.records:yyDataList.list.concat(res.records)
yyDataList.total = res.total
}).finally(()=>{
disabled.loading=false
})
}
const load = () => {
if (yyDataList.list.length == yyDataList.total) {
disabled.disabled = true
} else {
queryParams.pageCurrent++
getYyfxSelectPage()
}
}
onMounted(() => {
emitter.on('getYyfxSelectPage', (res) => {
getYyfxSelectPage()
})
getYyfxSelectPage()
})
onUnmounted(() => {
emitter.off(() => {
getYyfxSelectPage()
})
})
</script>
<style lang="scss" scoped>
.listBox {
width: 100%;
color: #000;
height: 100%;
.titleBar {
width: 100%;
padding: 10px;
text-align: center;
font-family: 'verdana';
font-size: 18px;
font-weight: bold;
background-color: #fff;
.barSearch {
margin: 10px 0;
}
}
.list {
max-height: calc(100% - 150px);
overflow: auto;
box-sizing: border-box;
.listItemNotHover{
color:#000;
padding-left:10px;
margin-bottom: 5px;
font-size: 16px;
}
.listItem {
border-left: 5px solid #0386fb;
padding-left: 5px;
background-color: #f2f9ff;
margin-bottom: 5px;
color: #0386fb;
font-size: 16px;
}
.listItem,.listItemNotHover .listItemTitle {
font-size: 14px;
// width: calc(100% - 21px);
white-space: nowrap;
/* 文本不会换行,会在同一行内继续,直到遇到<br>标签为止 */
text-overflow: ellipsis;
/* 当文本溢出包含它的容器时,显示省略号(...)来表示被截断的文本 */
overflow: hidden;
/* 超出部分隐藏 */
}
.icon{
font-size: 20px;
margin-right: 5px;
}
}
.establishBut {
width: 100%;
position: sticky;
bottom: 0;
padding: 10px;
}
}
::v-deep .el-input__inner {
background-color: #d7d7d757;
}
</style>

View File

@ -0,0 +1,80 @@
<template>
<el-dialog v-model="modelValue" :before-close="close" width="300px" center class="analysisDialog"
:append-to-body="true">
<template #title>
<div class="dialogTitle"> 语义分析类别选择</div>
</template>
<div>
<div v-for="(item, index) in butList" :key="index" class="dialogItem">
<div class="flex align-center" style="width: 80%;" @click="selectiveType(item)">
<img :src="item.icon" alt="">
<span>{{ item.text }}</span>
</div>
<el-icon>
<Right />
</el-icon>
</div>
</div>
<!-- <template #footer>
<div class="dialog-footer">
<el-button @click="close">取消</el-button>
<el-button type="primary" @click="dialogVisible = false">
确认
</el-button>
</div>
</template> -->
</el-dialog>
</template>
<script setup>
import { onMounted, reactive, ref } from 'vue'
import emitter from "@/utils/eventBus.js";
const emit = defineEmits(['update:modelValue'])
const butList = reactive([
{ icon: require('@/assets/images/icon/4.png'), text: '警情' },
{ icon: require('@/assets/images/icon/3.png'), text: '案件' },
{ icon: require('@/assets/images/icon/2.png'), text: '情报线索' },
{ icon: require('@/assets/images/icon/1.png'), text: '附件上传' },
])
onMounted(() => {
})
const selectiveType = (val) => {
emit('update:modelValue', false)
emitter.emit('showDetailsTitle', val.text)
emitter.emit('getData', val)
}
const close = () => {
emit('update:modelValue', false)
}
</script>
<style lang="scss" scoped>
.dialogTitle {
color: #007bd9;
width: 100%;
text-align: left;
font-family: 'verdana';
font-size: 18px;
font-weight: bold;
}
.dialogItem {
text-align: left;
font-family: 'verdana';
font-size: 16px;
padding: 10px 20px;
color: #000;
box-shadow: 0 0 8px rgba(154, 154, 154, 0.3);
margin-bottom: 10px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: space-between;
img {
margin-right: 10px;
}
}
</style>

View File

@ -0,0 +1,102 @@
<template>
<div class="searchTool">
<div class="searchToolTitle">
语义分析类别选择
</div>
<div class="searchToolContent flex align-center">
<div class="searchToolContentTitle">分析类别</div>
<el-cascader style=" width: calc(100% - 70px)" :show-all-levels="false" clearable filterable placeholder=" 请选择标签"
:options="dict.D_GSXT_FXLB" v-model="selectedValues" @change="handleChange" :props="endProps"
ref="myCascader" :collapse-tags="true" :collapse-tags-tooltip="true" :max-collapse-tags="10"/>
</div>
</div>
</template>
<script setup>
import { onMounted, computed, ref, watch } from 'vue'
import emitter from "@/utils/eventBus.js";
onMounted(() => {
})
const props = defineProps({
dict: {
type: Object,
default: () => { }
},
title: {
type: String,
default: ''
}
})
const selectedValues = ref([]);
const endProps = {
children: "itemList",
value: "dm",
label: "zdmc",
checkStrictly: false,
multiple: true,
};
const myCascader = ref()
const handleChange = (val) => {
const obj = myCascader.value.getCheckedNodes().map(item => {
return {
label: item.label,
value: item.value
}
})
emitter.emit('changeTab', obj)
}
watch(() => props.title, (val) => {
console.log(myCascader.value);
myCascader.value.handleClear()
})
</script>
<style lang="scss" scoped>
.searchTool {
background-color: #fff;
color: #000;
padding: 16px 20px;
border-radius: 5px;
.searchToolTitle {
font-size: 18px;
font-family: 'verdana';
position: relative;
}
.searchToolContent {
margin-top: 16px;
.searchToolContentTitle {
width: 70px;
}
.searchToolContentSelect {
width: 100%;
//
}
}
.searchToolTitle::after {
content: "";
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 80px;
border-radius: 5px;
height: 4px;
background-color: #0386fb;
background: linear-gradient(90deg, #0aa1ff 2%, #ffffff 100%);
}
}
</style>

View File

@ -0,0 +1,128 @@
<template>
<div style="padding: 10px 15px;">
<div class="flex align-center just-between" style="width: 100%;">
<div class="searchToolTitle">
{{ title }}
</div>
<div>
<el-button type="primary" plain @click="handleClose">关闭</el-button>
</div>
</div>
<div v-for="(item, index) in model" :key="index">
<div class="searchTsubTitle">{{ data[item.value] }}</div>
<formNewModel v-model="item.model" :formList="item.inputs" ref="elform" :rules="rules" />
</div>
</div>
</template>
<script setup>
import { ref, reactive, toRaw, computed, watch, nextTick, onMounted,getCurrentInstance } from "vue";
import formNewModel from "./formNewModel.vue"
import emitter from "@/utils/eventBus.js";
const { proxy } = getCurrentInstance()
const rules = ref([])
const elform = ref()
const props = defineProps({
listData: {
type: String,
default: ''
}, title: {
type: String,
default: ''
}
})
const data = {
10: "实体识别分析",
20: "事件识别分析",
30: "关系识别分析",
40: "特征识别分析",
}
const model = ref()
function simpleExtractJSON(text) {
// 找到第一个 [
const startIndex = text.indexOf('[');
if (startIndex === -1) return null;
// 找到最后一个完整的 }
let lastBraceIndex = text.lastIndexOf('}');
if (lastBraceIndex === -1) return null;
// 确保 } 后面没有其他字符(除了空格和换行)
let endIndex = lastBraceIndex + 1;
// 截取从 [ 到最后一个 } 的内容,然后加上 ]
let jsonString = text.substring(startIndex, endIndex) + ']';
try {
return JSON.parse(jsonString);
} catch (error) {
console.error("修改JSON格式复失败:", error);
return null;
}
}
onMounted(() => {
const json =props.listData ;
const jsonString = JSON.parse(json);
if (jsonString) {
const jsonObject = jsonString;
console.log(jsonObject);
model.value = jsonObject.reduce((acc, cur) => {
const key = Object.keys(cur)[0];
const prefix = key.substring(0, 2);
if (!acc[prefix] && prefix !== '50' && prefix !== '60') {
acc[prefix] = {
inputs: [],
model: {},
value: prefix
};
}
if (prefix === '50' || prefix === '60') {
acc[10].inputs.push({ label: cur[key].name, prop: key, type: "input", width: "33%" });
acc[10].model[key] = cur[key].content? cur[key].content : '-';
} else {
acc[prefix].inputs.push({ label: cur[key].name, prop: key, type: "input", width: "33%" });
acc[prefix].model[key] = cur[key].content=='-'||cur[key].content==''||cur[key].content=='无'? '/':cur[key].content ;
}
return acc;
}, {});
} else {
model.value = []
proxy.$message({ type: "error", message: "解析失败" });
}
})
const handleClose = () => {
emitter.emit('showDetails', true)
}
</script>
<style lang="scss" scoped>
.searchToolTitle {
font-size: 18px;
font-family: 'verdana';
position: relative;
color: #000;
}
.searchToolTitle::after {
content: "";
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 80px;
border-radius: 5px;
height: 4px;
background-color: #0386fb;
background: linear-gradient(90deg, #0aa1ff 2%, #ffffff 100%);
}
.searchTsubTitle {
font-size: 16px;
font-family: 'verdana';
color: #000;
margin: 10px 0;
}
</style>

View File

@ -0,0 +1,461 @@
<template>
<div class="searchTool">
<div class="searchToolTitle">
{{ title }}选择
</div>
<div class="searchToolContent">
<div v-show="showBut">
<el-button @click="showText = true" style="margin-bottom:10px;">上传附件</el-button> <el-button
type="danger">批量删除</el-button>
</div>
<MyTable :tableData="tableDate.tableData" :tableColumn="tableDate.tableColumn" :key="tableDate.keyCount"
:tableConfiger="tableDate.tableConfiger" :controlsWidth="tableDate.controlsWidth"
:tableHeight="showBut ? tableHeight - 60 : tableHeight" v-infinite-scroll="loadMore"
:infinite-scroll-disabled="disabled" :infinite-scroll-distance="50" @chooseData="chooseData">
<template #jqlxdm="{ row }">
{{ getTage('06000000', dict.JQLB) }}
</template>
<template #xlLx="{ row }">
<DictTag tag="D_GS_XS_LX" :value="row.xlLx" :tag="false" :options="dict.D_GS_XS_LX"></DictTag>
</template>
</MyTable>
</div>
<div class="searchToolFooter"> <el-button type="primary" class="establishBut" @click.stop="getText"
:loading="loading">智能分析</el-button>
</div>
</div>
<!-- 文字解析 -->
<ExtractionText v-model="showText" @change="getFileList"></ExtractionText>
</template>
<script setup>
import { onMounted, ref, reactive, watch } from 'vue'
import MyTable from "@/components/aboutTable/MyTable.vue";
import ExtractionText from "@/components/ExtractionText/index.vue";
import { lzJcjPjdbSelectPage, tbGsxtBqglSelect, yyfxAdd, completions } from '@/api/semanticAnalysis'
import { qcckGet } from "@/api/qcckApi.js";
import { getCurrentInstance } from 'vue'
import { ParsingText } from '@/api/qcckApi'
import emitter from "@/utils/eventBus.js";
import { useRoute } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
const { proxy } = getCurrentInstance()
const props = defineProps({
dict: {
type: Object,
default: {}
},
title: {
type: String,
default: ''
}
})
// const title=ref('警情')
const route = useRoute()
const emit = defineEmits(['update:modelValue'])
const tally = ref([])
const dataList = ref()
const showText = ref(false);
let tableDate = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "radio",
loading: false,
haveControls: false,
},
tableHeight: 0,
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
}, //分页
controlsWidth: 200, //操作栏宽度
tableColumn: []
});
// 警情
const particulars = [{
label: "警情编号",
prop: "jjdbh"
},
{
label: "警情类型",
prop: "jqlxdm",
showSolt: true
}, {
label: "警情内容",
prop: "bjnr",
showOverflowTooltip: true
}]
// 线索
const thread = [{
label: "线索名称",
prop: "xsMc",
}, {
label: "线索编号",
prop: "xsBh",
}, {
label: "线索类型",
prop: "xlLx",
showSolt: true
},
{
label: "线索内容",
prop: "xsNr",
showOverflowTooltip: true
}]
// 附件
const fjColumn = [{
label: "附件编号",
prop: "fjdz",
}, {
label: "附件名称",
prop: "fjmc",
}, {
label: "附件内容",
prop: "text",
showOverflowTooltip: true
}]
tableDate.tableColumn = particulars
const showBut = ref(false)
// 保存到数据库的数据
const saveData = ref({})
// 存储选中的类型
const selectType = ref('警情')
onMounted(() => {
tabHeightFn();
gettbJqListPage()
// 获取选择框的值
emitter.on('changeTab', (res) => {
tally.value = res
})
// 获取弹窗的值
emitter.on('getData', (res) => {
showBut.value = false
tableDate.pageConfiger.pageCurrent = 1
selectType.value = res.text
switch (res.text) {
case '警情':
tableDate.tableColumn = particulars
gettbJqListPage()
break;
case '情报线索':
tableDate.tableColumn = thread
gettbClListPage()
break;
case '案件':
break;
default:
showBut.value = true
tableDate.tableColumn = fjColumn
tableDate.tableData = []
break;
}
})
})
const tableHeight = ref()
const tabHeightFn = () => {
tableHeight.value = window.innerHeight - 480;
window.onresize = function () {
tabHeightFn();
};
};
const disabled = ref(false);
const loadMore = () => {
if (tableDate.total == tableDate.tableData.length) {
disabled.value = true
} else {
tableDate.pageConfiger.pageCurrent++;
gettbJqListPage();
}
};
// 警情请求
const gettbJqListPage = () => {
tableDate.tableConfiger.loading = true;
lzJcjPjdbSelectPage({
pageCurrent: tableDate.pageConfiger.pageCurrent,
pageSize: tableDate.pageConfiger.pageSize,
}).then(res => {
tableDate.tableData = tableDate.pageConfiger.pageCurrent == 1 ? res.records || [] : tableDate.tableData.concat(res.records || []);
tableDate.total = res.total;
}).finally(() => {
tableDate.tableConfiger.loading = false;
})
}
//线索请求
const gettbClListPage = () => {
tableDate.tableConfiger.loading = true;
const params = {
pageCurrent: tableDate.pageConfiger.pageCurrent,
pageSize: tableDate.pageConfiger.pageSize,
}
qcckGet(params, '/mosty-gsxt/qbcj/selectPage').then(res => {
tableDate.tableData = tableDate.pageConfiger.pageCurrent == 1 ? res.records || [] : tableDate.tableData.concat(res.records || []);
tableDate.total = res.total;
}).catch(() => {
}).finally(() => {
tableDate.tableConfiger.loading = false;
})
}
// 获取附件的信息
const getFileList = (val) => {
tableDate.tableData.push(val)
}
const chooseData = (val) => {
if (val.length > 0) {
dataList.value = val[0]
} else {
dataList.value = ''
}
// 01是警情和线索案件
// 02是文件
switch (selectType.value) {
case '警情':
saveData.value.sjlyid = val[0].jjdbh
saveData.value.tqlx = '01'
break
case '情报线索':
saveData.value.sjlyid = val[0].id
saveData.value.tqlx = '01'
break;
case '案件':
break;
default:
console.log(val);
saveData.value.fj = val.length > 0 ? val[0].fjdz : ''
saveData.value.tqlx = '02'
break;
}
}
const getTage = (val, zd) => {
if (zd) {
let tag = zd.find(item => {
return item.dm == val
})
return tag ? tag.zdmc : ''
}
}
const bqList = reactive({
sfBq: [],
XwBq: []
})
const getBq = () => {
tbGsxtBqglSelect({ bqLx: '01' }).then(res => {
bqList.sfBq = res
})
tbGsxtBqglSelect({ bqLx: '02' }).then(res => {
bqList.XwBq = res
})
}
getBq()
const loading = ref(false)
const getText = async (val) => {
if (tally.value.length == 0) {
proxy.$message({ type: "error", message: "请先选择标签" });
return
}
console.log(dataList.value);
if (!dataList.value) {
proxy.$message({ type: "error", message: "请选择分析的内容" });
return
}
const findSf = tally.value.find(item => item.value == "10011400")
const findXw = tally.value.find(item => item.value == "10011500")
let sfBq = []
let XwBq = []
if (findSf) {
sfBq = bqList.sfBq.map(v => {
return `  - 50${v.bqDm}:${v.bqMc}`
}).join('');
}
if (findXw) {
XwBq = bqList.XwBq.map(v => {
return `  - 60${v.bqDm}:${v.bqMc}`
}).join('');
}
// 获取行为标签和身份标签
let obj = {
model: "deepseek-32b",
prompt: `# 角色定位\n你是一名资深警务人员尤其擅长对警情、案件、线索等非结构化文本数据进行阅读理解并从中提取各种对象特征信息进行结构化并总结各种对象之间的关联关系。\n`,
max_tokens: 1000,
}
const strTow = `\n## 注意\n- 返回json格式以键值对的形式以标签代码为key标签名为name提取的值为content。例如[{40050900:{name:非法运输、买卖、储存、使用罂粟壳,content:-}}]\n\n# 警情信息\n  - `
const strThree = `\n## 任务\n根据警情信息识别对象信息以及对象之间的关联关系。最后以json形式输出不要做任何解释。直接给出完整的json\n`
const strFive = `\n## 注意点\n- 地址信息能够根据上下文信息按照省、市、县、街道/乡镇、路名分段补全并标准化。例如:四川省 成都市 高新区 桂溪街道 交子大道11号\n- 对象之间的关联关系由对象类型、对象id、关系类型、目标对象类型、目标对象id 5个属性组成。\n`
const marks = tally.value.map(v => {
return `  - ${v.value}:${v.label}`
}).join('');
obj.prompt = obj.prompt + marks + sfBq + XwBq + strFive + strThree + strTow
let time = '时间必须按照 YYYY-MM-DD HH:mm:ss 的格式 \n'
let str = ""
switch (selectType.value) {
case '警情':
str = dataList.value.bcjjnr ? dataList.value.bcjjnr : '' + dataList.value.bjnr
break
case '情报线索':
str = dataList.value.xsNr
break;
case '案件':
break;
default:
str = dataList.value.text
break;
}
obj.prompt = obj.prompt + time + str
saveData.value.qqcs = JSON.stringify(obj.prompt)
handleFx(obj)
}
function simpleExtractJSON(text) {
// 找到第一个 [
const startIndex = text.indexOf('[');
if (startIndex === -1) return null;
// 找到最后一个完整的 }
let lastBraceIndex = text.lastIndexOf('}');
if (lastBraceIndex === -1) return null;
// 确保 } 后面没有其他字符(除了空格和换行)
let endIndex = lastBraceIndex + 1;
// 截取从 [ 到最后一个 } 的内容,然后加上 ]
let jsonString = text.substring(startIndex, endIndex) + ']';
try {
return JSON.parse(jsonString);
} catch (error) {
console.error("简单修复失败:", error);
return null;
}
}
const handleFx = (val) => {
// const json = "此外,相关部门还对事件现场进行了彻底清理和修复,确保类似的安全隐患不再发生。也让广大民众重新燃起了对公共场合安全的信心。这起案件的发生也难免对当地的旅游业和公共活动产生了一定的负面影响,人们在短期内可能会对参加大型聚会和公共活动产生一定的心理阴影和不安感。政府应该在事件发生后,采取更加有力的措施来恢复民众的安全感和信任感,比如加强公共场所的安全防护措施,增加监控设备,提高安保人员的警惕性,确保类似事件不再发生。在媒体报道方面,各级媒体也应该正确引导舆论,避免过度渲染或煽动性报道,以免造成社会恐慌和对立情绪的升温。对于此次事件,媒体应负责任地对案件进行报道和评论,既不能夸大其词,引起社会不必要的恐慌;也不能过于淡化,导致人们对公共安全问题的忽视。总之,樊维秋驾车撞人案不仅是一起严重的刑事犯罪,更是对社会治理能力的一次严峻考验。在这起案件中暴露出了婚姻家庭矛盾纠纷化解机制的不足、社会支持体系的不完善以及重点人员的管理不到位等问题,这些都需要在未来的社会治理中不断改进和完善。只有全社会共同努力,才能减少甚至避免类似悲剧的发生,实现社会的和谐稳定。\n</think>\n\n```json\n[\n {\n \"10010100\": {\n \"name\": \"人物姓名\",\n \"content\": \"樊维秋\"\n }\n },\n {\n \"60GRDL004\": {\n \"name\": \"亲属离世\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL010\": {\n \"name\": \"故意伤害\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL014\": {\n \"name\": \"生活失意\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL015\": {\n \"name\": \"特定对象\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL016\": {\n \"name\": \"打架斗殴\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL020\": {\n \"name\": \"寻衅滋事\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL022\": {\n \"name\": \"涉访人员\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL023\": {\n \"name\": \"吸贩毒\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL026\": {\n \"name\": \"劳资纠纷\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL028\": {\n \"name\": \"扬言危害他人\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL030\": {\n \"name\": \"涉抢人员\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL033\": {\n \"name\": \"邻里纠纷\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL039\": {\n \"name\": \"医患纠纷\",\n \"content\": \"-\"\n }\n },\n {\n \"60GRDL044\": {\n \"name\": \"涉校人员\",\n \"content\": \"-\"\n }\n },\n {\n \"50SFXL227\": {\n \"name\": \"放火犯罪前科\",\n \"content\": \"-\"\n }\n }\n]\n```"
const res = {
id: "cmpl-a1922b4950c34ce181a3c169c830bd1f",
object: "text_completion",
created: 1756121492,
model: "deepseek-32b",
choices: [
{
index: 0,
text: "综上所述,这起案件不仅是一个个鲜活生命的消逝,更是一个深刻的社会警示。从中我们可以汲取教训,进一步完善相关法律法规,健全社会保障体系,加强社会管理和服务,才能更好地维护社会稳定,保护人民群众的生命财产安全。 \n</think>\n\n```json\n[\n {\n \"20060000\": {\n \"name\": \"专题特征类\",\n \"content\": \"驾车冲撞人群事件\"\n }\n },\n {\n \"20061200\": {\n \"name\": \"伤害类\",\n \"content\": \"35人死亡、43人受伤\"\n }\n },\n {\n \"20050000\": {\n \"name\": \"时间特征类\",\n \"content\": \"2024-11-11 20:00:00\"\n }\n },\n {\n \"20010000\": {\n \"name\": \"人员特征类\",\n \"content\": \"樊维秋\"\n }\n },\n {\n \"20040300\": {\n \"name\": \"平台IP地址\",\n \"content\": \"珠海市香洲区体育中心\"\n }\n },\n {\n \"20010101\": {\n \"name\": \"穿着\",\n \"content\": \"未知\"\n }\n },\n {\n \"20010102\": {\n \"name\": \"体型\",\n \"content\": \"未知\"\n }\n },\n {\n \"20010103\": {\n \"name\": \"发型\",\n \"content\": \"未知\"\n }\n },\n {\n \"20010104\": {\n \"name\": \"身高\",\n \"content\": \"未知\"\n }\n },\n {\n \"20010105\": {\n \"name\": \"年龄\",\n \"content\": \"未知\"\n }\n },\n {\n \"20010200\": {\n \"name\": \"病残孕特征\",\n \"content\": \"无\"\n }\n },\n {\n \"20010300\": {\n \"name\": \"职业特征\",\n \"content\": \"未知\"\n }\n },\n {\n \"20060100\": {\n \"name\": \"上访\",\n \"content\": \"无\"\n }\n },\n {\n \"20060200\": {\n \"name\": \"诈骗\",\n \"content\": \"无\"\n }\n },\n {\n \"20060300\": {\n \"name\": \"敲诈勒索\",\n \"content\": \"无\"\n }\n },\n {\n \"20060400\": {\n \"name\": \"盗窃\",\n \"content\": \"无\"\n }\n },\n {\n \"20060500\": {\n \"name\": \"涉黄\",\n \"content\": \"无\"\n }\n },\n {\n \"20060600\": {\n \"name\": \"涉赌\",\n \"content\": \"无\"\n }\n },\n {\n \"20060700\": {\n \"name\": \"涉毒\",\n \"content\": \"无\"\n }\n },\n {\n \"20060800\": {\n \"name\": \"强奸猥亵\",\n \"content\": \"无\"\n }\n },\n {\n \"20060900\": {\n \"name\": \"灾害事故\",\n \"content\": \"驾车冲撞人群事件\"\n }\n },\n {\n \"20061000\": {\n \"name\": \"自杀\",\n \"content\": \"无\"\n }\n },\n {\n \"20061100\": {\n \"name\": \"群众求助\",\n \"content\": \"无\"\n }\n },\n {\n \"20061200\": {\n \"name\": \"伤害类\",\n \"content\": \"35人死亡、43人受伤\"\n }\n },\n {\n \"20061300\": {\n \"name\": \"纠纷\",\n \"content\": \"婚姻破裂、生活失意、离婚财产分割\"\n }\n },\n {\n \"20061400\": {\n \"name\": \"食药环\",\n \"content\": \"无\"\n }\n },\n {\n \"20061500\": {\n \"name\": \"损坏公私财物\",\n \"",
logprobs: null,
finish_reason: "length",
stop_reason: null,
prompt_logprobs: null
}
],
usage: {
prompt_tokens: 1758,
total_tokens: 2758,
completion_tokens: 1000
}
}
ElMessageBox.prompt('请输入名称', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
inputPattern:
/^(?!s*$).+/,
inputErrorMessage: '请输入名称',
})
.then(({ value }) => {
loading.value = true
completions(val).then(res => {
console.log(res,"分析报告数据");
// let jsonString
// let jsonMatch = res.choices[0].text.match(/\[[\s\S]*?\]/g);
// if (!jsonMatch) {
// jsonMatch = simpleExtractJSON(res.choices[0].text)
// jsonString = jsonMatch;
// } else {
// jsonString = jsonMatch[0];
// }
// if (jsonMatch) {
// const promes = {
// fxlb: selectType.value,
// fxmc: value,
// tqjg:JSON.stringify(jsonString),//提取结果
// xyjg: res.choices[0].text,
// ...saveData.value
// }
// yyfxAdd(promes).then(res => {
// proxy.$message({ type: "success", message: "添加成功" });
// emitter.emit('getYyfxSelectPage')
// emitter.emit('getlistData',JSON.stringify(jsonString))
// emitter.emit('showDetails', false)
// }).catch(err => {
// console.log(err, "xxxxx");
// proxy.$message({ type: "error", message: "添加失败" });
// })
// } else {
// proxy.$message({ type: "error", message: "解析失败,请重新上传分析" });
// }
}).catch(err => {
console.log(err, 'vvvv');
}).finally(() => {
loading.value = false
})
})
.catch((err) => {
console.log(err);
})
}
</script>
<style lang="scss" scoped>
.searchTool {
margin-top: 10px;
background-color: #fff;
color: #000;
padding: 16px 20px;
border-radius: 5px;
.searchToolTitle {
font-size: 18px;
font-family: 'verdana';
position: relative;
}
.searchToolContent {
// width: 100%;
margin-top: 16px;
}
.searchToolTitle::after {
content: "";
display: block;
position: absolute;
bottom: 0px;
left: 0px;
width: 80px;
border-radius: 5px;
height: 4px;
background-color: #0386fb;
background: linear-gradient(90deg, #0aa1ff 2%, #ffffff 100%);
}
}
.searchToolFooter {
height: 50px;
display: flex;
justify-content: center;
.establishBut {
width: 200px;
margin-top: 10px;
height: 40px;
}
}
</style>

View File

@ -0,0 +1,64 @@
<template>
<div class="tabDataBox">
<div class="flex titleBox semanticBox" :style="{ height: tableHeight + 'px' }">
<div style=" height: 100%;width: 250px;margin-right: 10px;background-color: #fff;border-radius: 10px;">
<leftList />
</div>
<div style=" height: 100%;width: calc(100% - 262px);">
<div class="headerTitle">警情/案件/情报线索类语义分析</div>
<SearchTool />
<TableType />
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import leftList from './components/leftList.vue';
import SearchTool from './components/searchTool.vue'
import TableType from './components/tableType.vue'
onMounted(() => {
tabHeightFn();
});
const tableHeight = ref()
// 表格高度计算
const tabHeightFn = () => {
tableHeight.value =
window.innerHeight - 150;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.semanticBox {
background-color: #ffffff00 !important;
}
.headerTitle {
font-size: 24px;
padding: 10px;
font-family: 'verdana';
color: #000;
padding-left: 8px;
position: relative;
}
.headerTitle::after {
content: "";
display: block;
position: absolute;
top: 14px;
left: 0px;
width: 4px;
border-radius: 5px;
height: 31px;
background-color: #0386fb
}
</style>

View File

@ -0,0 +1,169 @@
<template>
<div class="statistical-analysis">
<!-- 左侧树形菜单 -->
<div class="left-menu">
<leftList />
</div>
<!-- 右侧内容区 -->
<div class="right-content" v-if="showDetails">
<div class="btnsBox">
<div class="headerTitle">{{ title }}类语义分析</div>
</div>
<div>
<SearchTool :dict="{ D_GSXT_FXLB }" :title="title" />
</div>
<TableType :dict="{ JQLB, JQLX, JQXL, JQZL, D_GS_XS_LX }" :title="title" />
</div>
<div class="right-content details" v-else>
<ShowDetails :listData="listData" :title="title" />
</div>
</div>
<!-- 详情 -->
</template>
<script setup>
import leftList from './components/leftList.vue';
import SearchTool from './components/searchTool.vue'
import TableType from './components/tableType.vue'
import { getCurrentInstance, onMounted, ref } from 'vue'
import ShowDetails from './components/showDetails.vue';
import emitter from "@/utils/eventBus.js";
const { proxy } = getCurrentInstance();
const { D_GSXT_FXLB, JQLB, JQLX, JQXL, JQZL, D_GS_XS_LX } = proxy.$dict("D_GSXT_FXLB", "JQLB", "JQLX", "JQXL", "JQZL", "D_GS_XS_LX")
const showDetails = ref(true)
const title = ref('警情')
const listData = ref()
onMounted(() => {
emitter.on('showDetails', (res) => {
showDetails.value = res
})
emitter.on('showDetailsTitle', (res) => {
title.value = res
})
emitter.on('getlistData', (res) => {
listData.value = res
})
})
</script>
<style lang="scss" scoped>
.statistical-analysis {
width: 100%;
height: 100%;
.left-menu {
float: left;
width: 280px;
height: calc(100% - 10px);
padding: 20px 4px;
margin-top: 20px;
border-radius: 4px;
background-color: #fff;
border-right: 1px solid #e8e8e8;
color: #333;
line-height: 32px;
::v-deep .checkBox {
flex-direction: column;
.checkall {
margin: 0;
}
}
::v-deep .el-checkbox-group {
display: flex;
flex-direction: column;
}
::v-deep .is-checked {
background: rgb(242, 249, 255);
margin-bottom: 4px;
}
::v-deep .el-checkbox {
padding-left: 8px;
margin-right: 4px;
}
.all {
width: calc(100% - 4px);
}
}
.right-content {
float: left;
width: calc(100% - 290px);
height: 100%;
margin-top: 20px;
margin-left: 10px;
border-radius: 4px;
box-sizing: border-box;
.btnsBox {
background: #fff;
padding: 10px 5px;
border-radius: 4px;
margin-bottom: 10px;
}
.cntlsit {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 22px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 4px;
box-sizing: border-box;
.cntItem {
width: 300px;
border: 1px solid #ccc;
color: #787878;
border-radius: 4px;
overflow: hidden;
.foot {
text-align: right;
margin-top: 4px;
border-top: 1px solid #ccc;
padding: 4px;
box-sizing: border-box;
}
}
}
}
.details {
background-color: #fff;
height: 99%;
}
}
.headerTitle {
font-size: 24px;
padding: 10px;
font-family: 'verdana';
color: #000;
padding-left: 8px;
position: relative;
}
.headerTitle::after {
content: "";
display: block;
position: absolute;
top: 14px;
left: 0px;
width: 4px;
border-radius: 5px;
height: 31px;
background-color: #0386fb
}
</style>

View File

@ -0,0 +1,91 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<span class="title">警情{{ title }} </span>
<div>
<!-- <el-button type="primary" size="small" :loading="loading" @click="submit">保存</el-button> -->
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<FormMessage :formList="formData" v-model="listQuery" ref="elform">
</FormMessage>
</div>
</div>
</template>
<script setup>
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, watch } from "vue";
const emit = defineEmits(["updateDate"]);
const props = defineProps({
dic: {
type: Object,
default: () => {}
}
});
const { proxy } = getCurrentInstance();
const dialogForm = ref(false); //弹窗
const formData = ref( [
{ label: "报警电话", prop: "bjdh", type: "input" },
{ label: "报警电话用户地址", prop: "bjdhyhdz", type: "input" },
{ label: "报警电话用户名", prop: "bjdhyhm", type: "input" },
{ label: "报警地址", prop: "bjdz", type: "input" },
{ label: "报警人名称", prop: "bjrmc", type: "input" },
{ label: "报警人证件号码", prop: "bjrzjhm", type: "input" },
{ label: "报警时间", prop: "bjsj", type: "input" },
{ label: "警情颜色", prop: "color", type: "select",options: props.dic.D_GS_SSYJ },
{ label: "管辖单位名称", prop: "gxdwmc", type: "input" },
{ label: "单位名称", prop: "jcjxtjsdwmc", type: "input" },
{ label: "接警单编号", prop: "jjdbh", type: "input" },
{ label: "接警单位名称", prop: "jjdwmc", type: "input" },
{ label: "接警录音号", prop: "jjlyh", type: "input" },
{ label: "接警时间", prop: "jjsj", type: "input" },
{ label: "接警完成时间", prop: "jjwcsj", type: "input" },
{ label: "接警员编号", prop: "jjybh", type: "input" },
{ label: "接警员姓名", prop: "jjyxm", type: "input" },
{ label: "警情标签", prop: "jqbq", type: "select",options: props.dic.D_BZ_JQBQ},
{ label: "警情地址", prop: "jqdz", type: "input" },
{ label: "警情类别代码", prop: "jqlbdm", type: "select", options: props.dic.JQLB },
{ label: "警情类型代码", prop: "jqlxdm", type: "select",options: props.dic.JQLX},
{ label: "警情来源", prop: "jqly", type: "select",options: props.dic.D_BZ_JQLY},
{ label: "警情细类代码", prop: "jqxldm", type: "select" ,options: props.dic.JQXL},
{ label: "警情子类代码", prop: "jqzldm", type: "select" ,options: props.dic.JQZL},
{ label: "报警内容", prop: "bjnr", type: "textarea", width: "100%" },
{ label: "补充接警内容", prop: "bcjjnr", type: "textarea", width: "100%" },
{ label: "被困人员情况说明", prop: "bkryqksm", type: "textarea", width: "100%" },
])
const listQuery = ref({}); //表单
const loading = ref(false);
const elform = ref();
const title = ref("详情");
const init = (type, row) => {
dialogForm.value = true;
title.value = type == "add" ? "新增" : "编辑";
// 根据id查询详情
if (row) {
listQuery.value = row;
}
};
// 关闭
const close = () => {
listQuery.value = {};
loading.value = false;
dialogForm.value = false;
listQuery.value = {}
};
defineExpose({ init });
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
</style>

View File

@ -0,0 +1,164 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="警情管理">
<!-- <el-button type="primary" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle"><CirclePlus /></el-icon>
<span style="vertical-align: middle">新增</span>
</el-button> -->
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount"></Search>
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
<!-- <template #jjlx="{ row }">
<DictTag :tag="false" :value="row.jjlx" :options="D_BZ_JQBQ" />
</template> -->
<template #jqlbdm="{ row }">
<DictTag :tag="false" :value="row.jqlbdm" :options="JQLB" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" @click="addEdit('edit', row)">详情</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<!-- 编辑详情 -->
<EditAddForm v-if="show" ref="detailDiloag" :dic="{ JQLB,JQLX,JQXL,JQZL,D_BZ_JQLY,D_BZ_JQFL,JQLB_DP,D_BZ_JQBQ,D_GS_SSYJ }"
@updateDate="getList" />
</div>
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import EditAddForm from "./components/editAddForm.vue";
import { lzJcjPjdbSelectPage } from '@/api/semanticAnalysis.js'
import { reactive, ref, onMounted, getCurrentInstance, nextTick } from "vue";
const { proxy } = getCurrentInstance();
const { JQLB,JQLX,JQXL,JQZL,D_BZ_JQLY,D_BZ_JQFL,JQLB_DP,D_BZ_JQBQ,D_GS_SSYJ } = proxy.$dict("JQLB",'JQLX','JQXL','JQZL','D_BZ_JQLY','D_BZ_JQFL','JQLB_DP','D_BZ_JQBQ','D_GS_SSYJ'); //获取字典数据
const detailDiloag = ref();
const show = ref(false)
const searchConfiger = ref([
{
label: "接警员姓名",
prop: "jjyxm",
placeholder: "请输入接警员姓名",
showType: "input"
},
{
label: "报警内容",
prop: "bjnr",
placeholder: "请输入报警内容",
showType: "input"
},
{
label: "接警单编号",
prop: "jjdbh",
placeholder: "请输入接警单编号",
showType: "input"
},
]);
const searchBox = ref(); //搜索框
const pageData = reactive({
tableData: [], //表格数据
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false,
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
}, //分页
controlsWidth: 160, //操作栏宽度
tableColumn: [
{ label: "接警单编号", prop: "jjdbh" },
{ label: "报警电话", prop: "bjdh" },
{ label: "报警时间", prop: "bjsj" },
{ label: "报警内容", prop: "bjnr", showOverflowTooltip: true },
{ label: "接警员姓名", prop: "jjyxm" },
// { label: "警情标签", prop: "jjlx", showSolt: true },
{ label: "警情类型", prop: "jqlbdm",showSolt:true },
{ label: "警情地址", prop: "jqdz" },
{ label: "补充接警内容", prop: "bcjjnr", showOverflowTooltip: true },
]
});
onMounted(() => {
tabHeightFn();
getList()
});
const listQuery=ref({})
// 搜索
const onSearch = (val) => {
listQuery.value = { ...val };
pageData.pageConfiger.pageCurrent = 1;
getList()
}
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList()
}
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList()
}
const getList = () => {
pageData.tableConfiger.loading = true;
const params = {
pageCurrent: pageData.pageConfiger.pageCurrent,
pageSize: pageData.pageConfiger.pageSize,
...listQuery.value
}
lzJcjPjdbSelectPage(params).then(res => {
console.log(res);
pageData.tableData = res.records || [];
pageData.total = res.total;
}).finally(() => {
pageData.tableConfiger.loading = false;
})
}
// 新增
const addEdit = (type, row) => {
show.value = true;
nextTick(() => {
detailDiloag.value.init(type, row,);
})
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style>
.el-loading-mask {
background: rgba(0, 0, 0, 0.5) !important;
}
</style>

View File

@ -1,17 +1,17 @@
<template>
<DialogDragger title="预警详情" top="150px" v-model="props.show" @close="close">
<DialogDragger title="预警详情" top="150px" v-model="props.show" @close="close">
<ul class="warningList" ref="gjyjList">
<li v-for="item in props.data" :key="item.id">
<YjItem :item="item"/>
<YjItem :item="item" />
</li>
<MOSTY.Empty :show="props.data.length <= 0" :imgSize="150"></MOSTY.Empty>
</ul>
<!-- :style="{height: `calc(100vh - ${handleHs}px)`}" -->
<div style="position:relative;width: 100%;" :style="{height: `calc(100vh - ${handleHs}px)`}">
<div style="position:relative;width: 100%;" :style="{ height: `calc(100vh - ${handleHs}px)` }">
<GdMap v-if="showMap"></GdMap>
</div>
</DialogDragger>
@ -29,66 +29,69 @@ const gjyjList = ref(null); //预警列表数据
const props = defineProps({
//某条预警详情
data: {
type:Array,
default:[]
type: Array,
default: []
},
show: {
type:Boolean,
default:false
type: Boolean,
default: false
},
});
console.log(props.show);
//关闭
function close() {
emitter.emit('deletePointArea','home_yj_map');
emitter.emit("showHomeYJ",false);
emitter.emit('deletePointArea', 'home_yj_map');
emitter.emit("showHomeYJ", false);
}
const showMap=ref(false)
const showMap = ref(false)
onMounted(() => {
setTimeout(() => {
showMap.value = true
setTimeout(() => {
for (let i = 0; i < props.data.length; i++) {
const item = props.data[i];
console.log(item);
const item = props.data[i];
console.log(item);
emitter.emit('showHomeYJ',[item]);
emitter.emit('deletePointArea','home_yj_map');
if(!item.jd || !item.jd) return proxy.$message({ type: "warning", message: "该预警没有坐标!" });
let icon = require('@/assets/point/yj.png');
if(item.yjjb == '20') icon = require('@/assets/point/yj1.png');
if(item.yjjb == '30') icon = require('@/assets/point/yj2.png');
if(item.yjjb == '40') icon = require('@/assets/point/yj3.png');
emitter.emit('addPointArea',{flag:'home_yj_map',icon,coords:[item]});
emitter.emit('setMapCenter',{location:[item.jd,item.wd],zoomLevel:10});
}
emitter.emit('showHomeYJ', [item]);
emitter.emit('deletePointArea', 'home_yj_map');
if (!item.jd || !item.jd) return proxy.$message({ type: "warning", message: "该预警没有坐标!" });
let icon = require('@/assets/point/yj.png');
if (item.yjjb == '20') icon = require('@/assets/point/yj1.png');
if (item.yjjb == '30') icon = require('@/assets/point/yj2.png');
if (item.yjjb == '40') icon = require('@/assets/point/yj3.png');
emitter.emit('addPointArea', { flag: 'home_yj_map', icon, coords: [item] });
emitter.emit('setMapCenter', { location: [item.jd, item.wd], zoomLevel: 10 });
}
}, 500);
}, 200);
})
const handleHs=ref(0)
const handleHs = ref(0)
watch(() => gjyjList.value, (val) => {
console.log(val.clientHeight);
handleHs.value=val.clientHeight+198+150+20
},{deep:true})
handleHs.value = val.clientHeight + 198 + 150 + 20
}, { deep: true })
</script>
<style lang="scss" scoped>
@import "@/assets/css/homeScreen.scss";
.dialogBox {
z-index: 999;
ul.warningList{
ul.warningList {
height: calc(100vh - 198px);
overflow: hidden;
overflow-y: auto;
padding: 7px 10px;
box-sizing: border-box;
.photo {
width: 60px;
height: 80px;
img {
width: 100%;
height: 100%;
@ -96,9 +99,9 @@ watch(() => gjyjList.value, (val) => {
}
}
}
//加载时 取消背景
::v-deep .el-loading-mask {
background-color: transparent !important;
}
</style>

View File

@ -90,7 +90,7 @@
<script setup>
import { getItem } from "@/utils/storage";
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
import emitter from "@/utils/eventBus.js";
import { timeValidate, weekValidate } from "@/utils/tools.js";
import { useRouter, useRoute, onBeforeRouteLeave } from "vue-router";
import { useStore } from "vuex";

View File

@ -8,6 +8,7 @@ const serverHost = "http://192.168.1.32:8006"//波哥
// const serverHost = "http://192.168.0.231:8006"//线上
// const serverHost = "http://192.168.1.117:8006"//周
// const serverHost = "http://192.168.1.98:8006"//毛毛
module.exports = {
// configureWebpack: {
// resolve: {
@ -51,22 +52,24 @@ module.exports = {
changeOrigin: true,
logLevel: "debug"
},
"/": {
"/chat": {
target: 'https://api.deepseek.com/',
changeOrigin: true,
logLevel: "debug",
},
"/bpm": {
target: "http://192.168.0.101:32001",
changeOrigin: true,
logLevel: "debug",
onProxyReq(proxyReq) {
// 在这里添加固定的 Cookie
proxyReq.setHeader('Cookie', 'clientKey-temp=1c2db6cac7dd405fb33c2a6725337925; static_version_fpip-manage=1.222; clientKey=30842687f48c4ed1818dbc45a0cdd4e1; static_version_fpip-jgpt=1.222; static_version_fpip-mdjf=1.222; static_version_fpip-tddx=1.222; static_version_fpip-dtbd=1.222; static_version_fpip-qzgl=1.222; static_version_fpip-bzdz=1.222; static_version_fpip-pcsgl=1.222; static_version_fpip-sydw=1.222')
},
},
"/chat": {
target: 'https://api.deepseek.com/chat/',
"/flowApproval": {
target: "http://192.168.0.101:32001",
changeOrigin: true,
logLevel: "debug",
}, "/orgOrganization": {
target: "http://192.168.0.101:32001",
changeOrigin: true,
logLevel: "debug",
pathRewrite: {
"^/chat": "/"
}
},
}
},