This commit is contained in:
lcw
2025-09-24 18:10:41 +08:00
parent 63cd5ba2a3
commit 16d05358d1
178 changed files with 5957 additions and 1293 deletions

156
src/api/model.js Normal file
View File

@ -0,0 +1,156 @@
import request from "@/utils/request";
const gsxtApi = "/mosty-api/mosty-gsxt";
// 新增模型
export const addEntity = (data) => {
return request({
url: gsxtApi + "/gsxtMxgl/addEntity",
method: "POST",
data
});
};
// 分页查询模型
export const getPageList = (params) => {
return request({
url: gsxtApi + "/gsxtMxgl/getPageList",
method: "get",
params
});
};
// 不分页列表查询模型
export const selectList = (params) => {
return request({
url: gsxtApi + "/gsxtMxgl/selectList",
method: "get",
params
});
};
// 通过id查询模型详情
export const getEntityById = (params) => {
return request({
url: gsxtApi + `/gsxtMxgl/${params.id}`,
method: "get",
});
};
// 修改模型
export const editEntity = (data) => {
return request({
url: gsxtApi + `/gsxtMxgl/editEntity`,
method: "put",
data
});
};
// 删除模型
export const deleteEntity = (data) => {
return request({
url: gsxtApi + `/gsxtMxgl/deleteEntity`,
method: "delete",
data
});
};
// 四色预警新增
export const addSsyjpz = (data) => {
return request({
url: gsxtApi + `/mxglSsyjpz/addEntity`,
method: "POST",
data
});
}
// 分页查询四色预警规则配置列表
export const getSsyjpzPageList = (params) => {
return request({
url: gsxtApi + `/mxglSsyjpz/getPageList`,
method: "get",
params
});
}
// 删除四色预警规则配置
export const deleteSsyjpz = (data) => {
return request({
url: gsxtApi + `/mxglSsyjpz/deleteEntity`,
method: "delete",
data
});
}
// 修改四色预警规则配置
export const editSsyjpz = (data) => {
return request({
url: gsxtApi + `/mxglSsyjpz/editEntity`,
method: "put",
data
});
}
// 运行规则
export const getSsyjpzMxgzxl = (params) => {
return request({
url: gsxtApi + `/mxglSsyjpz/mxgzxl`,
method: "get",
params
});
}
// 新增预警规则
export const addYjgzpz = (data) => {
return request({
url: gsxtApi + `/mxglYjgzpz/addEntity`,
method: "POST",
data
});
}
// 修改预警规则配置
export const editYjgzpz = (data) => {
return request({
url: gsxtApi + `/mxglYjgzpz/editEntity`,
method: "put",
data
});
}
// 分页查询预警规则配置列表
export const getYjgzpzPageList = (params) => {
return request({
url: gsxtApi + `/mxglYjgzpz/getPageList`,
method: "get",
params
});
}
// 不分页查询预警规则配置列表
export const getYjgzpzSelectList = (params) => {
return request({
url: gsxtApi + `/mxglYjgzpz/selectList`,
method: "get",
params
});
}
// 不分页查询预警规则配置列表
export const mxglSsyjpzSelectList = (params) => {
return request({
url: gsxtApi + `/mxglSsyjpz/selectList`,
method: "get",
params
});
}
// 删除预警规则配置
export const deleteYjgzpz = (data) => {
return request({
url: gsxtApi + `/mxglYjgzpz/deleteEntity`,
method: "delete",
data
});
}
// 运行规则
export const getYjgzpzMxgzxl = (params) => {
return request({
url: gsxtApi + `/mxglYjgzpz/mxgzxl`,
method: "get",
params
});
}
// 预警信息
export const getYjxxPageList = (params) => {
return request({
url: gsxtApi + `/mxglYjxx/getPageList`,
method: "get",
params
});
}

View File

@ -1,61 +1,106 @@
import request from "@/utils/request";
import axios from "axios";
const api = "/mosty-api";
import { getItem, setItem } from '@/utils/storage'
// 解析数据
export function ParsingText(data,fun){
export function ParsingText(data, fun) {
axios({
method: 'post',
url: '/chat/completions',
data:data,
data: data,
headers: { 'Authorization': 'Bearer sk-064b5c53131c4046883b718f2b31c050' }
}).then( (res) => {
}).then((res) => {
fun(res)
})
}
//get 请求
export const qcckFlvGet = (params = {}, url) => {
return request({
url: url,
method: "get",
params
});
//get 请求 (for flv streams, without API prefix)
export const qcckFlvGet = (params = {}, url, cookie) => {
if (cookie) {
return request({
withCredentials: true,
url: url,
method: "get",
params
});
} else {
return request({
url: url,
method: "get",
params
});
}
};
//get 请求
export const qcckGet = (params = {}, url) => {
return request({
url: api + url,
method: "get",
params
});
export const qcckGet = (params = {}, url, cookie) => {
if (cookie) {
return request({
withCredentials: true,
url: api + url,
method: "get",
params
});
} else {
return request({
url: api + url,
method: "get",
params
});
}
};
//post 请求
export const qcckPost = (data = {}, url) => {
return request({
url: api + url,
method: "post",
data
});
export const qcckPost = (data = {}, url, cookie) => {
if (cookie) {
return request({
withCredentials: true,
url: api + url,
method: "post",
data
});
} else {
return request({
url: api + url,
method: "post",
data
});
}
};
//put 请求
export const qcckPut = (data = {}, url) => {
return request({
url: api + url,
method: "put",
data
});
export const qcckPut = (data = {}, url, cookie) => {
if (cookie) {
return request({
withCredentials: true,
url: api + url,
method: "put",
data
});
} else {
return request({
url: api + url,
method: "put",
data
});
}
};
//put 请求
export const qcckDelete = (data = {}, url) => {
return request({
url: api + url,
method: "delete",
data
});
//delete 请求
export const qcckDelete = (data = {}, url, cookie) => {
if (cookie) {
return request({
withCredentials: true,
url: api + url,
method: "delete",
data
});
} else {
return request({
url: api + url,
method: "delete",
data
});
}
};

View File

@ -0,0 +1,242 @@
<template>
<el-dialog
:title="titleValue"
width="1400px"
:model-value="modelValue"
append-to-body
@close="closed"
>
<div>
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
<el-form-item label="标签名称">
<el-input
placeholder="请输入标签名称"
v-model="listQuery.bqMc"
clearable
></el-input>
</el-form-item>
<el-form-item>
<el-button type="success" @click="handleFilter">查询</el-button>
<el-button type="info" @click="reset"> 重置 </el-button>
</el-form-item>
</el-form>
<div
class="tabBox"
:class="props.Single ? 'tabBoxRadio' : ''"
:key="keyVal"
style="margin-top: 0px"
>
<el-table
ref="multipleUserRef"
@selection-change="handleSelectionChange"
:data="tableData"
v-loading="loading"
border
:row-key="keyid"
style="width: 100%"
height="450"
>
<el-table-column
type="selection"
width="55"
:reserve-selection="true"
/>
<el-table-column prop="zdmc" align="center" label="名称" />
<el-table-column prop="dm" align="center" label="代码" />
</el-table>
</div>
<!-- <div class="fenye" :style="{ top: tableHeight + 'px' }">
<el-pagination
class="pagination"
@pageSize-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="listQuery.pageCurrent"
:page-sizes="[10, 20, 50, 100]"
:page-pageSize="listQuery.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
></el-pagination>
</div> -->
</div>
<template #footer>
<div class="dialog-footer">
<el-button @click="closed">取消</el-button>
<el-button type="primary" @click="onComfirm">确认</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import {getDictItem} from '@/api/semanticAnalysis.js'
import { defineProps, ref, getCurrentInstance, watch } from "vue";
const props = defineProps({
modelValue: {
type: Boolean,
default: false
},
titleValue: {
type: String,
default: "选择标签"
},
LeaderType: {
type: String,
default: ""
},
//是否单选
Single: {
type: Boolean,
default: false
},
roleIds: {
type: Array,
default: []
}
});
const loading = ref(false);
const total = ref(0);
const listQuery = ref({
pageCurrent: 1,
pageSize: 20
});
const keyVal = ref();
const multipleUserRef = ref(null);
const multipleSelectionUser = ref([]);
const tableData = ref([]);
const emits = defineEmits(["update:modelValue", "choosed"]);
const keyid = (row) => {
return row.id;
};
const closed = () => {
emits("update:modelValue", false);
};
const reset = () => {
listQuery.value = { pageCurrent: 1, pageSize: 20 };
getListData();
};
// 为用户分配角色
const onComfirm = () => {
const userList = multipleSelectionUser.value;
let list = [];
let listId = [];
userList.forEach((val) => {
if (listId.indexOf(val.id) == -1) {
list.push(val);
listId.push(val.id);
}
});
emits("choosed", list);
closed();
};
/**
* pageSize 改变触发
*/
const handleSizeChange = (currentSize) => {
listQuery.value.pageSize = currentSize;
getListData();
};
/**
* 页码改变触发
*/
const handleCurrentChange = (currentPage) => {
listQuery.value.pageCurrent = currentPage;
getListData();
};
const getListData = () => {
// keyVal.value++;
loading.value = true;
const params = { dictCode: "00000000" };
console.log(params);
getDictItem(params)
.then((res) => {
loading.value = false;
// tableData.value = res.records || [];
tableData.value = res
// .records || [];
// total.value = res.total;
multipleUser();
})
.catch(() => {
loading.value = false;
});
};
//列表回显 - 优化版,确保已选择数据正确回显
function multipleUser() {
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
return;
}
// 先清除所有选中状态
tableData.value.forEach((item) => {
multipleUserRef.value.toggleRowSelection(item, false);
});
// 再根据roleIds重新设置选中状态
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
tableData.value.forEach((item) => {
if (props.roleIds.some((id) => id == item.id)) {
multipleUserRef.value.toggleRowSelection(item, true);
}
});
}
}
const handleFilter = () => {
listQuery.value.pageCurrent = 1;
getListData();
};
const handleSelectionChange = (val) => {
if (props.Single) {
if (val.length > 1) {
let del_row = val.shift();
multipleUserRef.value.toggleRowSelection(del_row, false);
}
multipleSelectionUser.value = val;
} else {
multipleSelectionUser.value = val;
}
};
// 监听弹窗打开状态,打开时重新加载数据
watch(
() => props.modelValue,
(val) => {
if (val) {
handleFilter();
}
},
{ immediate: true }
);
// 监听roleIds变化确保数据回显正确
watch(
() => props.roleIds,
(newRoleIds) => {
// 使用setTimeout确保在表格数据加载完成后再进行选择
setTimeout(() => {
multipleUser();
}, 100);
},
{ deep: true }
);
</script>
<style lang="scss" scoped>
@import "@/assets/css/layout.scss";
@import "@/assets/css/element-plus.scss";
</style>
<style>
.tabBoxRadio .el-checkbox__inner {
border-radius: 50% !important;
}
.tabBoxRadio .el-table__header-wrapper .el-checkbox {
display: none;
}
</style>

View File

@ -8,10 +8,10 @@
>
<div>
<el-form :model="listQuery" class="mosty-from-wrap" :inline="true">
<el-form-item label="报告名称">
<el-form-item label="标签名称">
<el-input
placeholder="请输入报告名称"
v-model="listQuery.bgmc"
placeholder="请输入标签名称"
v-model="listQuery.bqMc"
clearable
></el-input>
</el-form-item>
@ -36,17 +36,21 @@
style="width: 100%"
height="450"
>
<!-- <el-table-column
<el-table-column
type="selection"
width="55"
:reserve-selection="true"
/> -->
<el-table-column prop="bgmc" align="center" label="报告名称" />
<el-table-column prop="scsj" align="center" label="保存时间" />
<el-table-column align="center" label="操作">
/>
<el-table-column prop="bqMc" align="center" label="标签名称" />
<el-table-column prop="bqDm" align="center" label="标签代码" />
<el-table-column prop="bqDj" align="center" label="标签等级">
<template #default="{ row }">
<el-button type="primary" size="mini" @click="deletBg(row)">删除</el-button>
<el-button type="primary" size="mini" @click="onComfirm(row.bgnr)">详情</el-button>
<DictTag :tag="false" :value="row.bqDj" :options="D_GS_BQ_DJ" />
</template>
</el-table-column>
<el-table-column prop="bqYs" align="center" label="标签颜色">
<template #default="{ row }">
<DictTag :value="row.bqYs" :tag="false" :options="D_GS_SSYJ" />
</template>
</el-table-column>
</el-table>
@ -67,17 +71,18 @@
<template #footer>
<div class="dialog-footer">
<el-button @click="closed">取消</el-button>
<!-- <el-button type="primary" @click="onComfirm">确认</el-button> -->
<el-button type="primary" @click="onComfirm">确认</el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessage } from 'element-plus'
import { qcckGet ,qcckDelete} from "@/api/qcckApi.js";
import { qcckGet } from "@/api/qcckApi.js";
import { defineProps, ref, getCurrentInstance, watch } from "vue";
const { proxy } = getCurrentInstance();
const { D_GS_BQ_DJ, D_GS_SSYJ,D_GS_BQ_LB,D_GS_BQ_LX } = proxy.$dict("D_GS_BQ_DJ", "D_GS_SSYJ","D_GS_BQ_LB","D_GS_BQ_LX"); //
const props = defineProps({
modelValue: {
type: Boolean,
@ -85,7 +90,7 @@ const props = defineProps({
},
titleValue: {
type: String,
default: "查看报告"
default: "选择标签"
},
LeaderType: {
type: String,
@ -94,14 +99,11 @@ const props = defineProps({
//
Single: {
type: Boolean,
default: true
default: false
},
roleIds: {
type: Array,
default: []
}, chageData: {
type: String,
default: ""
}
});
const loading = ref(false);
@ -129,17 +131,17 @@ const reset = () => {
};
//
const onComfirm = (val) => {
// const userList = multipleSelectionUser.value;
// let list = [];
// let listId = [];
// userList.forEach((val) => {
// if (listId.indexOf(val.id) == -1) {
// list.push(val);
// listId.push(val.id);
// }
// });
emits("choosed", val);
const onComfirm = () => {
const userList = multipleSelectionUser.value;
let list = [];
let listId = [];
userList.forEach((val) => {
if (listId.indexOf(val.id) == -1) {
list.push(val);
listId.push(val.id);
}
});
emits("choosed", list);
closed();
};
/**
@ -156,16 +158,11 @@ const handleCurrentChange = (currentPage) => {
listQuery.value.pageCurrent = currentPage;
getListData();
};
const chageDatas=ref()
// watch(() => props.chageData, (val) => {
// chageDatas.value = val;
// getListData()
// },{deep:true,immediate:true})
const getListData = () => {
keyVal.value++;
loading.value = true;
const params = { ...listQuery.value,ypid:chageDatas.value};
qcckGet(params, "/mosty-gsxt/gsxtYpbg/getPageList")
const params = { ...listQuery.value, bqLb: "01" };
qcckGet(params, "/mosty-gsxt/tbGsxtBqgl/selectPage")
.then((res) => {
loading.value = false;
tableData.value = res.records || [];
@ -177,14 +174,25 @@ const getListData = () => {
});
};
//
// -
function multipleUser() {
if (!multipleUserRef.value || !tableData.value || tableData.value.length === 0) {
return;
}
//
tableData.value.forEach((item) => {
multipleUserRef.value.toggleRowSelection(item, false);
if (props.roleIds.some((id) => id == item.id)) {
multipleUserRef.value.toggleRowSelection(item, true);
}
});
// roleIds
if (props.roleIds && Array.isArray(props.roleIds) && props.roleIds.length > 0) {
tableData.value.forEach((item) => {
if (props.roleIds.some((id) => id == item.id)) {
multipleUserRef.value.toggleRowSelection(item, true);
}
});
}
}
const handleFilter = () => {
@ -203,40 +211,29 @@ const handleSelectionChange = (val) => {
multipleSelectionUser.value = val;
}
};
//
const deletBg = (val) => {
const id = { ids: [val.id] }
proxy.$confirm('确定删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
qcckDelete(id, `/mosty-gsxt/gsxtYpbg/deleteEntity`).then((res) => {
getListData();
ElMessage.success("删除成功");
})
}).catch(() => {
ElMessage({
type: 'info',
message: '已取消删除'
});
});
}
//
watch(
() => props.modelValue,
(val) => {
if (val) {
chageDatas.value = props.chageData;
console.log(chageDatas.value );
handleFilter();
}
},
{ immediate: true }
);
// roleIds
watch(
() => props.roleIds,
(newRoleIds) => {
// 使setTimeout
setTimeout(() => {
multipleUser();
}, 100);
},
{ deep: true }
);
</script>
<style lang="scss" scoped>

View File

@ -100,7 +100,7 @@ onMounted(() => {
window.map = map;
map.mapboxGLMap.on("load", () => {
map.addWMTSLayer(
"/PGIS_S_TileMapServer/Maps/XZDJ_SL/EzMap"
"/PGIS_S_TileMapServer/Maps/XZDJ_DJ/EzMap"
,
{
Service: "getImage",

View File

@ -166,7 +166,6 @@ watch(
let arr = val ? val : [];
if (arr && arr.length > 0) {
if (!props.sfUrl) {
console.log(arr, "图片");
if (Array.isArray(arr)) {
fileList.value = arr.map((el) => {
if (Object.prototype.toString.call(el) === "[object Object]") {

View File

@ -31,7 +31,8 @@ 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'
import { getItem, setItem } from '@/utils/storage'
import { setCookie } from '@/utils/cookie'
const props = defineProps({
modelValue: {
type: Boolean,
@ -85,9 +86,12 @@ const qcckGetList = () => {
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)
qcckGet({ sfzh: Sfzh }, '/mosty-base/fzmsg/getCokie',true).then(res => {
// setItem('fzcookie', res)
// setCookie('clientKey', res.sy)
setCookie('clientKey', res.substring(10,res.length))
// document.cookie = res.cookie
// setItem('userOrg',res.userOrg)
qcckGetList()
})
}

View File

@ -47,7 +47,15 @@ const mode = "default";
//工具配置
const toolbarConfig = {
excludeKeys: ["blockquote", "codeBlock"] //清除不必要的工具,引用和代码块
// 注意wangEditor默认包含了对齐相关的按钮包括两端对齐
// 如果需要自定义工具栏,可以使用以下配置
// toolbarKeys: [
// // 其他工具栏按钮
// 'justifyJustify', // 两端对齐按钮
// ]
};
// 为了确保编辑器内容默认应用两端对齐,我们在编辑器创建时设置全局样式
const emits = defineEmits(["update:textContent", "changeFn","update:modelValue","SaveReport"]);
//编辑器配置
const editorConfig = {
@ -75,6 +83,27 @@ const editorConfig = {
}
};
// 初始化完成后设置默认的两端对齐样式
const setDefaultJustifyStyle = () => {
const editor = editorRef.value;
if (editor) {
// 获取编辑区域元素
const editableEle = editor.getEditableContainer();
if (editableEle) {
editableEle.style.textAlign = 'justify';
// 添加中文两端对齐的处理样式
editableEle.style.textJustify = 'inter-character';
}
}
};
// 监听编辑器创建完成事件,设置两端对齐样式
watch(editorRef, (newVal) => {
if (newVal) {
setDefaultJustifyStyle();
}
});
const uploadFn = (file, insertFn) => {
let param = new FormData();
param.append("file", file);
@ -110,6 +139,18 @@ const downloadWithStyles = () => {
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>富文本导出</title>
<style>
/* 应用两端对齐样式 */
body {
text-align: justify;
text-justify: inter-character; /* 中文文本两端对齐 */
font-family: "Microsoft YaHei", Arial, sans-serif;
}
p {
text-align: justify;
text-justify: inter-character;
}
</style>
</head>
<body>
${props.textContent}
@ -124,13 +165,15 @@ const downloadWithStyles = () => {
saveAs(blob, 'styled-document.doc');
};
const SaveReport = () => {
console.log(props.textContent);
emits("SaveReport",props.textContent)
}
</script>
<style lang="scss" scoped>
.cntBox{
height: 60vh;
// height: 60vh;
padding: 8px;
box-sizing: border-box;
overflow: hidden;

View File

@ -174,7 +174,7 @@ export const publicRoutes = [
redirect: "/IdentityManage",
component: layout,
children: [
{
{
path: "/FourColorWarning",
name: "FourColorWarning",
meta: { title: "四色预警管理", icon: "article" },
@ -191,11 +191,20 @@ export const publicRoutes = [
component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/centerHome/index"),
meta: { title: "预警中心大屏", icon: "article" },
},
// {
// path: "/warningBk",
// name: "warningBk",
// meta: { title: "布控预警", icon: "article" },
// component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/warningBk/index"),
// },
{
path: "/warningBk",
name: "warningBk",
meta: { title: "布控预警", icon: "article" },
component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/warningBk/index"),
path: "/warningList",
name: "warningList",
component: () => import("@/views/backOfficeSystem/fourColorManage/warningList/index"),
meta: {
title: "布控预警",
icon: "article"
}
},
{
path: "/behaviorWarning",
@ -220,6 +229,14 @@ export const publicRoutes = [
name: "modelWarning",
meta: { title: "模型预警", icon: "article" },
component: () => import("@/views/backOfficeSystem/fourColorManage/warningControl/modelWarning/index"),
}, {
path: "/tsypHome",
name: "tsypHome",
component: () => import("@/views/backOfficeSystem/JudgmentHome/tsypHome/index"),
meta: {
title: "模型管理",
icon: "article"
}
},
]
@ -260,15 +277,7 @@ export const publicRoutes = [
icon: "article"
}
},
{
path: "/warningList",
name: "warningList",
component: () => import("@/views/backOfficeSystem/fourColorManage/warningList/index"),
meta: {
title: "布控预警列表",
icon: "article"
}
},
// 暂时取消
// {
// path: "/WarningModel",
@ -279,7 +288,7 @@ export const publicRoutes = [
// icon: "article"
// }
// },
]
},
{
@ -342,7 +351,7 @@ export const publicRoutes = [
{
path: "/ssemanticAnalysis",
name: "semanticAnalysis",
component: () => import( "@/views/backOfficeSystem/SemanticAnalysis/index.vue"),
component: () => import("@/views/backOfficeSystem/SemanticAnalysis/index.vue"),
meta: {
title: "语义分析",
icon: "article"
@ -483,15 +492,7 @@ export const publicRoutes = [
name: "ExcavationResearch",
meta: { title: "重点人发掘系统", icon: "article" },
children: [
{
path: "/tsypHome",
name: "tsypHome",
component: () => import("@/views/backOfficeSystem/JudgmentHome/tsypHome/index"),
meta: {
title: "重点人员模型管理",
icon: "article"
}
},
{
path: "/PreliminaryExcavations",
name: "PreliminaryExcavations",
@ -548,7 +549,7 @@ export const publicRoutes = [
icon: "article"
}
},
{
path: "/situationHome",
name: "situationHome",
@ -673,12 +674,12 @@ export const publicRoutes = [
title: "经验分享",
icon: "article"
}
},
},
{
path: "/policeReport",
name: "policeReport",
component: () =>import("@/views/backOfficeSystem/policeReport/index.vue"),
component: () => import("@/views/backOfficeSystem/policeReport/index.vue"),
meta: {
title: "警情管理",
icon: "article"

61
src/utils/cookie.js Normal file
View File

@ -0,0 +1,61 @@
/*
* 1.设置cookie
* @param {string} key - cookie的名称
* @param {string} value - cookie的值
* @param {number} days - 过期天数默认7天
*/
export const setCookie = (key, value, days = 7) => {
const date = new Date();
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
const expires = `expires=${date.toGMTString()}`;
document.cookie = `${key}=${encodeURIComponent(value)}; ${expires}; path=/`;
};
/*
* 2.获取cookie
* @param {string} key - cookie的名称
* @returns {string|null} - cookie的值如果不存在则返回null
*/
export const getCookie = (key) => {
const name = `${key}=`;
const ca = document.cookie.split(';');
for (let i = 0; i < ca.length; i++) {
let c = ca[i].trim();
if (c.indexOf(name) === 0) {
return decodeURIComponent(c.substring(name.length, c.length));
}
}
return null;
};
/*
* 3.删除指定cookie
* @param {string} key - cookie的名称
*/
export const removeCookie = (key) => {
setCookie(key, '', -1);
};
/*
* 4.删除所有cookie
*/
export const removeAllCookies = () => {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i];
const eqPos = cookie.indexOf('=');
const name = eqPos > -1 ? cookie.substr(0, eqPos).trim() : '';
if (name) {
removeCookie(name);
}
}
};
/*
* 5.检查cookie是否存在
* @param {string} key - cookie的名称
* @returns {boolean} - 是否存在该cookie
*/
export const hasCookie = (key) => {
return getCookie(key) !== null;
};

View File

@ -6,9 +6,8 @@ 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
timeout: 100000,
});
// 1.请求拦截器

View File

@ -0,0 +1,107 @@
<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" v-show="title != '详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<FormMessage :formList="formData" v-model="listQuery" ref="elform" :rules="rules" :disabled="editAdd">
</FormMessage>
</div>
</div>
</template>
<script setup>
import { reactive, ref, getCurrentInstance } from 'vue'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { addEntity,editEntity } from '@/api/model.js'
import { ElMessage } from "element-plus";
const proxy = getCurrentInstance()
const props = defineProps({
dict: {
type: Array,
default: () => [],
}
})
const dialogForm = ref(false)
const emit = defineEmits(['getLits'])
// 判断是否增删改
const editAdd = ref(false)
const title = ref("新增")
const formData = ref()
const listQuery = ref({})
const elform = ref()
const rules = ref({
mxmc: [
{ required: true, message: '请输入模型名称', trigger: 'blur' },
],
mxlx: [
{ required: true, message: '请选择模型类型', trigger: 'change' },
],
})
const init = (type, row) => {
dialogForm.value = true
editAdd.value = false
formData.value = [
{ label: "模型名称", prop: "mxmc", type: "input", width: "40%" },
{
label: "模型类型", prop: "mxlx", type: "select",
width: "40%", options: props.dict.D_MXGL_MXLX
},
]
listQuery.value = { ...row }
if (type == 'edit') {
title.value = "编辑"
} else if (type == 'add') {
title.value = "新增"
} else {
editAdd.value = true
title.value = "详情"
}
}
// 表单内容
const loading = ref(false)
// 新增
const submit = () => {
elform.value.submit((data) => {
loading.value = true
if (title.value == '新增') {
addEntity(listQuery.value).then((res) => {
ElMessage.success("新增成功");
emit('getLits')
dialogForm.value = false
}).catch((err) => {
console.log(err);
}).finally(() => {
loading.value = false
});
} else {
editEntity(listQuery.value).then((res) => {
ElMessage.success("修改成功");
emit('getLits')
dialogForm.value = false
}).finally(() => {
loading.value = false
});
}
})
}
// 关闭
const close = () => {
dialogForm.value = false
}
defineExpose({
init
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,290 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="预警规则">
<el-button type="primary" size="small" @click="openAddRule('add', item)">新增</el-button>
<el-button type="primary" size="small" :disabled="ids.length == 0" @click="deleteRule(ids)">批量删除</el-button>
<el-button size="small" @click="retenHome()">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #tjName="{ row }">
<div class="flex one_text_detail" v-if="row.tj">{{ ` ${row.tj} ${row.cs}` }} </div>
</template>
<template #zz="{ row }">
<template v-if="row.zz">
<span v-for="(item, index) in jsonParse(row.zz)" :key="index">{{ item.zzmc }}
<span v-if="index < jsonParse(row.zz).length - 1"></span>
</span>
</template>
</template>
<template #sfbq="{ row }">
<template v-if="row.sfbq">
<span v-for="(item, index) in jsonParse(row.sfbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.sfbq).length - 1"></span>
</span>
</template>
</template>
<template #xwbq="{ row }">
<template v-if="row.xwbq">
<span v-for="(item, index) in jsonParse(row.xwbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.xwbq).length - 1"></span>
</span>
</template>
</template>
<template #dd="{ row }">
<template v-if="row.dd">
<span v-for="(item, index) in jsonParse(row.dd)" :key="index">{{ item.dz }}
<span v-if="index < jsonParse(row.dd).length - 1"></span>
</span>
</template>
</template>
<template #ryxx="{ row }">
<template v-if="row.ryxx">
<span v-for="(item, index) in jsonParse(row.ryxx)" :key="index">{{ item.xm }}
<span v-if="index < jsonParse(row.ryxx).length - 1"></span>
</span>
</template>
</template>
<template #jqlx="{ row }">
<template v-if="row.jqlx">
<span v-for="(item, index) in jsonParse(row.jqlx)" :key="index">{{ item.lxmc }}
<span v-if="index < jsonParse(row.jqlx).length - 1"></span>
</span>
</template>
</template>
<template #sjlx="{ row }">
<template v-if="row.sjlx">
<span v-for="(item, index) in jsonParse(row.sjlx)" :key="index">{{ item.lxmc }}
<span v-if="index < jsonParse(row.sjlx).length - 1"></span>
</span>
</template>
</template>
<template #wp="{ row }">
<template v-if="row.wp">
<span v-for="(item, index) in jsonParse(row.wp)" :key="index">{{ item.wpmc }}
<span v-if="index < jsonParse(row.wp).length - 1"></span>
</span>
</template>
</template>
<template #controls="{ row }">
<el-link type="primary" size="small" @click="yzSsyjpzMxgzxl( row.id)">运行规则</el-link>
<el-link type="primary" size="small" @click="openAddRule('edit',item, row)">修改</el-link>
<el-link type="primary" size="small" @click="openAddRule('detail',item, row)">详情</el-link>
<!-- <el-link type="primary" size="small" @click="openAddRule('detail',item, row)">预警列表</el-link> -->
<el-link type="danger" size="small" @click="deleteRule(row.id)">删除</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
</div>
<List ref="regulation" :dict="{ D_BB_AJLB,D_BZ_WPLX }" @getList="getList" />
</template>
<script setup>
import { ElMessage } from "element-plus";
import List from "../list";
import emitter from "@/utils/eventBus.js";
import { deleteYjgzpz,getYjgzpzMxgzxl,getYjgzpzPageList } from "@/api/model";
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 { reactive, ref, onMounted, getCurrentInstance } from "vue";
import { template } from "lodash";
const props = defineProps({
item: {
type: Object,
default: () => ({})
}
})
const { proxy } = getCurrentInstance();
const { D_BB_AJLB,D_BZ_WPLX} = proxy.$dict("D_BB_AJLB","D_BZ_WPLX")
const regulation = ref(null)
const queryFrom = ref({})
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{
label: "规则名称",
prop: "gzmc",
placeholder: "请输入规则名称",
showType: "input"
},
{
label: "时间",
prop: "startTime",
placeholder: "请选择时间",
showType: "daterange"
},
]);
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 300,
tableColumn: [
{ label: "规则名称", prop: "gzmc", showOverflowTooltip: true },
{ label: "开始时间", prop: "jssj", showOverflowTooltip: true },
{ label: "结束时间", prop: "kssj", showOverflowTooltip: true },
{ label: "条件", prop: "tjName", showOverflowTooltip: true, showSolt: true },
{ label: "组织", prop: "zz", showOverflowTooltip: true, showSolt: true },
{ label: "人员信息", prop: "ryxx", showOverflowTooltip: true, showSolt: true },
{ label: "警情类型", prop: "jqlx", showOverflowTooltip: true, showSolt: true },
{ label: "事件类型", prop: "sjlx", showOverflowTooltip: true, showSolt: true },
{ label: "物品", prop: "wp", showOverflowTooltip: true, showSolt: true },
{ label: "地址", prop: "dd", showOverflowTooltip: true, showSolt: true },
]
});
onMounted(() => {
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
queryFrom.value.startTime = val.startTime&&val.startTime.length > 0 ? val.startTime[0] : '';
queryFrom.value.endTime = val.startTime&&val.startTime.length > 0 ? val.startTime[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
//
// 获取列表
const getList = () => {
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
mxid:props.item.id,
}
getYjgzpzPageList(promes).then((res) => {
pageData.tableData = res.records
pageData.total = res.total
});
};
const retenHome = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
const openAddRule = (type, item, row) => {
regulation.value.init(type, item, row)
}
const ids = ref([])
const chooseData = (val) => {
ids.value = val.map(item => item.id)
}
const deleteRule = (row) => {
proxy.$confirm('是否删除该规则, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let list
if (Array.isArray(row)) {
list = ids.value
} else {
list =[row]
}
deleteYjgzpz({ids:list}).then(() => {
ElMessage.success("删除成功");
getList()
})
}).catch((err) => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
const yzSsyjpzMxgzxl = (params) => {
getYjgzpzMxgzxl({id:params}).then((res) => {
console.log(res);
})
}
const jsonParse = (val) => {
if (val) {
return JSON.parse(val)
}
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.checkbox-group {
display: flex;
gap: 20px;
}
.basic-info {
display: flex;
gap: 15px;
.avatar {
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info-list {
display: flex;
flex-direction: column;
gap: 5px;
}
}
.control-buttons {
display: flex;
gap: 10px;
}
</style>

View File

@ -0,0 +1,696 @@
<template>
<!-- 可用条件类型列表 -->
<div class="regulation-wrapper">
<div class="rule-name-section flex align-center">
<div class="rule-name-label">规则名称</div>
<el-input v-model="gzmc" :disabled="disabled" placeholder="请输入规则名称" class="search-input" clearable></el-input>
</div>
<!-- 可用条件区域 -->
<div class="condition-section">
<div class="available-conditions">
<VueDraggable class="flex-wrap" v-model="dataList" ghostClass="ghost"
:group="{ name: 'people', pull: 'clone', put: false }" :clone="clone">
<el-button v-for="item in dataList" :key="item.name" class="condition-button" size="small">
<i class="el-icon-document-add"></i>
{{ item.name }}
</el-button>
</VueDraggable>
</div>
</div>
<!-- 拖拽提示 -->
<div class="drag-hint">
<i class="el-icon-arrow-down"></i>
<span>拖拽条件到下方区域</span>
</div>
<!-- 已选条件区域 -->
<div class="selected-section">
<div class="section-title">
<i class="el-icon-check-square"></i>
<span>已选条件</span>
<span class="selected-count">{{ copyList.length }}</span>
</div>
<div class="selected-container">
<VueDraggable v-model="copyList" :group="{ name: 'people', pull: !disabled, put: !disabled }" ghostClass="ghost"
class="selected-list" itemKey="name">
<div v-for="(item, indexs) in copyList" :key="item" class="draggable-item">
<div class="item-content">
<div v-if="!disabled" class="item-remove-btn" @click="romes(item)"><el-icon :size="16">
<Close />
</el-icon></div>
<span class="item-text">{{ item.name }}{{}}</span>
</div>
<div v-if="item[item['key']]">
<template v-if="item.key == 'dd'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'cs'">
<div class="count-condition-container">
<el-select v-model="item[item['key']].tj" placeholder="请选择条件" class="condition-select">
<el-option :label="item" :value="item" v-for="(item, index) in dataConst" :key="index"></el-option>
</el-select>
<el-input-number v-model="item[item['key']].cs" :min="1" :max="1000" />
</div>
</template>
<template v-if="item.key == 'zz'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'kssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'jssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'sjlx'">
<div class="condition-input-container flex just-between">
<el-select v-model="item[item['key']]" multiple :placeholder="`请选择${item.name}`">
<el-option v-for="item in dict.D_BB_AJLB" :key="item.dm" :label="item.zdmc" :value="item.dm" />
</el-select>
</div>
</template>
<template v-if="item.key == 'wp'">
<div class="condition-input-container flex just-between">
<el-select v-model="item[item['key']]" multiple :placeholder="`请选择${item.name}`" style="width: 240px">
<el-option v-for="item in dict.D_BZ_WPLX" :key="item.dm" :label="item.zdmc" :value="item.dm" />
</el-select>
</div>
</template>
<template v-if="item.key == 'ryxx'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index].xm" :placeholder="`请输入姓名`" clearable></el-input>
</div>
<div>
<el-input v-model="item[item['key']][index].sfzh" :placeholder="`请输入身份证号`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-else-if="item.key == 'jqlx'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseMarksVisible = true" v-model="item[item['key']][index].lxmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
</div>
</div>
</VueDraggable>
<!-- 空状态提示 -->
<div v-if="copyList.length === 0" class="empty-state">
<i class="el-icon-tickets"></i>
<p>暂无已选条件</p>
<p class="empty-tip">从上方拖拽条件到此处</p>
</div>
</div>
</div>
</div>
<ChooseIdeJqlb v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import { ElMessage } from "element-plus";
import ChooseIdeJqlb from '@/components/ChooseList/ChooseIdeJqlb/index.vue'
import { VueDraggable } from 'vue-draggable-plus'//npm install vue-draggable-plus
const props = defineProps({
dict: {
type: Object,
default: () => { },
},
list: {
type: Array,
default: () => [
'Joao',
'Jean',
'Johanna',
'Juan',
],
}, defaultData: {
type: Object,
default: () => { },
}, disabled: {
type: Boolean,
default: false
}
})
const dataConst = reactive([
">",
"<",
"="
])
const gzmc = ref('')
const dataList = ref(props.list)
const copyList = ref([])
const clone = (val) => {
if (val.key == 'jqlx') {
dataList.value = dataList.value.filter(item => item.key != 'sjlx')
}
if (val.key == 'sjlx') {
dataList.value = dataList.value.filter(item => item.key != 'jqlx')
}
const data = copyList.value.find(item => item.name == val.name)
if (data) {
console.log("已存在")
} else {
switch (val.key) {
case 'cs':
return {
name: val.name,
key: val.key,
[val["key"]]: {}
}
case "wp":
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
case 'ryxx':
return {
name: val.name,
key: val.key,
[val["key"]]: [{
xm: "",
sfzh: ""
}]
}
case 'kssj':
case 'jssj':
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
case 'sjlx':
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
default:
return {
name: val.name,
key: val.key,
[val["key"]]: [""]
}
}
}
}
watch(() => props.defaultData, (val) => {
if (val) {
gzmc.value = val.gzmc
const data = props.list.map(item => {
switch (item.key) {
case 'cs':
return {
name: item.name,
key: item.key,
[item["key"]]: val.cs && val.tj ? {
cs: val.cs,
tj: val.tj
} : null
}
case 'jssj':
case 'kssj':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? val[item.key] : null,
}
case 'zz':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.zzmc) : null,
}
case 'dd':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.dz) : null,
}
default:
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]) : null
}
}
})
copyList.value = data.filter(item => item[item.key] != null)
}
}, { deep: true, immediate: true })
const addInput = (key, index) => {
if (key == 'ryxx') {
copyList.value[index][key].push({
xm: "",
sfzh: ""
})
} else {
copyList.value[index][key].push("")
}
}
// 移除项目
const removeItem = (key, index) => {
const data = copyList.value.findIndex(item => item.key == key)
if (copyList.value[data][key].length == 1) {
return
}
copyList.value[data][key].splice(index, 1)
}
const chooseMarksVisible = ref(false)
const roleIds = ref([])
const choosed = (val) => {
roleIds.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'jqlx')['jqlx'] = val.map(item => {
return {
lxmc: item.zdmc,
lxdm: item.dm
}
})
}
const romes = (val) => {
copyList.value = copyList.value.filter(item => item.key !== val.key)
if (val.key == 'jqlx' || val.key == 'sjlx') {
dataList.value = props.list
}
}
const promes = ref({})
// 新增
const retValue = () => {
if (gzmc.value == '') {
return
}
const data = copyList.value.map(item => {
return {
[item.key]: item[item.key]
}
})
promes.value = data.reduce((acc, cur) => {
return { ...acc, ...cur }
}, {})
promes.value = { ...promes.value, ...promes.value.cs, gzmc: gzmc.value }
if (promes.value.dd && promes.value.dd.length > 0) {
const dd = promes.value.dd.map(item => {
return { dz: item }
})
promes.value.dd = JSON.stringify(dd)
}
if (promes.value.zz && promes.value.zz.length > 0) {
const zz = promes.value.zz.map(item => {
return { zzmc: item }
})
promes.value.zz = JSON.stringify(zz)
}
const sjlx = copyList.value.find(item => item.key == 'sjlx')
if (sjlx) {
const data = props.dict.D_BB_AJLB.filter(item => {
if (sjlx['sjlx'].includes(item.dm)) {
return item
}
}).map(item => {
return {
lxmc: item.zdmc,
lxdm: item.dm
}
})
promes.value.sjlx = JSON.stringify(data)
}
const wplx = copyList.value.find(item => item.key == 'wp')
if (wplx) {
const data = props.dict.D_BZ_WPLX.filter(item => {
if (wplx['wp'].includes(item.dm)) {
return item
}
}).map(item => {
return {
wpmc: item.zdmc,
wpdm: item.dm
}
})
promes.value.wp = JSON.stringify(data)
}
if (promes.value.ryxx && promes.value.ryxx.length > 0) {
promes.value.ryxx = JSON.stringify(promes.value.ryxx)
}
if (promes.value.jqlx && promes.value.jqlx.length > 0) {
promes.value.jqlx = JSON.stringify(promes.value.jqlx)
}
return promes.value
}
defineExpose({
retValue
})
</script>
<style lang="scss" scoped>
.regulation-wrapper {
padding: 20px;
background: #f5f7fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
// 条件区域通用样式
.condition-section,
.selected-section {
background: white;
border-radius: 10px;
padding: 10px;
// margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.condition-section:hover,
.selected-section:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
// 区域标题
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
color: #303133;
font-weight: 600;
font-size: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e6f7ff;
i {
color: #409eff;
margin-right: 8px;
font-size: 18px;
}
.selected-count {
margin-left: 10px;
font-size: 14px;
font-weight: normal;
color: #606266;
background: #f0f9ff;
padding: 2px 8px;
border-radius: 12px;
min-width: 24px;
text-align: center;
}
}
// 可用条件区域
.available-conditions {
// min-height: 100px;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.condition-button {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 8px 16px !important;
font-size: 14px !important;
transition: all 0.3s ease !important;
min-width: 120px;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
&:hover {
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%) !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
}
i {
margin-right: 6px;
}
}
// 拖拽提示
.drag-hint {
display: flex;
align-content: flex-start;
// align-items: center;
justify-content: center;
padding: 20px;
color: #909399;
font-size: 14px;
i {
margin-right: 8px;
font-size: 16px;
animation: bounce 1.5s infinite;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
}
// 已选条件区域
.selected-container {
min-height: 120px;
border: 2px dashed #dcdfe6;
border-radius: 8px;
padding: 20px;
transition: all 0.3s ease;
background-color: #dcdfe670;
&:hover {
border-color: #409eff;
background: #f0f9ff;
}
}
.selected-list {
display: flex;
min-height: 100px;
width: 100%;
flex-wrap: wrap;
}
// 拖拽项样式
.draggable-item {
position: relative;
padding: 3px;
margin: 8px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: table-cell;
justify-content: space-between;
text-align: center;
flex-wrap: wrap;
&:hover {
transform: translateY(-2px) scale(1.02);
box-shadow: 0 6px 16px rgba(103, 194, 58, 0.4);
}
&.ghost {
opacity: 0.6;
transform: rotate(5deg);
}
}
.item-content {
background: white;
border-radius: 8px;
padding: 20px 12px 12px 12px;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
position: relative;
}
.item-text {
font-size: 14px;
color: #303133;
font-weight: 500;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.item-remove {
color: #c0c4cc;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
padding: 4px;
border-radius: 50%;
&:hover {
color: #f56c6c;
background: #fef0f0;
transform: rotate(90deg);
}
}
/* 规则名称区域 */
.rule-name-section {
margin-bottom: 10px;
}
.rule-name-label {
width: 100px;
}
/* 项目删除按钮 */
.item-remove-btn {
position: absolute;
top: 5px;
right: 10px;
}
/* 条件输入容器 */
.condition-input-container {
flex-wrap: nowrap;
margin-top: 10px;
}
/* 计数条件容器 */
.count-condition-container {
margin-top: 10px;
display: flex;
}
/* 条件选择框 */
.condition-select {
width: 100px;
}
/* 按钮右侧边距 */
.btn-margin-right {
margin-right: 5px;
}
// 空状态样式
.empty-state {
text-align: center;
padding: 40px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
transition: color 0.3s ease;
}
p {
margin: 0;
font-size: 14px;
}
.empty-tip {
font-size: 12px;
color: #c0c4cc;
margin-top: 8px;
}
&:hover i {
color: #409eff;
}
}
// 拖拽效果
.ghost {
opacity: 0.6;
background-color: #e6f7ff;
border: 2px dashed #409eff;
border-radius: 8px;
}
// 响应式设计
@media (max-width: 768px) {
.regulation-wrapper {
padding: 15px;
}
.condition-section,
.selected-section {
padding: 15px;
}
.condition-button {
min-width: 100px;
font-size: 13px !important;
}
.item-content {
min-width: 120px;
padding: 10px 12px;
}
}
:v-deep .el-select {
width: 59%;
}
</style>

View File

@ -0,0 +1,257 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="四色预警规则">
<el-button type="primary" size="small" @click="openAddRule('add', item)">新增</el-button>
<el-button type="primary" size="small" :disabled="ids.length == 0" @click="deleteRule(ids)">批量删除</el-button>
<el-button size="small" @click="retenHome()">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<!-- <template #tjName="{ row }">
<div class="flex one_text_detail">{{ ` ${row.tj} ${row.cs}` }} </div>
</template> -->
<!-- <template #fxDj="{ row }">
<DictTag :tag="false" :value="row.fxDj" :options="D_GS_RQFJ_FXDJ"/>
</template> -->
<template #zz="{ row }">
<template v-if="row.zz">
<span v-for="(item, index) in jsonParse(row.zz)" :key="index">{{ item.zzmc }}
<span v-if="index < jsonParse(row.zz).length - 1"></span>
</span>
</template>
</template>
<template #sfbq="{ row }">
<template v-if="row.sfbq">
<span v-for="(item, index) in jsonParse(row.sfbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.sfbq).length - 1"></span>
</span>
</template>
</template>
<template #xwbq="{ row }">
<template v-if="row.xwbq">
<span v-for="(item, index) in jsonParse(row.xwbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.xwbq).length - 1"></span>
</span>
</template>
</template>
<template #dd="{ row }">
<template v-if="row.dd">
<span v-for="(item, index) in jsonParse(row.dd)" :key="index">{{ item.dz }}
<span v-if="index < jsonParse(row.dd).length - 1"></span>
</span>
</template>
</template>
<template #controls="{ row }">
<el-link type="primary" size="small" @click="yzSsyjpzMxgzxl( row.id)">运行规则</el-link>
<el-link type="primary" size="small" @click="openAddRule('edit',item, row)">修改</el-link>
<el-link type="primary" size="small" @click="openAddRule('detail',item, row)">详情</el-link>
<!-- <el-link type="primary" size="small" @click="openAddRule('detail',item, row)">预警列表</el-link> -->
<el-link type="danger" size="small" @click="deleteRule(row.id)">删除</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
</div>
<List ref="regulation" :dict="{ D_BZ_RYBQ }" @getList="getList" />
</template>
<script setup>
import { ElMessage } from "element-plus";
import List from "../list";
import emitter from "@/utils/eventBus.js";
import { getSsyjpzPageList, deleteSsyjpz,getSsyjpzMxgzxl } from "@/api/model";
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 { reactive, ref, onMounted, getCurrentInstance } from "vue";
import { template } from "lodash";
const props = defineProps({
item: {
type: Object,
default: () => ({})
}
})
const { proxy } = getCurrentInstance();
const { D_BZ_RYBQ } = proxy.$dict("D_BZ_RYBQ")
const regulation = ref(null)
const queryFrom = ref({})
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{
label: "规则名称",
prop: "gzmc",
placeholder: "请输入规则名称",
showType: "input"
},
{
label: "时间",
prop: "startTime",
placeholder: "请选择时间",
showType: "daterange"
},
]);
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 300,
tableColumn: [
{ label: "规则名称", prop: "gzmc", showOverflowTooltip: true },
{ label: "开始时间", prop: "jssj", showOverflowTooltip: true },
{ label: "结束时间", prop: "kssj", showOverflowTooltip: true },
// { label: "条件", prop: "tjName", showOverflowTooltip: true, showSolt: true },
{ label: "组织", prop: "zz", showOverflowTooltip: true, showSolt: true },
{ label: "身份标签", prop: "sfbq", showOverflowTooltip: true, showSolt: true },
{ label: "行为标签", prop: "xwbq", showOverflowTooltip: true, showSolt: true },
{ label: "地址", prop: "dd", showOverflowTooltip: true, showSolt: true },
]
});
onMounted(() => {
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value.startTime = val.startTime&&val.startTime.length > 0 ? val.startTime[0] : '';
queryFrom.value.endTime = val.startTime&&val.startTime.length > 0 ? val.startTime[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
//
// 获取列表
const getList = () => {
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
mxid:props.item.id
}
getSsyjpzPageList(promes).then((res) => {
pageData.tableData = res.records
pageData.total = res.total
});
};
const retenHome = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
const openAddRule = (type, item, row) => {
regulation.value.init(type, item, row)
}
const ids = ref([])
const chooseData = (val) => {
ids.value = val.map(item => item.id)
}
const deleteRule = (row) => {
proxy.$confirm('是否删除该规则, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let list
if (Array.isArray(row)) {
list = ids.value
} else {
list =[row]
}
deleteSsyjpz({ids:list}).then(() => {
ElMessage.success("删除成功");
getList()
})
}).catch((err) => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
const yzSsyjpzMxgzxl = (params) => {
getSsyjpzMxgzxl({id:params}).then((res) => {
console.log(res);
})
}
const jsonParse = (val) => {
if (val) {
return JSON.parse(val)
}
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.checkbox-group {
display: flex;
gap: 20px;
}
.basic-info {
display: flex;
gap: 15px;
.avatar {
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info-list {
display: flex;
flex-direction: column;
gap: 5px;
}
}
.control-buttons {
display: flex;
gap: 10px;
}
</style>

View File

@ -0,0 +1,638 @@
<template>
<!-- 可用条件类型列表 -->
<div class="regulation-wrapper">
<div class="rule-name-section flex align-center">
<div class="rule-name-label">规则名称</div>
<el-input v-model="gzmc" :disabled="disabled" placeholder="请输入规则名称" class="search-input" clearable></el-input>
</div>
<!-- 可用条件区域 -->
<div class="condition-section">
<div class="available-conditions">
<VueDraggable class="flex-wrap" v-model="dataList" ghostClass="ghost"
:group="{ name: 'people', pull: 'clone', put: false }" :clone="clone">
<el-button v-for="item in dataList" :key="item.name" class="condition-button" size="small">
<i class="el-icon-document-add"></i>
{{ item.name }}
</el-button>
</VueDraggable>
</div>
</div>
<!-- 拖拽提示 -->
<div class="drag-hint">
<i class="el-icon-arrow-down"></i>
<span>拖拽条件到下方区域</span>
</div>
<!-- 已选条件区域 -->
<div class="selected-section">
<div class="section-title">
<i class="el-icon-check-square"></i>
<span>已选条件</span>
<span class="selected-count">{{ copyList.length }}</span>
</div>
<div class="selected-container">
<VueDraggable v-model="copyList" :group="{ name: 'people', pull: !disabled, put: !disabled }" ghostClass="ghost"
class="selected-list" itemKey="name">
<div v-for="(item, indexs) in copyList" :key="item" class="draggable-item">
<div class="item-content">
<div v-if="!disabled" class="item-remove-btn" @click="romes(item)"><el-icon :size="16">
<Close />
</el-icon></div>
<span class="item-text">{{ item.name }}</span>
</div>
<div v-if="item[item['key']]">
<template v-if="item.key == 'dd'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-else-if="item.key == 'sfbq'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseIdentityVisible = true" v-model="item[item['key']][index].bqmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
<!-- <template v-if="item.key == 'cs'">
<div class="count-condition-container">
<el-select v-model="item[item['key']].tj" placeholder="请选择条件" class="condition-select">
<el-option :label="item" :value="item" v-for="(item, index) in dataConst" :key="index"></el-option>
</el-select>
<el-input-number v-model="item[item['key']].cs" :min="1" :max="1000" />
</div>
</template> -->
<template v-if="item.key == 'xwbq'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseMarksVisible = true" v-model="item[item['key']][index].bqmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'zz'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'kssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'jssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
</div>
</div>
</VueDraggable>
<!-- 空状态提示 -->
<div v-if="copyList.length === 0" class="empty-state">
<i class="el-icon-tickets"></i>
<p>暂无已选条件</p>
<p class="empty-tip">从上方拖拽条件到此处</p>
</div>
</div>
</div>
</div>
<ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
<ChooseIdentity v-model="chooseIdentityVisible" @choosed="choosedIdentity" :roleIds="roleIdsIdentity" />
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
import ChooseIdentity from "@/components/ChooseList/ChooseIdentity/index.vue";
import { ElMessage } from "element-plus";
import { VueDraggable } from 'vue-draggable-plus'//npm install vue-draggable-plus
const props = defineProps({
dict: {
type: Array,
default: () => [],
},
list: {
type: Array,
default: () => [
'Joao',
'Jean',
'Johanna',
'Juan',
],
}, defaultData: {
type: Object,
default: () => { },
}, disabled: {
type: Boolean,
default: false
}
})
const dataConst = reactive([
">",
"<",
"="
])
const gzmc = ref('')
const dataList = ref(props.list)
const copyList = ref([])
const clone = (val) => {
const data = copyList.value.find(item => item.name == val.name)
if (data) {
console.log("已存在")
} else {
// if (val.key == 'cs') {
// return {
// name: val.name,
// key: val.key,
// [val["key"]]: {}
// }
// } else {
if (val.key == 'cs') {
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
} else {
return {
name: val.name,
key: val.key,
[val["key"]]: [""]
}
}
}
}
watch(() => props.defaultData, (val) => {
if (val) {
gzmc.value = val.gzmc
const data = props.list.map(item => {
switch (item.key) {
// case 'cs':
// return {
// name: item.name,
// key: item.key,
// [item["key"]]: {
// cs: val.cs,
// tj: val.tj
// }
// }
case 'jssj':
case 'kssj':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? val[item.key] : null,
}
case 'zz':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.zzmc) : null,
}
case 'dd':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.dz) : null,
}
default:
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]) : null
}
}
})
copyList.value = data.filter(item => {
return item[item.key] != null
})
}
}, { deep: true, immediate: true })
const addInput = (key, index) => {
copyList.value[index][key].push("")
}
// 移除项目
const removeItem = (key, index) => {
const data = copyList.value.findIndex(item => item.key == key)
if (copyList.value[data][key].length == 1) {
return
}
copyList.value[data][key].splice(index, 1)
}
// 选择预警标签
const roleIds = ref([])
const chooseMarksVisible = ref()
const choosed = (val) => {
roleIds.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'xwbq')['xwbq'] = val.map(item => {
return {
bqdm: item.bqDm,
bqmc: item.bqMc
}
})
}
// 选择身份标签
const chooseIdentityVisible = ref()
const roleIdsIdentity = ref([])
const choosedIdentity = (val) => {
roleIdsIdentity.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'sfbq')['sfbq'] = val.map(item => {
return {
bqdm: item.bqDm,
bqmc: item.bqMc
}
})
}
const romes = (val) => {
copyList.value = copyList.value.filter(item => item.key !== val.key)
}
const promes = ref({})
// 新增
const retValue = () => {
if (gzmc.value == '') {
return
}
const data = copyList.value.map(item => {
return {
[item.key]: item[item.key]
}
})
promes.value = data.reduce((acc, cur) => {
console.log(cur);
return { ...acc, ...cur }
}, {})
promes.value = { ...promes.value, gzmc: gzmc.value }
if (promes.value.dd && promes.value.dd.length > 0) {
promes.value.dd = promes.value.dd.map(item => {
return { dz: item }
})
}
if (promes.value.zz && promes.value.zz.length > 0) {
promes.value.zz = promes.value.zz.map(item => {
return { zzmc: item }
})
}
promes.value.kssj = promes.value.kssj ? promes.value.kssj.toString() : null
promes.value.jssj = promes.value.jssj ? promes.value.jssj.toString() : null
const retData = {
...promes.value,
dd: promes.value.dd ? JSON.stringify(promes.value.dd) : null,
sfbq: promes.value.sfbq ? JSON.stringify(promes.value.sfbq) :null,
xwbq: promes.value.xwbq ? JSON.stringify(promes.value.xwbq) :null,
zz: promes.value.zz ? JSON.stringify(promes.value.zz) :null,
}
return retData
}
defineExpose({
retValue
})
</script>
<style lang="scss" scoped>
.regulation-wrapper {
padding: 20px;
background: #f5f7fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
// 条件区域通用样式
.condition-section,
.selected-section {
background: white;
border-radius: 10px;
padding: 10px;
// margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.condition-section:hover,
.selected-section:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
// 区域标题
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
color: #303133;
font-weight: 600;
font-size: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e6f7ff;
i {
color: #409eff;
margin-right: 8px;
font-size: 18px;
}
.selected-count {
margin-left: 10px;
font-size: 14px;
font-weight: normal;
color: #606266;
background: #f0f9ff;
padding: 2px 8px;
border-radius: 12px;
min-width: 24px;
text-align: center;
}
}
// 可用条件区域
.available-conditions {
// min-height: 100px;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.condition-button {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 8px 16px !important;
font-size: 14px !important;
transition: all 0.3s ease !important;
min-width: 120px;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
&:hover {
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%) !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
}
i {
margin-right: 6px;
}
}
// 拖拽提示
.drag-hint {
display: flex;
align-content: flex-start;
// align-items: center;
justify-content: center;
padding: 20px;
color: #909399;
font-size: 14px;
i {
margin-right: 8px;
font-size: 16px;
animation: bounce 1.5s infinite;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
}
// 已选条件区域
.selected-container {
min-height: 120px;
border: 2px dashed #dcdfe6;
border-radius: 8px;
padding: 20px;
transition: all 0.3s ease;
background-color: #dcdfe670;
&:hover {
border-color: #409eff;
background: #f0f9ff;
}
}
.selected-list {
min-height: 100px;
}
// 拖拽项样式
.draggable-item {
position: relative;
// background: rgba(103, 194, 58, 0.3);
padding: 3px;
margin: 8px;
// box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: table-cell;
justify-content: space-between;
// cursor: move;
text-align: center;
&:hover {
transform: translateY(-2px) scale(1.02);
box-shadow: 0 6px 16px rgba(103, 194, 58, 0.4);
}
&.ghost {
opacity: 0.6;
transform: rotate(5deg);
}
}
.item-content {
background: white;
border-radius: 8px;
padding: 20px 12px 12px 12px;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
position: relative;
}
.item-text {
font-size: 14px;
color: #303133;
font-weight: 500;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.item-remove {
color: #c0c4cc;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
padding: 4px;
border-radius: 50%;
&:hover {
color: #f56c6c;
background: #fef0f0;
transform: rotate(90deg);
}
}
/* 规则名称区域 */
.rule-name-section {
margin-bottom: 10px;
}
.rule-name-label {
width: 100px;
}
/* 项目删除按钮 */
.item-remove-btn {
position: absolute;
top: 5px;
right: 10px;
}
/* 条件输入容器 */
.condition-input-container {
flex-wrap: nowrap;
margin-top: 10px;
}
/* 计数条件容器 */
.count-condition-container {
margin-top: 10px;
display: flex;
}
/* 条件选择框 */
.condition-select {
width: 100px;
}
/* 按钮右侧边距 */
.btn-margin-right {
margin-right: 5px;
}
// 空状态样式
.empty-state {
text-align: center;
padding: 40px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
transition: color 0.3s ease;
}
p {
margin: 0;
font-size: 14px;
}
.empty-tip {
font-size: 12px;
color: #c0c4cc;
margin-top: 8px;
}
&:hover i {
color: #409eff;
}
}
// 拖拽效果
.ghost {
opacity: 0.6;
background-color: #e6f7ff;
border: 2px dashed #409eff;
border-radius: 8px;
}
// 响应式设计
@media (max-width: 768px) {
.regulation-wrapper {
padding: 15px;
}
.condition-section,
.selected-section {
padding: 15px;
}
.condition-button {
min-width: 100px;
font-size: 13px !important;
}
.item-content {
min-width: 120px;
padding: 10px 12px;
}
}
:v-deep .el-select {
width: 59%;
}
</style>

View File

@ -1,37 +0,0 @@
<template>
<div>
<YpHome v-if="showModel == '研判首页'" @change="changeModel"></YpHome>
<YjList v-if="showModel == '态势预警列表'" :item="itemYj" @change="changeModel"></YjList>
<YjDetail v-if="showModel == '预警详情'" :item="itemDetail" @change="changeModel"></YjDetail>
</div>
</template>
<script setup>
import YpHome from "./components/ypHome.vue";
import YjList from "./components/yjList.vue";
import YjDetail from "./components/yjDetail.vue";
import { onMounted, ref } from "vue";
const showModel = ref('研判首页')
const itemYj = ref({})
const itemDetail = ref({})
onMounted(()=>{
// route.query.id ? lookDeatl(route.query.id): getLits();
})
function changeModel(val){
showModel.value = val.type ;
if(val.data){
if(val.type == '态势预警列表'){
itemYj.value = val.data
}else if(val.type == '预警详情'){
itemDetail.value = val.data
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,234 @@
<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" v-show="title != '详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<EarlyWarning :list="listData" v-if=" listQuery.mxlx=='01'" ref="regulationRef" :dict="props.dict" :defaultData="defaultData"
:disabled="title == '详情'" />
<Regulation :list="listData" v-if=" listQuery.mxlx=='02'" ref="regulationRef" :dict="props.dict" :defaultData="defaultData"
:disabled="title == '详情'" />
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import { ElMessage } from "element-plus";
import { addSsyjpz, editSsyjpz,addYjgzpz,editYjgzpz } from '@/api/model'
import Regulation from "../components/FourColor/regulation.vue";
import EarlyWarning from "../components/EarlyWarning/regulation.vue";
const props = defineProps({
dict: {
type: Array,
default: () => [],
}
})
const dialogForm = ref(false)
const title = ref("新增")
const emit = defineEmits(['getList'])
const typeData = {
'02': [{
name: "地点",
key: "dd",
id: 1
}, {
name: "身份标签",
key: "sfbq",
id: 2
},
// {
// name: "次数",
// key: "cs",
// id: 3
// },
{
name: "行为标签",
key: "xwbq",
id: 4
}, {
name: "组织",
key: "zz",
id: 5
}, {
name: "开始时间",
key: "kssj",
id: 6
}, {
name: "结束时间",
key: "jssj",
id: 7
}],
'01': [{
name: "地点",
key: "dd",
}, {
name: '警情类型',
key: 'jqlx',
}, {
name: '人员信息',
key: 'ryxx',
}, {
name: '事件类型',
key: 'sjlx',
}, {
name: '物品',
key: 'wp',
}, {
name: '组织',
key: 'zz',
}, {
name: '开始时间',
key: 'kssj',
}, {
name: '结束时间',
key: 'jssj',
}, {
name: '次数',
key: 'cs',
}],
}
const listData = ref([])
const listQuery = ref()
const defaultData = ref({})
const mxlx=ref()
const init = (type, item, row) => {
dialogForm.value = true
listQuery.value = item
listData.value = typeData[item.mxlx]
if (type == 'edit') {
defaultData.value = row
title.value = "编辑"
} else if (type == 'add') {
defaultData.value={}
title.value = "新增"
} else {
title.value = "详情"
defaultData.value = row
}
}
const regulationRef = ref(null)
const loading = ref(false)
// 新增
const submit = () => {
switch (listQuery.value.mxlx) {
case '01':
addYjgzpzs()
break;
case '02':
addSsyj()
break;
default:
break;
}
}
const addSsyj = () => {
const data = regulationRef.value.retValue()
if (!data||!data.gzmc) {
ElMessage.warning('请填写规则名称')
return
}
if (title.value == "新增") {
const promes = {
mxid: listQuery.value.id,
...data
}
addSsyjpz(promes).then((result) => {
ElMessage.success('新增成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
} else {
editSsyjpz({
id: defaultData.value.id,
...data
}).then((result) => {
ElMessage.success('编辑成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
}
}
const addYjgzpzs = () => {
const data = regulationRef.value.retValue()
if (!data||!data.gzmc) {
ElMessage.warning('请填写规则名称')
return
}
if (title.value == "新增") {
const promes = {
mxid: listQuery.value.id,
...data
}
addYjgzpz(promes).then((result) => {
ElMessage.success('新增成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
} else {
editYjgzpz({
id: defaultData.value.id,
...data
}).then((result) => {
ElMessage.success('编辑成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
}
}
const close = () => {
dialogForm.value = false
}
defineExpose({
init,
})
</script>
<style lang="scss" scoped>
::v-deep .el-button+.el-button {
margin-left: 0px;
}
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.just-between {
justify-content: space-between;
}
.mb-10 {
margin-bottom: 10px;
}
.mr-10 {
margin-right: 10px;
}
</style>

View File

@ -1,88 +0,0 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<div>详情</div>
<div><el-button @click="close">关闭</el-button></div>
</div>
<div class="form_cnt">
<FormMessage v-model="listQuery" disabled :formList="formData" ref="elform" />
</div>
</div>
</template>
<script setup>
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { qcckGet } from "@/api/qcckApi.js";
import { ref, defineExpose, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const { JQCLJG,JQLB,D_BZ_JQLY,JQLX,JQXL ,JQZL} = proxy.$dict( 'JQCLJG',"JQLB","D_BZ_JQLY","JQLX",'JQXL','JQZL' ); //获取字典数据
const dialogForm = ref(false); //弹窗
const formData = ref([
{ label: "报警电话", prop: "bjdh", type: "input" },
{ label: "报警地址", prop: "bjdz", type: "input" },
{ label: "报警内容", prop: "bjnr", type: "input" },
{ label: "报警人名称", prop: "bjrmc", type: "input" },
{ label: "报警人证件号码", prop: "bjrzjhm", type: "input" },
{ label: "报警时间", prop: "bjsj", type: "input" },
{ label: "接警完成时间", prop: "jjwcsj", type: "input" },
{ label: "警情子类", prop: "jqzldm", type: "select", options: JQZL },
{ label: "警情细类", prop: "jqxldm", type: "select", options: JQXL },
{ label: "警情类型", prop: "jqlxdm", type: "select",options: JQLX },
{ label: "警情来源", prop: "jqlyfs", type: "select",options: D_BZ_JQLY },
{ label: "警情类别", prop: "jqlbdm", type: "select", options: JQLB },
{ label: "警情处理状态", prop: "jqclztdm", type: "select",options: JQCLJG },
]);
const listQuery = ref({}); //表单
const elform = ref();
onMounted(() => {
});
// 初始化数据
const init = (row) => {
dialogForm.value = true;
qcckGet({}, `/mosty-gsxt/jjdbYp/getInfo/${row.id}`).then(res => {
listQuery.value = res;
}).catch(() => {
})
};
// 关闭
const close = () => {
listQuery.value = {};
dialogForm.value = false;
};
defineExpose({ init });
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
::v-deep .el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
color: #0072ff;
background: rgba(0, 114, 255, 0.3);
}
.boxlist {
width: 99%;
height: 225px;
margin-top: 10px;
overflow: hidden;
}
::v-deep .avatar-uploader {
display: flex;
align-items: center;
}
::v-deep .el-upload-list {
margin-left: 20px;
display: flex;
align-items: center;
}
::v-deep .el-upload-list__item-name .el-icon {
top: 3px;
}
</style>

View File

@ -1,135 +0,0 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="查看详情">
<el-button size="small" @click="goback">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"></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 #jqlbdm="{ row }">
<DictTag :tag="false" :value="row.jqlbdm" :options="JQLB" />
</template>
<template #controls="{ row }">
<el-link type="primary" @click="addEdit( row)">详情</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{ ...pageData.pageConfiger, total: pageData.total }"></Pages>
</div>
</div>
<Particulars ref="particulars" />
</template>
<script setup>
import Particulars from "./particulars.vue";
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 { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref,defineProps, onMounted, defineEmits,getCurrentInstance } from "vue";
const props = defineProps({
item: {
type: Object,
default: {}
}
})
const { proxy } = getCurrentInstance();
const { JQLB } = proxy.$dict( "JQLB" ); //获取字典数据
const emit = defineEmits(['change']);
const particulars = ref()
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{ label: "研判名称", prop: 'ypmc', placeholder: "请输入研判名称", showType: "input" },
]);
const queryFrom = 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: "ypmc" },
{ label: "报警时间", prop: "bjsj" },
{ label: "报警地址", prop: "bjdz" },
{ label: "警情类型", prop: "jqlbdm",showSolt:true },
{ label: "报警内容", prop: "bjnr", showOverflowTooltip: true },
{ label: "报警电话", prop: "bjdh" },
{ label: "报警时间", prop: "bjsj" },
]
});
onMounted(() => {
tabHeightFn();
getList();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...queryFrom.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;
let data = {
yjid:props.item.id,
...queryFrom.value,
pageCurrent: pageData.pageConfiger.pageCurrent,
pageSize: pageData.pageConfiger.pageSize
}
qcckPost(data, '/mosty-gsxt/jjdbYp/getPageList').then(res => {
pageData.tableData = res.records;
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch(() => {
pageData.tableConfiger.loading = false;
});
};
const addEdit = (row) => {
particulars.value.init(row)
}
const goback = () => {
emit('change', { type: '态势预警列表', data: null })
}
// 表格高度计算
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,328 +1,273 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="态势预警列表">
<el-button size="small" @click="goback">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"></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 #jqlbdm="{ row }">
<DictTag :tag="false" :value="row.jqlbdm" :options="JQLB" />
</template>
<template #jqzldm="{ row }">
<DictTag :tag="false" :value="row.jqzldm" :options="JQZL" />
</template>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" @click="viewDetails(row)">详情</el-link>
<el-link type="primary" @click="generateReport(row.id)">研判报告</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<div>
<div class="titleBox">
<PageTitle title="预警列表">
<el-button type="primary" size="small" @click="openAddRule('add', item)">新增</el-button>
<el-button type="primary" size="small" :disabled="ids.length == 0" @click="deleteRule(ids)">批量删除</el-button>
<el-button size="small" @click="retenHome()">返回</el-button>
</PageTitle>
</div>
<YjDetail ref="yjDetail"></YjDetail>
<YpModel v-model="showModel" @SaveReport="SaveReport" :heightNumber="436" v-model:textContent="textContent"></YpModel>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #tjName="{ row }">
<div class="flex one_text_detail" v-if="row.tj">{{ ` ${row.tj} ${row.cs}` }} </div>
</template>
<template #zz="{ row }">
<template v-if="row.zz">
<span v-for="(item, index) in jsonParse(row.zz)" :key="index">{{ item.zzmc }}
<span v-if="index < jsonParse(row.zz).length - 1"></span>
</span>
</template>
</template>
<template #sfbq="{ row }">
<template v-if="row.sfbq">
<span v-for="(item, index) in jsonParse(row.sfbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.sfbq).length - 1"></span>
</span>
</template>
</template>
<template #xwbq="{ row }">
<template v-if="row.xwbq">
<span v-for="(item, index) in jsonParse(row.xwbq)" :key="index">{{ item.bqmc }}
<span v-if="index < jsonParse(row.xwbq).length - 1"></span>
</span>
</template>
</template>
<template #dd="{ row }">
<template v-if="row.dd">
<span v-for="(item, index) in jsonParse(row.dd)" :key="index">{{ item.dz }}
<span v-if="index < jsonParse(row.dd).length - 1"></span>
</span>
</template>
</template>
<template #ryxx="{ row }">
<template v-if="row.ryxx">
<span v-for="(item, index) in jsonParse(row.ryxx)" :key="index">{{ item.xm }}
<span v-if="index < jsonParse(row.ryxx).length - 1"></span>
</span>
</template>
</template>
<template #jqlx="{ row }">
<template v-if="row.jqlx">
<span v-for="(item, index) in jsonParse(row.jqlx)" :key="index">{{ item.lxmc }}
<span v-if="index < jsonParse(row.jqlx).length - 1"></span>
</span>
</template>
</template>
<template #sjlx="{ row }">
<template v-if="row.sjlx">
<span v-for="(item, index) in jsonParse(row.sjlx)" :key="index">{{ item.lxmc }}
<span v-if="index < jsonParse(row.sjlx).length - 1"></span>
</span>
</template>
</template>
<template #wp="{ row }">
<template v-if="row.wp">
<span v-for="(item, index) in jsonParse(row.wp)" :key="index">{{ item.wpmc }}
<span v-if="index < jsonParse(row.wp).length - 1"></span>
</span>
</template>
</template>
<template #controls="{ row }">
<el-link type="primary" size="small" @click="yzSsyjpzMxgzxl( row.id)">运行规则</el-link>
<el-link type="primary" size="small" @click="openAddRule('edit',item, row)">修改</el-link>
<el-link type="primary" size="small" @click="openAddRule('detail',item, row)">详情</el-link>
<!-- <el-link type="primary" size="small" @click="openAddRule('detail',item, row)">预警列表</el-link> -->
<el-link type="danger" size="small" @click="deleteRule(row.id)">删除</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
</div>
</template>
<script setup>
import { timeValidate } from '@/utils/tools.js'
import YpModel from '@/components/ypModel/index.vue'
import { getItem } from '@/utils/storage.js'
import YjDetail from './yjDetail.vue'
import { ElMessage } from "element-plus";
import emitter from "@/utils/eventBus.js";
import { deleteYjgzpz,getYjgzpzMxgzxl,getYjxxPageList } from "@/api/model";
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 { jqypDywdtj, jqypfxbgJqlxtj, jqypfxbgYdfx, jqypfxbgJqlytj, jqypfxbgTj, jqypfxbgCljgf, jqypfxbgCzlfx, getDictItem } from '@/api/semanticAnalysis'
import { textStyle, Firstlevelheading, Subheading, BiheadlinegTitle, BigTitle, headTitle, report, signature } from './content.js'
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted,defineProps, getCurrentInstance, defineEmits } from "vue";
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
import { template } from "lodash";
const props = defineProps({
item: {
type: Object,
default: {}
}
item: {
type: Object,
default: () => ({})
}
})
const showModel = ref(false)
const sortingRatioValue = ref({})
const textContent = ref('');
const emit = defineEmits(['change']);
const { proxy } = getCurrentInstance();
const { JQLB,JQZL} = proxy.$dict( "JQLB",'JQZL' ); //获取字典数据
const { D_BB_AJLB,D_BZ_WPLX} = proxy.$dict("D_BB_AJLB","D_BZ_WPLX")
const regulation = ref(null)
const queryFrom = ref({})
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{
label: "预警名称",
prop: "yjMc",
placeholder: "预警名称",
showType: "input"
},
{
label: "预警时间",
prop: "timeRange",
placeholder: "预警时间",
showType: "datetimerange"
}
{
label: "时间",
prop: "startTime",
placeholder: "请选择时间",
showType: "daterange"
},
]);
const yjDetail = ref();
const queryFrom = 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: "ypmc" },
{ label: "预警时间", prop: "yjsj" },
{ label: "预警名称大类", prop: "jqlbdm" ,showSolt: true },
{ label: "预警名称细类", prop: "jqzldm" ,showSolt: true}
]
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 300,
tableColumn: [
{ label: "预警时间", prop: "gzmc", showOverflowTooltip: true },
{ label: "类型", prop: "jssj", showOverflowTooltip: true, showSolt: true },
{ label: "内容", prop: "kssj", showOverflowTooltip: true, showSolt: true },
]
});
const timeDate = ref()
const endYears = ref()
onMounted(() => {
tabHeightFn();
getList();
Time()
getList();
tabHeightFn();
});
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');
timeDate.value = `${endYear}${endMonth}${endDay}`
endYears.value = year
return `${year}${month}${day}日 至${endYear}${endMonth}${endDay}`
}
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...queryFrom.value,...val };
queryFrom.value.startTime = val.timeRange ? val.timeRange[0] : '';
queryFrom.value.endTime = val.timeRange ? val.timeRange[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
queryFrom.value.startTime = val.startTime&&val.startTime.length > 0 ? val.startTime[0] : '';
queryFrom.value.endTime = val.startTime&&val.startTime.length > 0 ? val.startTime[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList();
pageData.pageConfiger.pageCurrent = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
pageData.pageConfiger.pageSize = val;
getList();
};
//
// 获取列表
const getList = () => {
pageData.tableConfiger.loading = true;
let data = {
yjid:props.item.id,
...queryFrom.value,
pageCurrent: pageData.pageConfiger.pageCurrent,
pageSize: pageData.pageConfiger.pageSize
}
delete data.timeRange;
qcckPost(data, "/mosty-gsxt/jjdbYp/yjPageList").then((res) => {
pageData.tableData = res.records;
pageData.total = res.total;
pageData.tableConfiger.loading = false;
}).catch(() => {
pageData.tableConfiger.loading = false;
});
};
// 查看详情
const viewDetails = (row) => {
emit('change', { type: '预警详情', data: row })
};
// 生成研判报告
const generateReport = (val) => {
const dev = getItem('deptId')[0]
sortingRatioValue.value = {}
textContent.value = BigTitle(`${endYears.value}年度西藏公安执法数据分析`) + headTitle({
orgName: dev.deptName,
serialNumber: timeValidate("", "mm"),
time: timeValidate(),
})
const data = `为全面、客观、准确掌握全区公安机关的执法状况,自治区公安厅基于数据统计,对全区公安机关${endYears.value}年度的执法状况作了客观分析。`
textContent.value += BiheadlinegTitle('1.接处预警况') + textStyle(data) + Firstlevelheading('一、执法状况总体分析')
getfxbgYdfx(val)
getfxbgTj(val)
getfxbgJqlxtj(val)
getfxbgJqlytj(val)
getfxbgDywdtj(val)
getfxgbCljgf(val)
getfxgbCzlfx(val)
showModel.value = true;
};
//分析报告-时间维度-月分析
const getfxbgYdfx = (val) => {
jqypfxbgYdfx({ yjid: val }).then(res => {
const model = sortingRatio(res)
const data = `我们将所有预警按照月份划分进行统计发现,每月预警分布较为平均。最高月份为${model[0].month}月,占到${model[0].number};最低月份为${model[res.length - 1].month}月,占到${model[res.length - 1].number}。考虑是因为${model[0].month}月为我区传统旅游旺季,进藏人员较多。 ${model[res.length - 1].month}月一般春节及藏历新年期间,在藏人员较少。`
sortingRatioValue.value.ydfx = Subheading('1.1.4时间维度') + textStyle(data)
})
}
const getfxbgTj = (val) => {
jqypfxbgTj({ yjid: val }).then(res => {
const data = `${Time()} ,全区公安机关共接报各类预警${res.total}起,同比上升 ${res.tbbsb}%,同比上升${res.hbbsb}%`
textContent.value += BiheadlinegTitle('1.1接报预警') + textStyle(data)
dataList.XsfxTj = res
})
}
// 预警类型统计
const getfxbgJqlxtj = (val) => {
let params = {
...pageData.parameter,
yjid: val
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
mxid:props.item.id,
}
jqypfxbgJqlxtj(params).then(res => {
const model = sortingRatio(res)
const data = `按预警类型来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqlx = Subheading('1.1.1类型维度') + textStyle(data)
})
getYjxxPageList(promes).then((res) => {
pageData.tableData = res.records
pageData.total = res.total
});
};
const retenHome = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
// 预警来源统计
const getfxbgJqlytj = (val) => {
jqypfxbgJqlytj({ yjid: val }).then(res => {
const model = sortingRatio(res)
const data = `按预警来源来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqly = Subheading('1.1.2来源维度') + textStyle(data)
})
const openAddRule = (type, item, row) => {
regulation.value.init(type, item, row)
}
const ids = ref([])
// 地域统计
const getfxbgDywdtj = (val) => {
jqypDywdtj({ yjid: val }).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
}
const model = sortingRatio(res)
let data
if (model.length > 1) {
data = `从地市分布地市来看,${model[0].ssbm}预警量最大,占到全区预警总量的${model[0].number}。其次为${model[1].ssbm}${model[2].ssbm},两市预警量较为接近。预警量最少的为${model[model.length - 1].ssbm}`
} else {
data = `从地市分布地市来看,${model[0].ssbm}预警量最大,占到全区预警总量的${model[0].number}`
}
sortingRatioValue.value.dywd = Subheading('1.1.3地域维度') + textStyle(data)
})
const chooseData = (val) => {
ids.value = val.map(item => item.id)
}
// 分析报告-处理结果分析
const getfxgbCljgf = (val) => {
jqypfxbgCljgf({ yjid: val }).then(res => {
// sortingRatioValue.Cljgf =
const model = sortingRatio(res)
let czjgfx = `从预警处置结果来看,`
model.forEach(item => {
czjgfx += `${item.name},占到${item.ratio};`
})
sortingRatioValue.value.xlwdfx = BiheadlinegTitle('1.2预警处置') + Firstlevelheading('1.2.1结果维度') + textStyle(czjgfx)
})
}
// 分析报告-处置率分析
const getfxgbCzlfx = (val) => {
jqypfxbgCzlfx({ yjid: val }).then(res => {
dataList.withinTj = [{
name: "超时分流(超过24小时)",
value: res.within24h ? res.within24h : 0
}, {
name: "按时分流(24小时内)",
value: res.over24h ? res.over24h : 0
}]
const data = `从处警效率来看24小时以内处警的占到${res.over24h}%。表明我区公安机关在接警之后能够在第一时间处警。`
sortingRatioValue.value.czjgfx = Subheading('1.2.2效率维度') + textStyle(data)
})
}
const SaveReport = (val) => {
ElMessageBox.prompt('请输入名称', '提示', {
confirmButtonText: '确认',
const deleteRule = (row) => {
proxy.$confirm('是否删除该规则, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
// inputPattern:/[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
// inputErrorMessage: 'Invalid Email',
type: 'warning'
}).then(() => {
let list
if (Array.isArray(row)) {
list = ids.value
} else {
list =[row]
}
deleteYjgzpz({ids:list}).then(() => {
ElMessage.success("删除成功");
getList()
})
}).catch((err) => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
const yzSsyjpzMxgzxl = (params) => {
getYjgzpzMxgzxl({id:params}).then((res) => {
console.log(res);
})
.then(({ value }) => {
const promes = {
bgmc:value,
bgnr: val,
yjid:chageData.value
}
qcckPost( promes , "/mosty-gsxt/gsxtYpbg/addEntity")
.then(() => {
ElMessage.success("保存成功");
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消保存',
})
})
.catch(() => { });
}
const goback = () => {
emit('change', { type: '研判首页', data: null })
const jsonParse = (val) => {
if (val) {
return JSON.parse(val)
}
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
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 lang="scss" scoped>
.checkbox-group {
display: flex;
gap: 20px;
}
.basic-info {
display: flex;
gap: 15px;
.avatar {
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info-list {
display: flex;
flex-direction: column;
gap: 5px;
}
}
.control-buttons {
display: flex;
gap: 10px;
}
</style>

View File

@ -1,124 +1,116 @@
<template>
<!-- 研判类型 -->
<div class="content">
<div class="btnsBox" ref="refBtn">
<CheckBox :data="checkData.yplxBtn" @changeData="changeData_yplx"></CheckBox>
</div>
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"> </Search>
</div>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }"
v-loading="loading">
<li class="cntItem" @click.stop="lookDeatl(it)" v-for="(it, idx) in list" :key="idx">
<div class="ww100"><img class="ww100" style="height: 168px;" src="@/assets/images/mxbg.jpg" alt=""></div>
<div class="f14 lh24 pl4 pr4 one_text_detail">名称{{ it.ypMc }}</div>
<div class="flex ww100 f14 lh24 pl4 pr4 one_text_detail">类型
<DictTag :value="it.ypLx" :tag="false" :options="D_SG_TSYPGZ" />
</div>
<div class="f14 lh24 pl4 pr4 one_text_detail">数量{{ it.num }}</div>
<div class="foot">
<span class="ml10 pointer" @click.stop="openHistoricalReport(it.id)" style="color:#027ff0 ;"><el-icon style="top: 2px;"><Document /></el-icon>历史报告</span>
<span class="ml10 pointer" @click.stop="funAll(it.id)" style="color:#027ff0 ;"><el-icon style="top: 2px;"><Document /></el-icon>报告</span>
<span class="ml10 pointer" @click="handleHs(it)" style="color:#f4ac47 ;"><el-icon style="top: 2px;"><Files /></el-icon>会商</span>
</div>
</li>
<div class="ww100 flex just-center">
<MOSTY.Empty :show="!loading && list.length <= 0"></MOSTY.Empty>
</div>
<div class="tc ww100 mb4" style="color: #a29f9f;" v-if="total == list.length && total > 0">暂时没有数据了</div>
</ul>
<!-- 研判类型 -->
<div class="content">
<div class="titleBox">
<PageTitle title="模型平台">
<el-button type="primary" @click="openAddModel('add')" :icon="CirclePlus">
新增模型
</el-button>
</PageTitle>
</div>
<YpModel v-model="showModel" @SaveReport="SaveReport" :heightNumber="436" v-model:textContent="textContent"></YpModel>
<HistoricalReport v-model="showHistoricalReport" @choosed="getHistory" :chageData="chageData"/>
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"> </Search>
</div>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }"
v-loading="loading">
<li class="model-card" v-for="(it, idx) in list" :key="idx">
<div class="model-info">
<div class="model-name">
<strong>模型名称</strong>{{ it.mxmc }}
</div>
<div class="model-type flex">
<strong>模型类型</strong> <DictTag :tag="false" :value="it.mxlx" :options="D_MXGL_MXLX" />
</div>
</div>
<div class="model-image-container" @click="openYjList">
<img class="model-image"
src="@/assets/images/mxbg.jpg" alt="">
</div>
<div class="model-actions">
<span class="action-btn action-btn-view" @click.stop="openAddRule('', it)">
<el-icon class="action-icon"><Document /></el-icon>查看规则
</span>
<span class="action-btn action-btn-edit" @click.stop="openAddModel('edit', it)">
<el-icon class="action-icon"><ChatDotSquare /></el-icon>编辑
</span>
<span class="action-btn action-btn-edit" @click.stop="openAddModel('detail', it)">
<el-icon class="action-icon"><Edit /></el-icon>详情
</span>
<span class="action-btn action-btn-delete" @click.stop="delDictItem(it.id)">
<el-icon class="action-icon"><Files /></el-icon>删除
</span>
</div>
</li>
<div class="empty-container">
<MOSTY.Empty :show="!loading && list.length <= 0"></MOSTY.Empty>
</div>
<div class="no-more-data" v-if="total == list.length && total > 0">暂时没有数据了</div>
</ul>
</div>
<!-- <AddModel ref="addModel" :dict="{ D_MXGL_MXLX }" @getLits="getLits" /> -->
</template>
<script setup>
import CheckBox from '@/components/checkBox/index.vue'
import YpModel from '@/components/ypModel/index.vue'
import HistoricalReport from './historicalReport.vue'
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import { getPageList, deleteEntity } from '@/api/model.js'
import emitter from "@/utils/eventBus.js";
import { CirclePlus } from '@element-plus/icons-vue'
import * as MOSTY from "@/components/MyComponents/index";
import Search from "@/components/aboutTable/Search.vue";
import { qcckPost } from "@/api/qcckApi.js";
import { timeValidate } from '@/utils/tools.js'
import { getItem } from '@/utils/storage.js'
import { useRoute, useRouter } from 'vue-router';
import { reactive, ref, onMounted, getCurrentInstance, watch, defineEmits } from "vue";
import { jqypDywdtj, jqypfxbgJqlxtj, jqypfxbgYdfx, jqypfxbgJqlytj, jqypfxbgTj, jqypfxbgCljgf, jqypfxbgCzlfx, getDictItem } from '@/api/semanticAnalysis'
import { textStyle, Firstlevelheading, Subheading, BiheadlinegTitle, BigTitle, headTitle, report, signature } from './content.js'
import { ElMessage, ElMessageBox } from 'element-plus'
const router = useRouter();
const { proxy } = getCurrentInstance();
// import AddModel from "../components/AddModel/addModel";
const emit = defineEmits(['change'])
const { D_SG_SJLY, D_SG_TSYPGZ, JQLB, JQLX, JQXL, JQZL, D_BZ_JQLY, D_BZ_JQFL, JQCLJG } = proxy.$dict("D_SG_SJLY", "D_SG_TSYPGZ", "JQLB", "JQLX", "JQXL", "JQZL", "D_BZ_JQLY", "D_BZ_JQFL", "JQCLJG"); //获取字典数据
const { proxy } = getCurrentInstance();
const { D_MXGL_MXLX ,D_BZ_RYBQ} = proxy.$dict("D_MXGL_MXLX","D_BZ_RYBQ")
const searchBox = ref(); //搜索框
const showModel = ref(false);
const textContent = ref('');
const refBtn = ref();
const show = ref(false)
const listHeight = ref()
const searchConfiger = ref([
{ label: "研判名称", prop: "ypMc", placeholder: "请输入研判名称", showType: "input" },
]);
const checkData = reactive({
yplxBtn: {
hasChoose: [],
list: []
{ label: "模型名称", prop: "mxmc", placeholder: "请输入模型名称", showType: "input" },
{
label: "模型类型",
prop: "mxlx",
placeholder: "请选择模型类型",
showType: "select",
options: D_MXGL_MXLX
},
]);
const PaginationConfig = reactive({
pageCurrent: 1,
pageSize: 8,
});
const page = ref(1);
const total = ref(0)
const list = ref([])
const loading = ref(false);
const formData = ref({})
const chageData=ref()
watch(() => D_SG_TSYPGZ.value, val => {
checkData.yplxBtn.list = val.map(v => v.zdmc);
checkData.yplxBtn.hasChoose = val.map(v => v.zdmc);
}, { immediate: true, deep: true });
onMounted(() => {
show.value = true;
Time()
tabHeightFn();
getLits()
})
// 研判类型
const changeData_yplx = (val) => {
checkData.yplxBtn.hasChoose = val;
let dms = [];
D_SG_TSYPGZ.value.forEach(item => {
if (val.includes(item.zdmc)) dms.push(item.dm);
});
formData.value.ypLx = dms;
page.value = 1;
getLits();
}
const onSearch = (val) => {
formData.value = { ...formData.value, ...val, };
page.value = 1;
PaginationConfig.pageCurrent = 1;
getLits();
}
const load = () => {
if (total.value == list.value.length) return;
page.value++;
getLits();
PaginationConfig.pageCurrent++;
// getLits();
}
const getLits = () => {
let params = {
pageCurrent: page.value,
pageSize: 8,
...PaginationConfig,
...formData.value
}
loading.value = true;
qcckPost(params, '/mosty-gsxt/tsyp/selectPage').then(res => {
getPageList(params).then(res => {
let arr = res.records || [];
list.value = page.value == 1 ? arr : list.value.concat(arr);
list.value = PaginationConfig.pageCurrent == 1 ? arr : list.value.concat(arr);
total.value = res.total;
loading.value = false;
}).catch(() => {
@ -126,292 +118,204 @@ const getLits = () => {
})
}
const handleHs = (val) => {
router.push({ path: '/MeetingRoom', query: { tsypid: val.id } })
}
// 查看详情
const lookDeatl = (val) => {
emit('change', { data:val, type:'态势预警列表' })
}
// 表格高度计算
const tabHeightFn = () => {
listHeight.value = window.innerHeight - searchBox.value.offsetHeight - refBtn.value.offsetHeight - 182;
listHeight.value = window.innerHeight - searchBox.value.offsetHeight - 230;
window.onresize = function () {
tabHeightFn();
};
};
const dataList = reactive({
dyTj: {
xAxisData: [],
seriesData: [],
},
jqlxTj: [],
jqlyTj: [],
CljgfTj: [],
XsfxTj: [],
})
const sortingRatioValue = ref({
jqlx: "",
jqly: "",
dywd: "",
ydfx: "",
xlwdfx: "",
czjgfx: "",
})
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 pageData = reactive({
parameter: { bjlbList: '' }
})
const getDictItemList = () => {
const promes = {
dictCode: "00000000"
}
getDictItem(promes).then(res => {
pageData.parameter.bjlbList = res.map(item => item.dm).join(',')
console.log(pageData.parameter.bjlbList);
})
}
getDictItemList()
const funAll = (val) => {
const dev = getItem('deptId')[0]
sortingRatioValue.value = {}
textContent.value = BigTitle(`${endYears.value}年度西藏公安执法数据分析`) + headTitle({
orgName: dev.deptName,
serialNumber: timeValidate("", "mm"),
time: timeValidate(),
})
const data = `为全面、客观、准确掌握全区公安机关的执法状况,自治区公安厅基于数据统计,对全区公安机关${endYears.value}年度的执法状况作了客观分析。`
textContent.value += BiheadlinegTitle('1.接处警情况') + textStyle(data) + Firstlevelheading('一、执法状况总体分析')
getfxbgYdfx(val)
getfxbgTj(val)
getfxbgJqlxtj(val)
getfxbgJqlytj(val)
getfxbgDywdtj(val)
getfxgbCljgf(val)
getfxgbCzlfx(val)
showModel.value = true;
}
watch(() => sortingRatioValue.value, (val) => {
if (val.jqlx && val.jqly && val.dywd && val.ydfx && val.xlwdfx && val.czjgfx) {
textContent.value += val.jqlx + val.jqly + val.dywd + val.ydfx + val.xlwdfx + val.czjgfx + report() + signature()
}
}, { deep: true })
const getfxbgTj = (val) => {
jqypfxbgTj({ ypid: val }).then(res => {
const data = `${Time()} ,全区公安机关共接报各类警情${res.total}起,同比上升 ${res.tbbsb}%,同比上升${res.hbbsb}%`
textContent.value += BiheadlinegTitle('1.1接报警情') + textStyle(data)
dataList.XsfxTj = res
})
}
// 警情类型统计
const getfxbgJqlxtj = (val) => {
let params = {
...pageData.parameter,
ypid: val
}
jqypfxbgJqlxtj(params).then(res => {
const model = sortingRatio(res)
const data = `按警情类型来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqlx = Subheading('1.1.1类型维度') + textStyle(data)
})
}
// 警情来源统计
const getfxbgJqlytj = (val) => {
jqypfxbgJqlytj({ ypid: val }).then(res => {
const model = sortingRatio(res)
const data = `按警情来源来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqly = Subheading('1.1.2来源维度') + textStyle(data)
})
}
// 地域统计
const getfxbgDywdtj = (val) => {
jqypDywdtj({ ypid: val }).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
}
const model = sortingRatio(res)
let data
if (model.length > 1) {
data = `从地市分布地市来看,${model[0].ssbm}警情量最大,占到全区警情总量的${model[0].number}。其次为${model[1].ssbm}${model[2].ssbm},两市警情量较为接近。警情量最少的为${model[model.length - 1].ssbm}`
} else {
data = `从地市分布地市来看,${model[0].ssbm}警情量最大,占到全区警情总量的${model[0].number}`
}
sortingRatioValue.value.dywd = Subheading('1.1.3地域维度') + textStyle(data)
})
}
//分析报告-时间维度-月分析
const getfxbgYdfx = (val) => {
jqypfxbgYdfx({ ypid: val }).then(res => {
const model = sortingRatio(res)
const data = `我们将所有警情按照月份划分进行统计发现,每月警情分布较为平均。最高月份为${model[0].month}月,占到${model[0].number};最低月份为${model[res.length - 1].month}月,占到${model[res.length - 1].number}。考虑是因为${model[0].month}月为我区传统旅游旺季,进藏人员较多。 ${model[res.length - 1].month}月一般春节及藏历新年期间,在藏人员较少。`
sortingRatioValue.value.ydfx = Subheading('1.1.4时间维度') + textStyle(data)
})
}
// 分析报告-处理结果分析
const getfxgbCljgf = (val) => {
jqypfxbgCljgf({ ypid: val }).then(res => {
// sortingRatioValue.Cljgf =
const model = sortingRatio(res)
let czjgfx = `从警情处置结果来看,`
model.forEach(item => {
czjgfx += `${item.name},占到${item.ratio};`
})
sortingRatioValue.value.xlwdfx = BiheadlinegTitle('1.2警情处置') + Firstlevelheading('1.2.1结果维度') + textStyle(czjgfx)
})
}
// 分析报告-处置率分析
const getfxgbCzlfx = (val) => {
jqypfxbgCzlfx({ ypid: val }).then(res => {
dataList.withinTj = [{
name: "超时分流(超过24小时)",
value: res.within24h ? res.within24h : 0
}, {
name: "按时分流(24小时内)",
value: res.over24h ? res.over24h : 0
}]
const data = `从处警效率来看24小时以内处警的占到${res.over24h}%。表明我区公安机关在接警之后能够在第一时间处警。`
sortingRatioValue.value.czjgfx = Subheading('1.2.2效率维度') + textStyle(data)
})
}
const timeDate = ref()
const endYears = ref()
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');
timeDate.value = `${endYear}${endMonth}${endDay}`
endYears.value = year
return `${year}${month}${day}日 至${endYear}${endMonth}${endDay}`
}
const showHistoricalReport = ref(false)
const openHistoricalReport = (val) => {
chageData.value = val
showHistoricalReport.value = true
}
// const
const getHistory = (val) => {
textContent.value = val
showHistoricalReport.value = false
showModel.value = true
}
const SaveReport = (val) => {
ElMessageBox.prompt('请输入名称', '提示', {
confirmButtonText: '确认',
const delDictItem = (id) => {
proxy.$confirm('是否删除该模型, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
// inputPattern:/[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
// inputErrorMessage: 'Invalid Email',
})
.then(({ value }) => {
const promes = {
bgmc:value,
bgnr: val,
ypid:chageData.value
}
qcckPost( promes , "/mosty-gsxt/gsxtYpbg/addEntity")
.then(() => {
ElMessage.success("保存成功");
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消保存',
})
type: 'warning'
}).then(() => {
deleteEntity({ ids: [id] }).then(res => {
proxy.$message.success("删除成功!")
getLits()
})
}).catch(() => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
.catch(() => { });
}
// 打开弹窗
const addModel = ref(null)
const openAddModel = (type, row) => {
addModel.value.init(type, row)
}
// 打开规则弹窗
const openAddRule = (type, row) => {
switch (row.mxlx) {
case '02':
emitter.emit('changeModel', {row,name:'四色预警规则'})
break;
case '01':
emitter.emit('changeModel', {row,name:'预警规则'})
break;
default:
break;
}
}
const openYjList = (row) => {
emitter.emit('changeModel', {row,name:'预警列表'})
}
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
margin-top: 20px;
margin-left: 10px;
border-radius: 4px;
box-sizing: border-box;
width: 100%;
height: 100%;
margin-top: 20px;
margin-left: 10px;
border-radius: 8px;
box-sizing: border-box;
.btnsBox {
background: #fff;
padding: 10px 5px;
border-radius: 4px;
margin-bottom: 10px;
.btnsBox {
background: #fff;
padding: 10px 5px;
border-radius: 4px;
margin-bottom: 10px;
}
.cntlsit {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 20px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 16px;
box-sizing: border-box;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
// 模型卡片样式
.model-card {
width: 300px;
border: 1px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
background: #fff;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
&:hover {
transform: translateY(-4px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
border-color: #409eff;
}
.cntlsit {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 18px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 4px;
box-sizing: border-box;
// 模型信息区域
.model-info {
padding: 16px;
background-color: #fafafa;
border-bottom: 1px solid #f0f0f0;
.cntItem {
width: 300px;
border: 1px solid #ccc;
color: #787878;
border-radius: 4px;
overflow: hidden;
.model-name,
.model-type {
margin-bottom: 8px;
font-size: 14px;
color: #606266;
.foot {
text-align: right;
margin-top: 4px;
border-top: 1px solid #ccc;
padding: 4px;
box-sizing: border-box;
strong {
color: #303133;
font-weight: 500;
}
}
.model-type {
margin-bottom: 0;
}
}
// 模型图片区域
.model-image-container {
cursor: pointer;
overflow: hidden;
transition: all 0.3s ease;
.model-image {
width: 100%;
height: 168px;
object-fit: cover;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
}
// 操作按钮区域
.model-actions {
text-align: right;
padding: 12px 0px;
border-top: 1px solid #f0f0f0;
background-color: #fafafa;
.action-btn {
// margin-left: 12px;
justify-content: space-between;
font-size: 13px;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 4px;
.action-icon {
margin-right: 4px;
font-size: 14px;
}
&:hover {
opacity: 0.8;
}
}
.action-btn-view,
.action-btn-edit {
color: #409eff;
&:hover {
background-color: #ecf5ff;
}
}
.action-btn-delete {
color: #f4ac47;
&:hover {
background-color: #fff7e6;
}
}
}
}
// 空状态和无更多数据样式
.empty-container {
width: 100%;
display: flex;
justify-content: center;
padding: 40px 0;
}
.no-more-data {
width: 100%;
text-align: center;
margin-bottom: 16px;
color: #a29f9f;
font-size: 13px;
}
}
</style>

View File

@ -0,0 +1,105 @@
<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" v-show="title != '详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<FormMessage :formList="formData" v-model="listQuery" ref="elform" :rules="rules" :disabled="editAdd">
</FormMessage>
</div>
</div>
</template>
<script setup>
import { reactive, ref, getCurrentInstance } from 'vue'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { addEntity,editEntity } from '@/api/model.js'
import { ElMessage } from "element-plus";
const proxy = getCurrentInstance()
const props = defineProps({
dict: {
type: Array,
default: () => [],
}
})
const dialogForm = ref(false)
const emit = defineEmits(['getLits'])
// 判断是否增删改
const editAdd = ref(false)
const title = ref("新增")
const formData = ref()
const listQuery = ref({})
const elform = ref()
const rules = ref({
mxmc: [
{ required: true, message: '请输入模型名称', trigger: 'blur' },
],
mxlx: [
{ required: true, message: '请选择模型类型', trigger: 'change' },
],
})
const init = (type, row) => {
dialogForm.value = true
editAdd.value = false
formData.value = [
{ label: "模型名称", prop: "mxmc", type: "input", width: "40%" },
{
label: "模型类型", prop: "mxlx", type: "select",
width: "40%", options: props.dict.D_MXGL_MXLX
},
]
listQuery.value = { ...row }
if (type == 'edit') {
title.value = "编辑"
} else if (type == 'add') {
title.value = "新增"
} else {
editAdd.value = true
title.value = "详情"
}
}
// 表单内容
const loading = ref(false)
// 新增
const submit = () => {
elform.value.submit((data) => {
loading.value = true
if (title.value == '新增') {
addEntity(listQuery.value).then((res) => {
ElMessage.success("新增成功");
emit('getLits')
dialogForm.value = false
}).catch((err) => {
console.log(err);
}).finally(() => {
loading.value = false
});
} else {
editEntity(listQuery.value).then((res) => {
ElMessage.success("修改成功");
emit('getLits')
dialogForm.value = false
}).finally(() => {
loading.value = false
});
}
})
}
// 关闭
const close = () => {
dialogForm.value = false
}
defineExpose({
init
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,201 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="预警列表">
<!-- <el-button type="primary" size="small" @click="yzSsyjpzMxgzxl()">测试</el-button> -->
<el-button size="small" @click="retenHome()">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
>
<template #yjlx="{ row }">
<DictTag :tag="false" :value="row.yjlx" :options="dict.D_BZ_TPYJLX" />
</template>
<template #controls="{ row }">
<el-link type="primary" size="small" @click="opneModel">打开研判报告</el-link>
<el-link type="primary" size="small" @click="openYjdict(row)">详情</el-link>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
</div>
<YpModel v-model="showModel" @SaveReport="SaveReport" :heightNumber="436" v-model:textContent="textContent"></YpModel>
<Yjdict ref="yjdict" :dict="dict"/>
</template>
<script setup>
import YpModel from '@/components/ypModel/index.vue'
import emitter from "@/utils/eventBus.js";
import { getYjxxPageList,getSsyjpzMxgzxl } from "@/api/model";
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 {timeValidate} from '@/utils/tools'
import { reactive, ref, onMounted, getCurrentInstance, watch } from "vue";
import { textStyle, Firstlevelheading, Subheading, BiheadlinegTitle, newTotitle,BigTitle,fbtool, headTitle, report, signature } from '../content.js'
import Yjdict from './yjdict.vue'
const props = defineProps({
item: {
type: Object,
default: () => ({})
}, dict: {
type: Object,
default: () => ({})
}
})
const queryFrom = ref({})
const searchBox = ref(); //搜索框
const yjdict = ref(null)//详情弹窗
const ItemData=ref()//模型数据
const showModel = ref(false)
const textContent=ref('')//报告数据
const SaveReport = () => {
}
const opneModel = () => {
showModel.value = true
textContent.value=''
textContent.value += BigTitle("林芝市公安局情指中心") + BigTitle("研判专刊(初稿)") + newTotitle({
org: "市公安局情指中心编",
time: timeValidate()
})+fbtool('同类事件发生3次以上预警')+textStyle("2025年9月2日164525,产生同类事件3次以上预警,刑事案件中的置充身份诈美发生3起同七上升30%、环比比下健5%")
+ Subheading('1.警情内容') + Subheading('2.警情内容') + Subheading('3.警情内容')
}
const searchConfiger = ref([
{
label: "时间",
prop: "startTime",
placeholder: "请选择时间",
showType: "daterange"
},
]);
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 300,
tableColumn: [
{ label: "预警时间", prop: "yjsj", showOverflowTooltip: true },
{ label: "类型", prop: "yjlx" ,showSolt:true },
{ label: "内容", prop: "yjnr", showOverflowTooltip: true},
// ypbg
]
});
onMounted(() => {
getList();
tabHeightFn();
});
const openYjdict = (val) => {
yjdict.value.init(val)
}
watch(() => props.item, (val) => {
ItemData.value=val
},{deep:true})
// 获取列表
const getList = () => {
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
mxid:props.item.id,
}
getYjxxPageList(promes).then((res) => {
pageData.tableData = res.records
pageData.total = res.total
});
};
// 搜索
const onSearch = (val) => {
queryFrom.value.startTime = val.startTime&&val.startTime.length > 0 ? val.startTime[0] : '';
queryFrom.value.endTime = val.startTime&&val.startTime.length > 0 ? val.startTime[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
//返回
const retenHome = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
// 测试
const yzSsyjpzMxgzxl = (params) => {
// getYjgzpzMxgzxl({id:'26aefb9f4c7c41b3a4bfb5b68449328b'}).then((res) => {
// })
getSsyjpzMxgzxl({id:'88c166e670da48e59324906648794b05'}).then((res) => {
})
}
</script>
<style lang="scss" scoped>
.checkbox-group {
display: flex;
gap: 20px;
}
.basic-info {
display: flex;
gap: 15px;
.avatar {
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info-list {
display: flex;
flex-direction: column;
gap: 5px;
}
}
.control-buttons {
display: flex;
gap: 10px;
}
</style>

View File

@ -0,0 +1,75 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<div>详情</div>
<div><el-button @click="close">关闭</el-button></div>
</div>
<div class="form_cnt">
<FormMessage v-model="listQuery" disabled :formList="formData" ref="elform" />
</div>
</div>
</template>
<script setup>
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { ref, defineExpose} from "vue";
const props = defineProps({
dict: {
type: Object,
default: () => ({})
}
});
const dialogForm = ref(false); //弹窗
const formData = ref([
{ label: "预警内容", prop: "yjnr", type: "textarea" ,width:'100%'},
{ label: "预警时间", prop: "yjsj", type: "date" },
{ label: "预警类型", prop: "yjlx", type: "select", options: props.dict.D_BZ_TPYJLX },
]);
const listQuery = ref({}); //表单
const elform = ref();
// 初始化数据
const init = (row) => {
dialogForm.value = true;
listQuery.value = row;
};
// 关闭
const close = () => {
listQuery.value = {};
dialogForm.value = false;
};
defineExpose({ init });
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
::v-deep .el-tabs--card>.el-tabs__header .el-tabs__item.is-active {
color: #0072ff;
background: rgba(0, 114, 255, 0.3);
}
.boxlist {
width: 99%;
height: 225px;
margin-top: 10px;
overflow: hidden;
}
::v-deep .avatar-uploader {
display: flex;
align-items: center;
}
::v-deep .el-upload-list {
margin-left: 20px;
display: flex;
align-items: center;
}
::v-deep .el-upload-list__item-name .el-icon {
top: 3px;
}
</style>

View File

@ -0,0 +1,739 @@
<template>
<!-- 可用条件类型列表 -->
<div class="regulation-wrapper">
<div class="rule-name-section flex align-center">
<div class="rule-name-label">规则名称</div>
<el-input v-model="gzmc" :disabled="disabled" placeholder="请输入规则名称" class="search-input" clearable></el-input>
</div>
<!-- 可用条件区域 -->
<div class="condition-section">
<div class="available-conditions">
<VueDraggable class="flex-wrap" v-model="dataList" ghostClass="ghost"
:group="{ name: 'people', pull: 'clone', put: false }" :clone="clone">
<el-button v-for="item in dataList" :key="item.name" class="condition-button" size="small">
<i class="el-icon-document-add"></i>
{{ item.name }}
</el-button>
</VueDraggable>
</div>
</div>
<!-- 拖拽提示 -->
<div class="drag-hint">
<i class="el-icon-arrow-down"></i>
<span>拖拽条件到下方区域<span style="color: red;">(事件类型和警情类型必须选择一个)</span></span>
</div>
<!-- 已选条件区域 -->
<div class="selected-section">
<div class="section-title">
<i class="el-icon-check-square"></i>
<span>已选条件</span>
<span class="selected-count">{{ copyList.length }}</span>
</div>
<div class="selected-container">
<VueDraggable v-model="copyList" :group="{ name: 'people', pull: !disabled, put: !disabled }" ghostClass="ghost"
class="selected-list" itemKey="name">
<div v-for="(item, indexs) in copyList" :key="item" class="draggable-item">
<div class="item-content">
<div v-if="!disabled" class="item-remove-btn" @click="romes(item)"><el-icon :size="16">
<Close />
</el-icon></div>
<span class="item-text">{{ item.name }}{{}}</span>
</div>
<div v-if="item[item['key']]">
<template v-if="item.key == 'dd'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'cs'">
<div class="count-condition-container">
<el-select v-model="item[item['key']].tj" placeholder="请选择条件" class="condition-select">
<el-option :label="item" :value="item" v-for="(item, index) in dataConst" :key="index"></el-option>
</el-select>
<el-input-number v-model="item[item['key']].cs" :min="1" :max="1000" />
</div>
</template>
<template v-if="item.key == 'zz'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'kssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'jssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'sjlx'">
<div class="condition-input-container flex just-between">
<el-select v-model="item[item['key']]" multiple :placeholder="`请选择${item.name}`">
<el-option v-for="item in dict.D_BB_AJLB" :key="item.dm" :label="item.zdmc" :value="item.dm" />
</el-select>
</div>
</template>
<template v-if="item.key == 'wp'">
<div class="condition-input-container flex just-between">
<el-select v-model="item[item['key']]" multiple :placeholder="`请选择${item.name}`" style="width: 240px">
<el-option v-for="item in dict.D_BZ_WPLX" :key="item.dm" :label="item.zdmc" :value="item.dm" />
</el-select>
</div>
</template>
<template v-if="item.key == 'ryxx'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index].xm" :placeholder="`请输入姓名`" clearable></el-input>
</div>
<div>
<el-input v-model="item[item['key']][index].sfzh" :placeholder="`请输入身份证号`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-else-if="item.key == 'jqlx'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseMarksVisible = true" v-model="item[item['key']][index].lxmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
</div>
</div>
</VueDraggable>
<!-- 空状态提示 -->
<div v-if="copyList.length === 0" class="empty-state">
<i class="el-icon-tickets"></i>
<p>暂无已选条件</p>
<p class="empty-tip">从上方拖拽条件到此处</p>
</div>
</div>
</div>
</div>
<ChooseIdeJqlb v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
</template>
<script setup>
import { reactive, ref, watch,onMounted } from 'vue'
import ChooseIdeJqlb from '@/components/ChooseList/ChooseIdeJqlb/index.vue'
import { VueDraggable } from 'vue-draggable-plus'//npm install vue-draggable-plus
const props = defineProps({
dict: {
type: Object,
default: () => { },
},
list: {
type: Array,
default: () => [
'Joao',
'Jean',
'Johanna',
'Juan',
],
}, defaultData: {
type: Object,
default: () => { },
}, disabled: {
type: Boolean,
default: false
}
})
const dataConst = reactive([
">",
"<",
"=",
">=",
"<="
])
const dataList = ref([])
const gzmc = ref('')
const list=[{
name: "地点",
key: "dd",
}, {
name: '警情类型',
key: 'jqlx',
}, {
name: '人员信息',
key: 'ryxx',
}, {
name: '事件类型',
key: 'sjlx',
}, {
name: '物品',
key: 'wp',
}, {
name: '组织',
key: 'zz',
}, {
name: '开始时间',
key: 'kssj',
}, {
name: '结束时间',
key: 'jssj',
}, {
name: '次数',
key: 'cs',
}]
const copyList = ref([])
const clone = (val) => {
if (val.key == 'jqlx') {
dataList.value = dataList.value.filter(item => item.key != 'sjlx')
}
if (val.key == 'sjlx') {
dataList.value = dataList.value.filter(item => item.key != 'jqlx')
}
const data = copyList.value.find(item => item.name == val.name)
if (data) {
console.log("已存在")
} else {
switch (val.key) {
case 'cs':
return {
name: val.name,
key: val.key,
[val["key"]]: {}
}
case "wp":
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
case 'ryxx':
return {
name: val.name,
key: val.key,
[val["key"]]: [{
xm: "",
sfzh: ""
}]
}
case 'kssj':
case 'jssj':
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
case 'sjlx':
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
default:
return {
name: val.name,
key: val.key,
[val["key"]]: [""]
}
}
}
}
watch(() => props.defaultData, (val) => {
if (val) {
gzmc.value = val.gzmc
const data = dataList.value.map(item => {
switch (item.key) {
case 'cs':
return {
name: item.name,
key: item.key,
[item["key"]]: val.cs && val.tj ? {
cs: val.cs,
tj: val.tj
} : null
}
case 'jssj':
case 'kssj':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? val[item.key] : null,
}
case 'zz':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.zzmc) : null,
}
case 'dd':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.dz) : null,
}
default:
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]) : null
}
}
})
copyList.value = data.filter(item => item[item.key] != null)
dataList.value = list.filter(item => {
if (val.sjlx) {
return item.key != 'jqlx'
}
if (val.jqlx){
return item.key != 'sjlx'
}
return item
})
} else {
dataList.value=list
}
}, { deep: true })
const addInput = (key, index) => {
if (key == 'ryxx') {
copyList.value[index][key].push({
xm: "",
sfzh: ""
})
} else {
copyList.value[index][key].push("")
}
}
// 移除项目
const removeItem = (key, index) => {
const data = copyList.value.findIndex(item => item.key == key)
if (copyList.value[data][key].length == 1) {
return
}
copyList.value[data][key].splice(index, 1)
}
const chooseMarksVisible = ref(false)
const roleIds = ref([])
const choosed = (val) => {
roleIds.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'jqlx')['jqlx'] = val.map(item => {
return {
lxmc: item.zdmc,
lxdm: item.dm
}
})
}
const romes = (val) => {
copyList.value = copyList.value.filter(item => item.key !== val.key)
if (val.key == 'jqlx' || val.key == 'sjlx') {
dataList.value = list
}
}
const promes = ref({})
// 新增
const retValue = () => {
if (gzmc.value == '') {
return
}
const data = copyList.value.map(item => {
return {
[item.key]: item[item.key]
}
})
promes.value = data.reduce((acc, cur) => {
return { ...acc, ...cur }
}, {})
promes.value = { ...promes.value, ...promes.value.cs, gzmc: gzmc.value }
if (promes.value.dd && promes.value.dd.length > 0) {
const dd = promes.value.dd.map(item => {
return { dz: item }
})
promes.value.dd = JSON.stringify(dd)
}
if (promes.value.zz && promes.value.zz.length > 0) {
const zz = promes.value.zz.map(item => {
return { zzmc: item }
})
promes.value.zz = JSON.stringify(zz)
}
const sjlx = copyList.value.find(item => item.key == 'sjlx')
if (sjlx) {
const data = props.dict.D_BB_AJLB.filter(item => {
if (sjlx['sjlx'].includes(item.dm)) {
return item
}
}).map(item => {
return {
lxmc: item.zdmc,
lxdm: item.dm
}
})
promes.value.sjlx = JSON.stringify(data)
}
const wplx = copyList.value.find(item => item.key == 'wp')
if (wplx) {
const data = props.dict.D_BZ_WPLX.filter(item => {
if (wplx['wp'].includes(item.dm)) {
return item
}
}).map(item => {
return {
wpmc: item.zdmc,
wpdm: item.dm
}
})
promes.value.wp = JSON.stringify(data)
}
if (promes.value.ryxx && promes.value.ryxx.length > 0) {
promes.value.ryxx = JSON.stringify(promes.value.ryxx)
}
if (promes.value.jqlx && promes.value.jqlx.length > 0) {
promes.value.jqlx = JSON.stringify(promes.value.jqlx)
}
return promes.value
}
defineExpose({
retValue
})
</script>
<style lang="scss" scoped>
.regulation-wrapper {
padding: 20px;
background: #f5f7fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
// 条件区域通用样式
.condition-section,
.selected-section {
background: white;
border-radius: 10px;
padding: 10px;
// margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.condition-section:hover,
.selected-section:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
// 区域标题
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
color: #303133;
font-weight: 600;
font-size: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e6f7ff;
i {
color: #409eff;
margin-right: 8px;
font-size: 18px;
}
.selected-count {
margin-left: 10px;
font-size: 14px;
font-weight: normal;
color: #606266;
background: #f0f9ff;
padding: 2px 8px;
border-radius: 12px;
min-width: 24px;
text-align: center;
}
}
// 可用条件区域
.available-conditions {
// min-height: 100px;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.condition-button {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 8px 16px !important;
font-size: 14px !important;
transition: all 0.3s ease !important;
min-width: 120px;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
&:hover {
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%) !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
}
i {
margin-right: 6px;
}
}
// 拖拽提示
.drag-hint {
display: flex;
align-content: flex-start;
// align-items: center;
justify-content: center;
padding: 20px;
color: #909399;
font-size: 14px;
i {
margin-right: 8px;
font-size: 16px;
animation: bounce 1.5s infinite;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
}
// 已选条件区域
.selected-container {
min-height: 120px;
border: 2px dashed #dcdfe6;
border-radius: 8px;
padding: 20px;
transition: all 0.3s ease;
background-color: #dcdfe670;
&:hover {
border-color: #409eff;
background: #f0f9ff;
}
}
.selected-list {
display: flex;
min-height: 100px;
width: 100%;
flex-wrap: wrap;
}
// 拖拽项样式
.draggable-item {
position: relative;
padding: 3px;
margin: 8px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: table-cell;
justify-content: space-between;
text-align: center;
flex-wrap: wrap;
&:hover {
transform: translateY(-2px) scale(1.02);
box-shadow: 0 6px 16px rgba(103, 194, 58, 0.4);
}
&.ghost {
opacity: 0.6;
transform: rotate(5deg);
}
}
.item-content {
background: white;
border-radius: 8px;
padding: 20px 12px 12px 12px;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
position: relative;
}
.item-text {
font-size: 14px;
color: #303133;
font-weight: 500;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.item-remove {
color: #c0c4cc;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
padding: 4px;
border-radius: 50%;
&:hover {
color: #f56c6c;
background: #fef0f0;
transform: rotate(90deg);
}
}
/* 规则名称区域 */
.rule-name-section {
margin-bottom: 10px;
}
.rule-name-label {
width: 100px;
}
/* 项目删除按钮 */
.item-remove-btn {
position: absolute;
top: 5px;
right: 10px;
}
/* 条件输入容器 */
.condition-input-container {
flex-wrap: nowrap;
margin-top: 10px;
}
/* 计数条件容器 */
.count-condition-container {
margin-top: 10px;
display: flex;
}
/* 条件选择框 */
.condition-select {
width: 100px;
}
/* 按钮右侧边距 */
.btn-margin-right {
margin-right: 5px;
}
// 空状态样式
.empty-state {
text-align: center;
padding: 40px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
transition: color 0.3s ease;
}
p {
margin: 0;
font-size: 14px;
}
.empty-tip {
font-size: 12px;
color: #c0c4cc;
margin-top: 8px;
}
&:hover i {
color: #409eff;
}
}
// 拖拽效果
.ghost {
opacity: 0.6;
background-color: #e6f7ff;
border: 2px dashed #409eff;
border-radius: 8px;
}
// 响应式设计
@media (max-width: 768px) {
.regulation-wrapper {
padding: 15px;
}
.condition-section,
.selected-section {
padding: 15px;
}
.condition-button {
min-width: 100px;
font-size: 13px !important;
}
.item-content {
min-width: 120px;
padding: 10px 12px;
}
}
:v-deep .el-select {
width: 59%;
}
</style>

View File

@ -0,0 +1,666 @@
<template>
<!-- 可用条件类型列表 -->
<div class="regulation-wrapper">
<div class="rule-name-section flex align-center">
<div class="rule-name-label">规则名称</div>
<el-input v-model="gzmc" :disabled="disabled" placeholder="请输入规则名称" class="search-input" clearable></el-input>
</div>
<!-- 可用条件区域 -->
<div class="condition-section">
<div class="available-conditions">
<VueDraggable class="flex-wrap" v-model="dataList" ghostClass="ghost"
:group="{ name: 'people', pull: 'clone', put: false }" :clone="clone">
<el-button v-for="item in dataList" :key="item.name" class="condition-button" size="small">
<i class="el-icon-document-add"></i>
{{ item.name }}
</el-button>
</VueDraggable>
</div>
</div>
<!-- 拖拽提示 -->
<div class="drag-hint">
<i class="el-icon-arrow-down"></i>
<span>拖拽条件到下方区域</span>
</div>
<!-- 已选条件区域 -->
<div class="selected-section">
<div class="section-title">
<i class="el-icon-check-square"></i>
<span>已选条件</span>
<span class="selected-count">{{ copyList.length }}</span>
</div>
<div class="selected-container">
<VueDraggable v-model="copyList" :group="{ name: 'people', pull: !disabled, put: !disabled }" ghostClass="ghost"
class="selected-list" itemKey="name">
<div v-for="(item, indexs) in copyList" :key="item" class="draggable-item">
<div class="item-content">
<div v-if="!disabled" class="item-remove-btn" @click="romes(item)"><el-icon :size="16">
<Close />
</el-icon></div>
<span class="item-text">{{ item.name }}</span>
</div>
<div v-if="item[item['key']]">
<template v-if="item.key == 'dd'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-else-if="item.key == 'sfbq'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseIdentityVisible = true" v-model="item[item['key']][index].bqmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
<!-- <template v-if="item.key == 'cs'">
<div class="count-condition-container">
<el-select v-model="item[item['key']].tj" placeholder="请选择条件" class="condition-select">
<el-option :label="item" :value="item" v-for="(item, index) in dataConst" :key="index"></el-option>
</el-select>
<el-input-number v-model="item[item['key']].cs" :min="1" :max="1000" />
</div>
</template> -->
<template v-if="item.key == 'xwbq'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input @click="chooseMarksVisible = true" v-model="item[item['key']][index].bqmc"
:placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" @click="removeItem(item['key'], index)" type="danger"
size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'zz'">
<div class="condition-input-container flex just-between" v-for="(value, index) in item[item['key']]">
<div>
<el-input v-model="item[item['key']][index]" :placeholder="`请输入${item.name}`" clearable></el-input>
</div>
<div>
<el-button class="btn-margin-right" v-if="index == item[item['key']].length - 1"
@click="addInput(item['key'], indexs)" type="danger" size="mini">+</el-button>
<el-button class="btn-margin-right" v-if="index != item[item['key']].length - 1"
@click="removeItem(item['key'], index)" type="danger" size="mini">-</el-button>
</div>
</div>
</template>
<template v-if="item.key == 'kssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
<template v-if="item.key == 'jssj'">
<div class="condition-input-container flex just-between">
<div>
<el-date-picker value-format="YYYY-MM-DD" format="YYYY-MM-DD" v-model="item[item['key']]"
type="date" :placeholder="`请选择${item.name}`" />
</div>
</div>
</template>
</div>
</div>
</VueDraggable>
<!-- 空状态提示 -->
<div v-if="copyList.length === 0" class="empty-state">
<i class="el-icon-tickets"></i>
<p>暂无已选条件</p>
<p class="empty-tip">从上方拖拽条件到此处</p>
</div>
</div>
</div>
</div>
<ChooseMarks v-model="chooseMarksVisible" @choosed="choosed" :roleIds="roleIds" />
<ChooseIdentity v-model="chooseIdentityVisible" @choosed="choosedIdentity" :roleIds="roleIdsIdentity" />
</template>
<script setup>
import { reactive, ref, watch } from 'vue'
import ChooseMarks from "@/components/ChooseList/ChooseMarks/index.vue";
import ChooseIdentity from "@/components/ChooseList/ChooseIdentity/index.vue";
import { ElMessage } from "element-plus";
import { VueDraggable } from 'vue-draggable-plus'//npm install vue-draggable-plus
const props = defineProps({
dict: {
type: Array,
default: () => [],
},
list: {
type: Array,
default: () => [
'Joao',
'Jean',
'Johanna',
'Juan',
],
}, defaultData: {
type: Object,
default: () => { },
}, disabled: {
type: Boolean,
default: false
}
})
const dataConst = reactive([
">",
"<",
"="
])
const dataList = ref([{
name: "地点",
key: "dd",
id: 1
}, {
name: "身份标签",
key: "sfbq",
id: 2
},
// {
// name: "次数",
// key: "cs",
// id: 3
// },
{
name: "行为标签",
key: "xwbq",
id: 4
}, {
name: "组织",
key: "zz",
id: 5
}, {
name: "开始时间",
key: "kssj",
id: 6
}, {
name: "结束时间",
key: "jssj",
id: 7
}])
const gzmc = ref('')
const copyList = ref([])
const clone = (val) => {
console.log(val);
const data = copyList.value.find(item => item.name == val.name)
if (data) {
console.log("已存在")
} else {
// if (val.key == 'cs') {
// return {
// name: val.name,
// key: val.key,
// [val["key"]]: {}
// }
// } else {
if (val.key == 'cs' || val.key == 'kssj' || val.key == 'jssj') {
return {
name: val.name,
key: val.key,
[val["key"]]: []
}
}
else {
return {
name: val.name,
key: val.key,
[val["key"]]: [""]
}
}
}
}
watch(() => props.defaultData, (val) => {
if (val) {
gzmc.value = val.gzmc
const data = dataList.value.map(item => {
switch (item.key) {
// case 'cs':
// return {
// name: item.name,
// key: item.key,
// [item["key"]]: {
// cs: val.cs,
// tj: val.tj
// }
// }
case 'jssj':
case 'kssj':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? val[item.key] : null,
}
case 'zz':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.zzmc) : null,
}
case 'dd':
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]).map(item => item.dz) : null,
}
default:
return {
name: item.name,
key: item.key,
[item["key"]]: val[item.key] ? JSON.parse(val[item.key]) : null
}
}
})
copyList.value = data.filter(item => {
return item[item.key] != null
})
}
}, { deep: true })
const addInput = (key, index) => {
copyList.value[index][key].push("")
}
// 移除项目
const removeItem = (key, index) => {
const data = copyList.value.findIndex(item => item.key == key)
if (copyList.value[data][key].length == 1) {
return
}
copyList.value[data][key].splice(index, 1)
}
// 选择预警标签
const roleIds = ref([])
const chooseMarksVisible = ref()
const choosed = (val) => {
roleIds.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'xwbq')['xwbq'] = val.map(item => {
return {
bqdm: item.bqDm,
bqmc: item.bqMc
}
})
}
// 选择身份标签
const chooseIdentityVisible = ref()
const roleIdsIdentity = ref([])
const choosedIdentity = (val) => {
roleIdsIdentity.value = val.map(item => item.id)
copyList.value.find(item => item.key == 'sfbq')['sfbq'] = val.map(item => {
return {
bqdm: item.bqDm,
bqmc: item.bqMc
}
})
}
const romes = (val) => {
copyList.value = copyList.value.filter(item => item.key !== val.key)
}
const promes = ref({})
// 新增
const retValue = () => {
if (gzmc.value == '') {
return
}
const data = copyList.value.map(item => {
return {
[item.key]: item[item.key]
}
})
promes.value = data.reduce((acc, cur) => {
return { ...acc, ...cur }
}, {})
promes.value = { ...promes.value, gzmc: gzmc.value }
if (promes.value.dd && promes.value.dd.length > 0) {
promes.value.dd = promes.value.dd.map(item => {
return { dz: item }
})
}
if (promes.value.zz && promes.value.zz.length > 0) {
promes.value.zz = promes.value.zz.map(item => {
return { zzmc: item }
})
}
promes.value.kssj = promes.value.kssj ? promes.value.kssj.toString() : null
promes.value.jssj = promes.value.jssj ? promes.value.jssj.toString() : null
const retData = {
...promes.value,
dd: promes.value.dd ? JSON.stringify(promes.value.dd) : null,
sfbq: promes.value.sfbq ? JSON.stringify(promes.value.sfbq) : null,
xwbq: promes.value.xwbq ? JSON.stringify(promes.value.xwbq) : null,
zz: promes.value.zz ? JSON.stringify(promes.value.zz) : null,
}
return retData
}
defineExpose({
retValue
})
</script>
<style lang="scss" scoped>
.regulation-wrapper {
padding: 20px;
background: #f5f7fa;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
// 条件区域通用样式
.condition-section,
.selected-section {
background: white;
border-radius: 10px;
padding: 10px;
// margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
}
.condition-section:hover,
.selected-section:hover {
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
// 区域标题
.section-title {
display: flex;
align-items: center;
margin-bottom: 16px;
color: #303133;
font-weight: 600;
font-size: 16px;
padding-bottom: 12px;
border-bottom: 2px solid #e6f7ff;
i {
color: #409eff;
margin-right: 8px;
font-size: 18px;
}
.selected-count {
margin-left: 10px;
font-size: 14px;
font-weight: normal;
color: #606266;
background: #f0f9ff;
padding: 2px 8px;
border-radius: 12px;
min-width: 24px;
text-align: center;
}
}
// 可用条件区域
.available-conditions {
// min-height: 100px;
}
.flex-wrap {
display: flex;
flex-wrap: wrap;
gap: 12px;
}
.condition-button {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
color: white !important;
border: none !important;
border-radius: 8px !important;
padding: 8px 16px !important;
font-size: 14px !important;
transition: all 0.3s ease !important;
min-width: 120px;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.3);
&:hover {
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%) !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
}
i {
margin-right: 6px;
}
}
// 拖拽提示
.drag-hint {
display: flex;
align-content: flex-start;
// align-items: center;
justify-content: center;
padding: 20px;
color: #909399;
font-size: 14px;
i {
margin-right: 8px;
font-size: 16px;
animation: bounce 1.5s infinite;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-10px);
}
60% {
transform: translateY(-5px);
}
}
}
// 已选条件区域
.selected-container {
min-height: 120px;
border: 2px dashed #dcdfe6;
border-radius: 8px;
padding: 20px;
transition: all 0.3s ease;
background-color: #dcdfe670;
&:hover {
border-color: #409eff;
background: #f0f9ff;
}
}
.selected-list {
min-height: 100px;
}
// 拖拽项样式
.draggable-item {
position: relative;
// background: rgba(103, 194, 58, 0.3);
padding: 3px;
margin: 8px;
// box-shadow: 0 4px 12px rgba(103, 194, 58, 0.3);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: table-cell;
justify-content: space-between;
// cursor: move;
text-align: center;
&:hover {
transform: translateY(-2px) scale(1.02);
box-shadow: 0 6px 16px rgba(103, 194, 58, 0.4);
}
&.ghost {
opacity: 0.6;
transform: rotate(5deg);
}
}
.item-content {
background: white;
border-radius: 8px;
padding: 20px 12px 12px 12px;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 140px;
position: relative;
}
.item-text {
font-size: 14px;
color: #303133;
font-weight: 500;
flex: 1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
margin-right: 10px;
}
.item-remove {
color: #c0c4cc;
font-size: 18px;
cursor: pointer;
transition: all 0.3s ease;
padding: 4px;
border-radius: 50%;
&:hover {
color: #f56c6c;
background: #fef0f0;
transform: rotate(90deg);
}
}
/* 规则名称区域 */
.rule-name-section {
margin-bottom: 10px;
}
.rule-name-label {
width: 100px;
}
/* 项目删除按钮 */
.item-remove-btn {
position: absolute;
top: 5px;
right: 10px;
}
/* 条件输入容器 */
.condition-input-container {
flex-wrap: nowrap;
margin-top: 10px;
}
/* 计数条件容器 */
.count-condition-container {
margin-top: 10px;
display: flex;
}
/* 条件选择框 */
.condition-select {
width: 100px;
}
/* 按钮右侧边距 */
.btn-margin-right {
margin-right: 5px;
}
// 空状态样式
.empty-state {
text-align: center;
padding: 40px 20px;
color: #909399;
i {
font-size: 48px;
margin-bottom: 16px;
color: #dcdfe6;
transition: color 0.3s ease;
}
p {
margin: 0;
font-size: 14px;
}
.empty-tip {
font-size: 12px;
color: #c0c4cc;
margin-top: 8px;
}
&:hover i {
color: #409eff;
}
}
// 拖拽效果
.ghost {
opacity: 0.6;
background-color: #e6f7ff;
border: 2px dashed #409eff;
border-radius: 8px;
}
// 响应式设计
@media (max-width: 768px) {
.regulation-wrapper {
padding: 15px;
}
.condition-section,
.selected-section {
padding: 15px;
}
.condition-button {
min-width: 100px;
font-size: 13px !important;
}
.item-content {
min-width: 120px;
padding: 10px 12px;
}
}
:v-deep .el-select {
width: 59%;
}
</style>

View File

@ -1,53 +0,0 @@
<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" v-show="title!='详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<FormMessage :formList="formData" v-model="listQuery" ref="elform" :rules="rules">
</FormMessage>
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
const dialogForm = ref(false)
const title=ref("新增")
const init = (type,row) => {
dialogForm.value = true
if (type=='edit') {
title.value="编辑"
} else if (type=='add') {
title.value="新增"
} else {
title.value="详情"
}
}
// 表单内容
const formData = reactive([
{ label: "模型名称", prop: "mxmc", type: "input", width: "40%" },
{ label: "模型类型", prop: "mxlx", type: "input", width: "40%"},
])
const loading=ref(false)
// 新增
const submit = () => {
loading.value = true
}
// 关闭
const close = () => {
dialogForm.value = false
}
defineExpose({
init
})
</script>
<style lang="scss" scoped>
</style>

View File

@ -27,4 +27,9 @@ export const report = (data) => {
export const signature = () => {
return `<p> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 承办人: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 核稿人 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;签发人:</p >`
}
export const newTotitle = (data) => {
return `<p style="text-align: center;"><span style="color: rgb(225, 60, 57); font-size: 16px; font-family: 标楷体;">${data.org} &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ${data.time}</span></p><hr/><p><br></p>`
}
export const fbtool = (data) => {
return `<p style="text-align: center;"><span style="font-size: 24px;">${data} </span></p>`
}

View File

@ -0,0 +1,202 @@
<template>
<!-- v-if="dialogForm" -->
<div class="dialog" >
<div class="head_box">
<span class="title">{{ title }}规则 </span>
<div>
<el-button type="primary" size="small" :loading="loading" @click="submit" v-show="title != '详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<EarlyWarning v-if="item.mxlx == YJGZ" ref="regulationRef"
:dict="{D_BB_AJLB,D_BZ_WPLX}"
:defaultData="defaultData" :disabled="false" />
<Regulation v-if="item.mxlx ==SSYJ" ref="regulationRef" :dict="{D_BZ_RYBQ}"
:defaultData="defaultData" :disabled="false" />
</div>
</div>
</template>
<script setup>
import { reactive, ref ,getCurrentInstance, onMounted} from 'vue'
import { ElMessage } from "element-plus";
import { addSsyjpz, editSsyjpz, addYjgzpz, editYjgzpz } from '@/api/model'
import emitter from "@/utils/eventBus.js";
import {mxglSsyjpzSelectList,getYjgzpzSelectList} from '@/api/model'
import Regulation from "./FourColor/regulation.vue";
import EarlyWarning from "./EarlyWarning/regulation.vue";
const props = defineProps({
item: {
type: Object,
default: () => {},
}
})
const { proxy } = getCurrentInstance();
const { D_BB_AJLB,D_BZ_WPLX,D_BZ_RYBQ} = proxy.$dict("D_BB_AJLB","D_BZ_WPLX","D_BZ_RYBQ")
const title = ref("新增")
const emit = defineEmits(['getList'])
const listQuery = ref()
const defaultData = ref({})
const SSYJ = '02'
const YJGZ='01'
onMounted(() => {
switch (props.item.mxlx) {
case SSYJ:
getmxglSsyjpzSelectList()
break;
case YJGZ:
getgetYjgzpzSelectList()
break;
default:
break;
}
})
const getgetYjgzpzSelectList = () => {
const promes = {
mxid:props.item.id
}
getYjgzpzSelectList(promes).then((res) => {
if (res.length > 0) {
listQuery.value = props.item
defaultData.value = res[0]
} else {
defaultData.value = {}
}
})
}
const getmxglSsyjpzSelectList=() => {
const promes = {
mxid:props.item.id
}
mxglSsyjpzSelectList(promes).then((res) => {
if (res.length > 0) {
listQuery.value = props.item
defaultData.value = res[0]
} else {
defaultData.value = {}
}
})
}
const regulationRef = ref(null)
const loading = ref(false)
// 新增
const submit = () => {
switch (props.item.mxlx) {
case SSYJ:
addSsyj()
break;
case YJGZ:
addYjgzpzs()
break;
default:
break;
}
}
const addSsyj = () => {
const data = regulationRef.value.retValue()
if (!data || !data.gzmc) {
ElMessage.warning('请填写规则名称')
return
}
if (!defaultData.value) {
const promes = {
mxid: props.item.id,
...data
}
addSsyjpz(promes).then((result) => {
ElMessage.success('新增成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
} else {
editSsyjpz({
id: defaultData.value.id,
...data
}).then((result) => {
ElMessage.success('编辑成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
}
}
const addYjgzpzs = () => {
const data = regulationRef.value.retValue()
if (!data || !data.gzmc) {
ElMessage.warning('请填写规则名称')
return
}
if (!data || !data.sjlx&&!data.jqlx) {
ElMessage.warning('请事件类型和警情类型必须选择一个')
return
}
if (!defaultData.value) {
const promes = {
mxid:props.item.id,
...data
}
addYjgzpz(promes).then((result) => {
ElMessage.success('新增成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
} else {
console.log( defaultData.value.id);
editYjgzpz({
id: defaultData.value.id,
...data
}).then((result) => {
ElMessage.success('编辑成功')
emit('getList')
close()
}).catch((err) => {
ElMessage.error(err.message)
});
}
}
const close = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
</script>
<style lang="scss" scoped>
::v-deep .el-button+.el-button {
margin-left: 0px;
}
.flex {
display: flex;
}
.flex-wrap {
flex-wrap: wrap;
}
.just-between {
justify-content: space-between;
}
.mb-10 {
margin-bottom: 10px;
}
.mr-10 {
margin-right: 10px;
}
</style>

View File

@ -1,67 +0,0 @@
<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" v-show="title != '详情'">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<VueDraggable @update="onUpdate"
@add="onAdd"
@remove="remove">
<el-button type="primary" v-for="(item,index) in listBut" :key="index">{{ item }}</el-button>
</VueDraggable>
<VueDraggable>
<el-button type="primary" v-for="(item,index) in listBut" :key="index">{{ item }}</el-button>
</VueDraggable>
</div>
</div>
</template>
<script setup>
import { reactive, ref } from 'vue'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
// import { VueDraggable } from 'vue-draggable-plus'
const dialogForm = ref(false)
const title = ref("新增")
const init = (type, row) => {
dialogForm.value = true
if (type == 'edit') {
title.value = "编辑"
} else if (type == 'add') {
title.value = "新增"
} else {
title.value = "详情"
}
}
const loading = ref(false)
// 新增
const submit = () => {
loading.value = true
}
const listBut = ref(["物品", "人员", "组织", "次数", "事件", "地点", "整情"])
// 关闭
const close = () => {
dialogForm.value = false
}
const onUpdate = (evt) => {
console.log(evt)
}
// 新增
const onAdd = (evt) => {
console.log(evt)
}
// 删除
const remove = (evt) => {
console.log(evt)
}
defineExpose({
init
})
</script>
<style lang="scss" scoped></style>

View File

@ -0,0 +1,209 @@
<template>
<div>
<div class="titleBox">
<PageTitle title="预警列表">
<el-button type="primary" size="small" @click="yzSsyjpzMxgzxl()">新增</el-button>
<!-- <el-button type="primary" size="small" :disabled="ids.length == 0" @click="deleteRule(ids)">批量删除</el-button> -->
<el-button size="small" @click="retenHome()">返回</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #tjName="{ row }">
<div class="flex one_text_detail" v-if="row.tj">{{ ` ${row.tj} ${row.cs}` }} </div>
</template>
</MyTable>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
</div>
</template>
<script setup>
import { ElMessage } from "element-plus";
import emitter from "@/utils/eventBus.js";
import { deleteYjgzpz,getYjgzpzMxgzxl,getYjxxPageList ,getSsyjpzMxgzxl} from "@/api/model";
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 { reactive, ref, onMounted, getCurrentInstance } from "vue";
const props = defineProps({
item: {
type: Object,
default: () => ({})
}
})
const { proxy } = getCurrentInstance();
const { D_BB_AJLB,D_BZ_WPLX} = proxy.$dict("D_BB_AJLB","D_BZ_WPLX")
const regulation = ref(null)
const queryFrom = ref({})
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{
label: "时间",
prop: "startTime",
placeholder: "请选择时间",
showType: "daterange"
},
]);
const pageData = reactive({
tableData: [],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false
},
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
controlsWidth: 300,
tableColumn: [
{ label: "预警时间", prop: "gzmc", showOverflowTooltip: true },
{ label: "类型", prop: "jssj", showOverflowTooltip: true, showSolt: true },
{ label: "内容", prop: "kssj", showOverflowTooltip: true, showSolt: true },
]
});
onMounted(() => {
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value.startTime = val.startTime&&val.startTime.length > 0 ? val.startTime[0] : '';
queryFrom.value.endTime = val.startTime&&val.startTime.length > 0 ? val.startTime[1] : '';
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageCurrent = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
//
// 获取列表
const getList = () => {
const promes = {
...pageData.pageConfiger,
...queryFrom.value,
mxid:props.item.id,
}
getYjxxPageList(promes).then((res) => {
pageData.tableData = res.records
pageData.total = res.total
});
};
const retenHome = () => {
emitter.emit('changeModel', { name: '研判首页', row: {} });
}
const openAddRule = (type, item, row) => {
regulation.value.init(type, item, row)
}
const ids = ref([])
const chooseData = (val) => {
ids.value = val.map(item => item.id)
}
const deleteRule = (row) => {
proxy.$confirm('是否删除该规则, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let list
if (Array.isArray(row)) {
list = ids.value
} else {
list =[row]
}
deleteYjgzpz({ids:list}).then(() => {
ElMessage.success("删除成功");
getList()
})
}).catch((err) => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
const yzSsyjpzMxgzxl = (params) => {
getYjgzpzMxgzxl({id:params}).then((res) => {
console.log(res);
})
}
const jsonParse = (val) => {
if (val) {
return JSON.parse(val)
}
}
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.checkbox-group {
display: flex;
gap: 20px;
}
.basic-info {
display: flex;
gap: 15px;
.avatar {
width: 80px;
height: 80px;
overflow: hidden;
border-radius: 4px;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.info-list {
display: flex;
flex-direction: column;
gap: 5px;
}
}
.control-buttons {
display: flex;
gap: 10px;
}
</style>

View File

@ -11,48 +11,72 @@
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"> </Search>
</div>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }" v-loading="loading">
<li class="cntItem" v-for="(it, idx) in 10" :key="idx">
<div class="ww100" @click.stop="openAddModel('detail', it)"><img class="ww100" style="height: 168px;" src="@/assets/images/mxbg.jpg" alt=""></div>
<div class="foot">
<span class="ml10 pointer" style="color:#027ff0 ;" @click="openAddRule"><el-icon style="top: 2px;">
<Document />
</el-icon>查看规则</span>
<span class="ml10 pointer" style="color:#027ff0 ;" @click="openAddModel('edit', it)"><el-icon
style="top: 2px;">
<Edit />
</el-icon>编辑</span>
<span class="ml10 pointer" style="color:#f4ac47 ;"><el-icon style="top: 2px;">
<Files />
</el-icon>删除</span>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }"
v-loading="loading">
<li class="model-card" v-for="(it, idx) in list" :key="idx">
<div class="model-info">
<div class="model-name">
<strong>模型名称</strong>{{ it.mxmc }}
</div>
<div class="model-type flex">
<strong>模型类型</strong> <DictTag :tag="false" :value="it.mxlx" :options="D_MXGL_MXLX" />
</div>
</div>
<div class="model-image-container" @click="openYjList(it)">
<img class="model-image"
src="@/assets/images/mxbg.jpg" alt="">
</div>
<div class="model-actions">
<span class="action-btn action-btn-view" @click.stop="openAddRule('', it)">
<el-icon class="action-icon"><Document /></el-icon>查看规则
</span>
<span class="action-btn action-btn-edit" @click.stop="openAddModel('edit', it)">
<el-icon class="action-icon"><ChatDotSquare /></el-icon>编辑
</span>
<span class="action-btn action-btn-edit" @click.stop="openAddModel('detail', it)">
<el-icon class="action-icon"><Edit /></el-icon>详情
</span>
<span class="action-btn action-btn-delete" @click.stop="delDictItem(it.id)">
<el-icon class="action-icon"><Files /></el-icon>删除
</span>
</div>
</li>
<div class="ww100 flex just-center">
<div class="empty-container">
<MOSTY.Empty :show="!loading && list.length <= 0"></MOSTY.Empty>
</div>
<div class="tc ww100 mb4" style="color: #a29f9f;" v-if="total == list.length && total > 0">暂时没有数据了</div>
<div class="no-more-data" v-if="total == list.length && total > 0">暂时没有数据了</div>
</ul>
</div>
<AddModel ref="addModel" />
<Regulation ref="regulation" />
<AddModel ref="addModel" :dict="{ D_MXGL_MXLX }" @getLits="getLits" />
</template>
<script setup>
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import { getPageList, deleteEntity } from '@/api/model.js'
import emitter from "@/utils/eventBus.js";
import { CirclePlus } from '@element-plus/icons-vue'
import * as MOSTY from "@/components/MyComponents/index";
import Search from "@/components/aboutTable/Search.vue";
import { qcckPost } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance, watch, defineEmits } from "vue";
import AddModel from "./addModel.vue";
import Regulation from "./regulation.vue";
import AddModel from "../components/AddModel/addModel";
const emit = defineEmits(['change'])
const { proxy } = getCurrentInstance();
const { D_MXGL_MXLX ,D_BZ_RYBQ} = proxy.$dict("D_MXGL_MXLX","D_BZ_RYBQ")
const searchBox = ref(); //搜索框
const show = ref(false)
const listHeight = ref()
const SSYJ = '02'
const YJGZ='01'
const searchConfiger = ref([
{ label: "模型名称", prop: "ypMc", placeholder: "请输入模型名称", showType: "input" },
{ label: "模型类型", prop: "ypLx", placeholder: "请输入模型类型", showType: "input" },
{ label: "模型名称", prop: "mxmc", placeholder: "请输入模型名称", showType: "input" },
{
label: "模型类型",
prop: "mxlx",
placeholder: "请选择模型类型",
showType: "select",
options: D_MXGL_MXLX
},
]);
const PaginationConfig = reactive({
pageCurrent: 1,
@ -86,7 +110,7 @@ const getLits = () => {
}
loading.value = true;
qcckPost(params, '/mosty-gsxt/tsyp/selectPage').then(res => {
getPageList(params).then(res => {
let arr = res.records || [];
list.value = PaginationConfig.pageCurrent == 1 ? arr : list.value.concat(arr);
total.value = res.total;
@ -105,16 +129,44 @@ const tabHeightFn = () => {
tabHeightFn();
};
};
const delDictItem = (id) => {
proxy.$confirm('是否删除该模型, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
deleteEntity({ ids: [id] }).then(res => {
proxy.$message.success("删除成功!")
getLits()
})
}).catch(() => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
// 打开弹窗
const addModel = ref(null)
const openAddModel = (type, row) => {
addModel.value.init(type, row)
}
// 打开规则弹窗
const regulation = ref(null)
const openAddRule = (type, row) => {
regulation.value.init(type, row)
switch (row.mxlx) {
case SSYJ:
emitter.emit('changeModel', {row,name:'四色预警规则'})
break;
case YJGZ:
emitter.emit('changeModel', {row,name:'预警规则'})
break;
default:
break;
}
}
const openYjList = (row) => {
emitter.emit('changeModel', {row,name:'预警列表'})
}
</script>
@ -124,7 +176,7 @@ const openAddRule = (type, row) => {
height: 100%;
margin-top: 20px;
margin-left: 10px;
border-radius: 4px;
border-radius: 8px;
box-sizing: border-box;
.btnsBox {
@ -138,29 +190,134 @@ const openAddRule = (type, row) => {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 18px;
gap: 20px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 4px;
padding: 16px;
box-sizing: border-box;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.cntItem {
width: 300px;
border: 1px solid #ccc;
color: #787878;
border-radius: 4px;
overflow: hidden;
// 模型卡片样式
.model-card {
width: 300px;
border: 1px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
background: #fff;
transition: all 0.3s ease;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
.foot {
text-align: right;
margin-top: 4px;
border-top: 1px solid #ccc;
padding: 4px;
box-sizing: border-box;
&:hover {
transform: translateY(-4px);
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
border-color: #409eff;
}
// 模型信息区域
.model-info {
padding: 16px;
background-color: #fafafa;
border-bottom: 1px solid #f0f0f0;
.model-name,
.model-type {
margin-bottom: 8px;
font-size: 14px;
color: #606266;
strong {
color: #303133;
font-weight: 500;
}
}
.model-type {
margin-bottom: 0;
}
}
// 模型图片区域
.model-image-container {
cursor: pointer;
overflow: hidden;
transition: all 0.3s ease;
.model-image {
width: 100%;
height: 168px;
object-fit: cover;
transition: transform 0.3s ease;
&:hover {
transform: scale(1.05);
}
}
}
// 操作按钮区域
.model-actions {
text-align: right;
padding: 12px 0px;
border-top: 1px solid #f0f0f0;
background-color: #fafafa;
.action-btn {
// margin-left: 12px;
justify-content: space-between;
font-size: 13px;
cursor: pointer;
transition: all 0.3s ease;
display: inline-flex;
align-items: center;
padding: 4px 8px;
border-radius: 4px;
.action-icon {
margin-right: 4px;
font-size: 14px;
}
&:hover {
opacity: 0.8;
}
}
.action-btn-view,
.action-btn-edit {
color: #409eff;
&:hover {
background-color: #ecf5ff;
}
}
.action-btn-delete {
color: #f4ac47;
&:hover {
background-color: #fff7e6;
}
}
}
}
// 空状态和无更多数据样式
.empty-container {
width: 100%;
display: flex;
justify-content: center;
padding: 40px 0;
}
.no-more-data {
width: 100%;
text-align: center;
margin-bottom: 16px;
color: #a29f9f;
font-size: 13px;
}
}
</style>

View File

@ -0,0 +1,34 @@
<template>
<div>
<YpHome v-if="showModel == '研判首页'"></YpHome>
<ModeList v-if="showModel == '四色预警规则'" :item="itemData" ></ModeList>
<EarlyWarning v-if="showModel == '预警规则'" :item="itemData" ></EarlyWarning>
<YjList v-if="showModel == '预警列表'" :item="itemData" ></YjList>
<!-- <YjDetail v-if="showModel == '预警详情'" :item="itemDetail" @change="changeModel"></YjDetail> -->
</div>
</template>
<script setup>
import YpHome from "./components/ypHome.vue";
import YjList from "./components/yjList.vue";
import ModeList from "./components/FourColor/modeList.vue";
import EarlyWarning from "./components/EarlyWarning/modeList.vue";
import emitter from "@/utils/eventBus.js";
import { onMounted, ref } from "vue";
const showModel = ref('研判首页')
const itemData=ref({})
onMounted(() => {
emitter.on('changeModel', (model) => {
showModel.value = model.name;
itemData.value=model.row;
})
})
</script>
<style lang="scss" scoped>
</style>

View File

@ -1,22 +1,39 @@
<template>
<div>
<YpHome v-if="showModel == '研判首页'" @change="changeModel"></YpHome>
<!-- <YjList v-if="showModel == '态势预警列表'" :item="itemYj" @change="changeModel"></YjList>
<YjDetail v-if="showModel == '预警详情'" :item="itemDetail" @change="changeModel"></YjDetail> -->
<YpHome v-if="showModel == '研判首页'"></YpHome>
<!-- <ModeList v-if="showModel == '四色预警规则'" :item="itemData" ></ModeList>
<EarlyWarning v-if="showModel == '预警规则'" :item="itemData" ></EarlyWarning> -->
<!-- <YjList v-if="showModel == '预警列表'" :item="itemData" ></YjList> -->
<List v-if="showModel == '四色预警规则' || showModel == '预警规则'" :item="itemData"></List>
<YjDetail v-if="showModel == '预警列表'" :item="itemData" :dict="{D_BZ_TPYJLX}"></YjDetail>
</div>
</template>
<script setup>
import YpHome from "./components/ypHome.vue";
import { onMounted, ref } from "vue";
// import YjList from "./components/yjList.vue";
import YjDetail from './components/AddModel/yjList.vue'
import List from "./components/list.vue";
// import ModeList from "./components/FourColor/modeList.vue";
// import EarlyWarning from "./components/EarlyWarning/modeList.vue";
const { proxy } = getCurrentInstance();
import emitter from "@/utils/eventBus.js";
import { onMounted, ref, getCurrentInstance } from "vue";
const { D_BZ_TPYJLX} = proxy.$dict("D_BZ_TPYJLX")
const showModel = ref('研判首页')
onMounted(()=>{
const itemData = ref({})
onMounted(() => {
emitter.on('changeModel', (model) => {
console.log(model);
showModel.value = model.name;
itemData.value = model.row;
})
})
</script>
<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>