更新目录

This commit is contained in:
2025-07-10 20:07:17 +08:00
parent a487cf59a1
commit 529089b73c
4 changed files with 10 additions and 32 deletions

View File

@ -0,0 +1,119 @@
<template>
<div class="dialog" v-if="dialogForm">
<div class="head_box">
<span class="title">网上会议室{{ title }} </span>
<div>
<el-button type="primary" size="small" :loading="loading" @click="submit" >保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="form_cnt">
<FormMessage v-model="listQuery" :formList="formData" ref="elform" :rules="rules">
<template #glxsmc>
<el-input placeholder="请选择关联线索" @click="chooseVisiblexS = true" readonly v-model="listQuery.glxsmc"></el-input>
</template>
<template #chryList>
<el-input placeholder="请选择参会人员" @click="chooseVisible = true" readonly v-model="listQuery.rymc"></el-input>
</template>
</FormMessage>
</div>
</div>
<ChooseUser v-model="chooseVisible" :Single="false" @choosedUsers="handleUserSelected" :roleIds="roleIds" />
<Xslist v-model="chooseVisiblexS" @choosed="choosed" :roleIds="roleIdsxs"></Xslist>
</template>
<script setup>
import ChooseUser from "@/components/MyComponents/ChooseUser/index.vue";
import Xslist from '@/components/MyComponents/ChooseXs/index.vue'
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
import { ref, defineExpose, reactive, defineEmits, getCurrentInstance, } from "vue";
const emit = defineEmits(["updateDate"]);
const roleIds = ref([]); //角色id
const chooseVisible = ref(false);
const roleIdsxs = ref([]); //角色id
const chooseVisiblexS = ref(false);
const { proxy } = getCurrentInstance();
const dialogForm = ref(false); //弹窗
const rules = reactive({
hskssj: [{ required: true, message: "请选择会商开始时间", trigger: "change" }],
hsjssj: [{ required: true, message: "请选择会商结束时间", trigger: "change" }],
hsnr: [{ required: true, message: "请输入会商内容", trigger: "blur" }],
hsbt: [{ required: true, message: "请输入会商标题", trigger: "blur" }],
glxsmc: [{ required: true, message: "请选择关联线索", trigger: "change" }],
chryList: [{ required: true, message: "请选择参会人员", trigger: "change" }],
});
const formData = ref([
{ label: "会商开始时间", prop: "hskssj", type: "datetime" },
{ label: "会商结束时间", prop: "hsjssj", type: "datetime" },
{ label: "会商内容", prop: "hsnr", type: "textarea", width: "100%" },
{ label: "关联线索", prop: "glxsmc", type: "slot", },
{ label: "会商标题", prop: "hsbt", type: "input" },
{ label: "参会人员", prop: "chryList", type: "slot" ,width:'100%'},
]);
const listQuery = ref({}); //表单
const loading = ref(false);
const elform = ref();
const title = ref("");
// 初始化数据
const init = (type, row) => {
dialogForm.value = true;
title.value = type == "add" ? "新增" : "编辑";
if (row) getDataById(row.id);
};
// 根据id查询详情
const getDataById = (id) => {
qcckGet({id}, "/mosty-gsxt/wshs/selectByid").then((res) => {
res.rymc = res.chryList ? res.chryList.map(v=>v.chryxm).join(","):'';
res.chryList = res.chryList ? res.chryList.map(item => item.chryid) : [];
roleIds.value = res.chryList;
roleIdsxs.value = res.glxsid ? [res.glxsid] : [];
listQuery.value = res;
});
};
const handleUserSelected = (userData) => {
roleIds.value = userData.map(item => item.id);
listQuery.value.chryList = userData.map(item => item.id)
listQuery.value.rymc = userData.map(item => item.userName).join("、");
};
const choosed = (data) => {
listQuery.value.glxsmc = data[0].xsMc;
listQuery.value.glxsid = data[0].id;
roleIdsxs.value = data.map(item => item.id);
};
// 提交
const submit = () => {
elform.value.submit((data) => {
let url = title.value == "新增" ? "/mosty-gsxt/wshs/add" : "/mosty-gsxt/wshs/update";
let params = { ...data };
loading.value = true;
qcckPost(params, url).then(() => {
loading.value = false;
proxy.$message({ type: "success", message: title.value + "成功" });
emit("updateDate");
close();
}).catch(() => {loading.value = false;});
});
};
// 关闭
const close = () => {
listQuery.value = {};
roleIds.value = [];
roleIdsxs.value = [];
dialogForm.value = false;
loading.value = false;
};
defineExpose({ init });
</script>
<style lang="scss" scoped>
@import "~@/assets/css/layout.scss";
@import "~@/assets/css/element-plus.scss";
</style>

View File

@ -0,0 +1,296 @@
<template>
<div class="titleBox">
<PageTitle title="网上会议室">
<el-button type="primary" @click="addEdit('add', '')">
<el-icon style="vertical-align: middle"><CirclePlus /></el-icon>
<span style="vertical-align: middle">新增</span>
</el-button>
</PageTitle>
</div>
<!-- 搜索 -->
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<!-- 表格 -->
<div class="tabBox">
<ul class="list noScollLine" v-loading="pageData.loading">
<li class="list-item" v-for="(item, index) in pageData.list" :key="`tableData${index}`">
<div class="top">
<div class="title ellipsis">{{ item.hsbt }}</div>
<div class="info h20 ellipsis">会商内容{{ item.hsnr }}</div>
<div class="info h20 ellipsis">关联线索{{ item.glxsmc }}</div>
<div class="info h20 ellipsis">涉及人员{{ item.sjry }}</div>
<div class="info h20 ellipsis">会商处置意见{{ item.czyj }}</div>
<div class="info h20 ellipsis">会议时间{{ item.hskssj }} - {{ item.hsjssj }}</div>
</div>
<div class="mid">
<div class="left">
<div class="title ellipsis">参会人员{{ item.chry }}</div>
<div class="desc">
<div class="info ellipsis" v-for="(el, i) in item.xsplList" :key="i">{{ i + 1 }}{{ el.plnr }}</div>
</div>
</div>
<div class="right">
<el-button type="primary" size="small" @click="joinMeeting(item)">加入会议</el-button>
<el-button type="primary" size="small">反馈情况</el-button>
<el-button type="primary" size="small">处置下发</el-button>
</div>
</div>
<div class="bottom">
<el-popover placement="top" :visible="item.visible" :width="400" trigger="click">
<template #reference>
<el-link type="primary"><el-icon><ChatDotSquare /></el-icon>评论</el-link>
</template>
<MOSTY.Other filterable style="width: 100%;" v-model="comments" type="textarea" rows="3" clearable placeholder="发表评论"/>
<div class="mt10 flex just-center">
<el-button size="small" type="primary" @click.stop="handleSumbit(item)">发送</el-button>
</div>
</el-popover>
<el-link type="primary" ><el-icon><VideoPlay /></el-icon>会议回放</el-link>
<el-link type="primary" @click="addEdit('edit', item)"><el-icon><Edit /></el-icon>编辑</el-link>
<el-link type="danger" @click="delDictItem(item.id)"><el-icon><Delete /></el-icon>删除</el-link>
</div>
</li>
<MOSTY.Empty :show="!pageData.loading && pageData.list.length <= 0"></MOSTY.Empty>
</ul>
<Pages
@changeNo="changeNo"
@changeSize="changeSize"
:tableHeight="pageData.tableHeight"
:pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"
></Pages>
</div>
<!-- 详情 -->
<DetailForm ref="detailDiloag" @updateDate="getList" />
</template>
<script setup>
import * as MOSTY from "@/components/MyComponents/index";
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import Search from "@/components/aboutTable/Search.vue";
import DetailForm from "./components/detailForm.vue";
import { qcckGet, qcckPost, qcckDelete } from "@/api/qcckApi.js";
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
const detailDiloag = ref();
const searchBox = ref(); //搜索框
const searchConfiger = ref([
{
label: "会议主题",
prop: "hsbt",
placeholder: "请输入会议主题",
showType: "input"
},
{
label: "会议时间",
prop: "daterange",
showType: "datetimerange"
},
]);
const comments = ref(''); // 评论内容
const queryFrom = ref({});
const pageData = reactive({
list: [],
loading: false,
total: 0,
pageConfiger: {
pageSize: 20,
pageCurrent: 1
},
});
onMounted(() => {
getList();
tabHeightFn();
});
// 搜索
const onSearch = (val) => {
queryFrom.value = { ...val };
if (val.daterange && val.daterange.length > 0) {
queryFrom.value.startTime = val.daterange[0];
queryFrom.value.endTime = val.daterange[1];
} else {
queryFrom.value.startTime = '';
queryFrom.value.endTime = '';
}
pageData.pageConfiger.pageCurrent = 1;
getList();
};
const changeNo = (val) => {
pageData.pageConfiger.pageNum = val;
getList();
};
const changeSize = (val) => {
pageData.pageConfiger.pageSize = val;
getList();
};
// 获取列表
const getList = () => {
pageData.loading = true;
let data = { ...pageData.pageConfiger, ...queryFrom.value };
delete data.daterange; // 删除daterange字段
qcckGet(data,'/mosty-gsxt/wshs/selectPage').then(res=>{
let arr = res.records || [];
arr.forEach(item => {
item.chry = item.chryList ? item.chryList.map(el => el.chryxm).join('、') : '';
item.sjry = item.xsryList ? item.xsryList.map(el => el.xm).join('、') : '';
});
pageData.list = arr;
pageData.total = res.total;
pageData.loading = false;
}).catch(()=>{ pageData.loading = false; })
};
// 提交评论
const handleSumbit = (item) => {
if (!comments.value) return proxy.$message({ type: "warning", message: "评论内容不能为空" });
proxy.$message({ type: "success", message: "评论已发送" });
qcckPost({id:item.id,plnr:comments.value},'/mosty-gsxt/wshs/addWshyPl').then((res)=>{
getList();
item.visible = false; // 关闭评论弹窗
comments.value = ''; // 清空评论内容
})
};
// 加入会议
const joinMeeting = (item) => {
qcckPost({id:item.id},'/mosty-gsxt/wshs/addWshyRy').then((res)=>{
getList();
})
};
// 删除
const delDictItem = (id) =>{
proxy.$confirm("确定要删除", "警告", {type: "warning"}).then(() => {
qcckPost({id},'/mosty-gsxt/wshs/delete').then(()=>{
proxy.$message({ type: "success", message: "删除成功" });
getList();
})
}).catch(() => {});
}
// 详情
const addEdit = (type, row) => {
detailDiloag.value.init(type, row);
};
// 表格高度计算
const tabHeightFn = () => {
pageData.tableHeight = window.innerHeight - searchBox.value.offsetHeight - 250;
window.onresize = function () {
tabHeightFn();
};
};
</script>
<style lang="scss" scoped>
.el-loading-mask {
background: rgba(0, 0, 0, 0.5) !important;
}
.tabBox {
.pageSearch {
margin-bottom: 0 !important;
.box {
align-items: center !important;
}
}
:deep(.pageSearch .box .item) {
margin-bottom: 0 !important;
}
}
.btns {
padding: 10px 20px;
}
.list {
height: calc(100% - 40px);
gap: 10px;
margin: 0 15px;
overflow: auto;
.list-item {
display: inline-block;
border: 1px solid #ccc;
height: 270px;
width: 380px;
box-sizing: border-box;
border-radius: 5px;
padding: 10px;
margin: 10px 5px;
&:hover {
border-color: rgb(124, 195, 253);
background-color: rgba(190, 233, 255, 0.582);
}
&:hover .mid {
border-color: rgb(124, 195, 253);
}
&:hover .desc {
background-color: rgb(190, 233, 255);
}
.title {
color: black;
font-size: 14px;
font-weight: 700;
margin-bottom: 5px;
}
.info {
color: #a5a1a1;
font-size: 12px;
line-height: 1.5;
}
.desc {
margin-top: 5px;
background-color: rgb(242, 242, 242);
width: 260px;
height: calc(100% - 25px);
padding: 10px;
}
.mid {
border: 1px dashed rgb(124, 195, 253);
border-left: 0;
border-right: 0;
padding: 10px 0;
display: flex;
justify-content: space-between;
.left {
width: calc(100% - 80px);
.title {
font-size: 14px;
color: black;
margin-bottom: 5px;
}
.info {
font-size: 12px;
color: #a5a1a1;
line-height: 1.5;
}
}
.right {
width: 80px;
.el-button + .el-button {
margin-left: 0;
margin-top: 5px;
}
}
}
.bottom {
display: flex;
justify-content: flex-end;
:deep(.el-link--inner) {
display: flex;
align-items: center;
gap: 2px;
}
}
}
}
</style>

View File

@ -0,0 +1,352 @@
<template>
<div class="yp—home flex">
<!-- 左边 -->
<div class="leftbox">
<div class="title">
<span v-for="idx in 3" :key="idx" :class="'sircleL'+idx" class="sircle mr5"></span>
<span class="ml10 mr10">专题统计</span>
<span v-for="idx in 3" :key="idx" :class="'sircleR'+idx" class="sircle ml5"></span>
</div>
<div class="commCnt">
<div class="hh50">
<div class="comm-title">类型统计</div>
<div class="echartsBox">
<MoreBarEcharts echartsId="cztjEcharts" :data="obj.data_lxtj"></MoreBarEcharts>
</div>
</div>
<div class="hh50">
<div class="comm-title">会商统计</div>
<div class="echartsBox">
<LineEcharts echartsId="hstjEcharts" :data="obj.data_hstj"></LineEcharts>
</div>
</div>
</div>
</div>
<!-- 右边 -->
<div class="rightbox">
<div class="title">
<span v-for="idx in 3" :key="idx" :class="'sircleL'+idx" class="sircle mr5"></span>
<span class="ml10 mr10">研判首页</span>
<span v-for="idx in 3" :key="idx" :class="'sircleR'+idx" class="sircle ml5"></span>
<el-button class="btn" type="primary">研判报告</el-button>
</div>
<div class="commCnt">
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch" :key="pageData.keyCount" />
</div>
<ul class="listBox" :style="{height:pageData.boxHeight+'px'}">
<li class="list-item" ref="listBoxRef" v-for="(it,idx) in list" :key="idx">
<div class="comm-title title-s">{{ it.title }}</div>
<div class="list-table" >
<MyTable
:tableData="it.tableList"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="it.keyCount"
:isScroll="true"
:fixed="false"
:tabelModel="it.title"
:tableConfiger="pageData.tableConfiger"
:controlsWidth="pageData.controlsWidth"
@changePage="changePage"
>
<!-- 操作 -->
<template #controls="{ row }">
<el-link type="primary" size="small">网上会商</el-link>
<el-link type="primary" size="small">处置</el-link>
</template>
</MyTable>
</div>
</li>
</ul>
</div>
</div>
</div>
</template>
<script setup>
import { qcckPost, qcckGet } from "@/api/qcckApi.js";
import MoreBarEcharts from "@/views/home/echarts/moreBarEcharts.vue";
import LineEcharts from "@/views/home/echarts/moreLineEcharts.vue";
import Search from "@/components/aboutTable/Search.vue";
import MyTable from "@/components/aboutTable/DarkTable.vue";
import { nextTick, onMounted, reactive,getCurrentInstance ,ref, watch } from 'vue';
import { set } from "lodash";
const { proxy } = getCurrentInstance();
const {D_BZ_SSZT,D_GS_XS_LY} = proxy.$dict("D_BZ_SSZT","D_GS_XS_LY"); //获取字典数据
const searchBox = ref();
const listBoxRef = ref();
// 图数据
const obj = reactive({
data_lxtj:{
xData:['上访','诈骗','敲诈勒索','盗窃','涉黄','涉毒','强奸猥亵','灾害事故','自杀'],
color:[['#0DBAC5','#28EEBF'],['#F06C0D','#EEB416']],
labelColor:'#000',
list:[
{label:'总数',val:[30,20,10,60,50,60,35,45,20]},
]
},
data_hstj:{
xData:['上访','诈骗','敲诈勒索','盗窃','涉黄','涉毒','强奸猥亵','灾害事故','自杀'],
color:['#0386FB','#00FFFF'],
labelColor:'#000',
list:[
{label:'总数',val:[30,20,10,60,50,60,35,45,20]},
]
}
})
// 搜索
const searchConfiger = ref([
{ label: "线索来源", prop: 'qbLy', placeholder: "请选择线索来源", showType: "select",options:D_GS_XS_LY },
{ label: "线索内容", prop: "xsNr", placeholder: "请输入", showType: "input"},
{ label: "开始时间", prop: 'zxkssj', placeholder: "请选择开始时间", showType: "date" },
{ label: "结束时间", prop: 'zxjssj', placeholder: "请选择结束时间", showType: "date" },
])
// 每个列表对应的值
const list = ref([
// { title:'诈骗', tableList:[]},
])
// 列表公用
const pageData = reactive({
tableColumn:[
{ label: "线索标题", prop: "xsMc",showOverflowTooltip: true},
{ label: "线索内容", prop: "xsNr",showOverflowTooltip: true},
{ label: "涉及人数", prop: "sjrs",showOverflowTooltip: true},
{ label: "上报时间", prop: "sxsbsj",showOverflowTooltip: true},
],
keyCount: 0,
tableConfiger: {
rowHieght: 61,
showSelectType: "null",
loading: false,
showIndex:false,
rowHeight: 30,
},
controlsWidth: 120, //操作栏宽度
});
onMounted(() => {
getCount(); //获取统计数据
});
const getCount = () => {
// 获取处置状态统计
qcckPost({}, '/mosty-gsxt/qbcj/getXscjTjByXslx').then(res => {
let arr = res || [];
obj.data_lxtj.xData = arr.map(v => v.zdmc);
obj.data_lxtj.list = [{ label: '总数', val: arr.map(v => v.count) }];
});
// 会商统计
qcckPost({}, '/mosty-gsxt/wshs/getWshyZttj').then(res => {
let arr = res || [];
obj.data_hstj.xData = arr.map(v => v.zdmc);
obj.data_hstj.list = [{ label: '总数', val: arr.map(v => v.count) }];
});
};
// 滚动加载
const changePage = (val) => {
list.value.forEach((item, index) => {
if(val == item.title && item.tableList.length < item.total) {
item.page++;
let params = { sszt: item.dm, pageNum: item.page, pageSize: 20, };
qcckPost(params, '/mosty-gsxt/qbcj/selectPage').then(res => {
let arr = res.records || [];
list.value[index].tableList = item.page == 1 ? arr : [...list.value[index].tableList, ...arr];
list.value[index].total = res.total;
item.keyCount++;
});
}
});
};
// 表格高度计算
const tabHeightFn = () => {
pageData.boxHeight = window.innerHeight - searchBox.value.offsetHeight - 250
nextTick(() => {
pageData.tableHeight = listBoxRef.value[0].offsetHeight - 40;
});
window.onresize = function () {
tabHeightFn();
};
};
const handleGetList = () => {
list.value.forEach((item, index) => {
let params = { sszt: item.dm, pageNum: 1, pageSize: 20 };
qcckGet(params, '/mosty-gsxt/qbcj/selectPage').then(res => {
list.value[index].tableList = res.records || [];
list.value[index].total = res.total;
item.keyCount++;
});
});
};
watch(()=>D_BZ_SSZT.value, (val) => {
let zdlist = val || [];
list.value = zdlist.map(v => ({ title: v.zdmc,dm:v.dm,keyCount:0, tableList: [],page:1,total:0 }));
if(list.value.length > 0) handleGetList();
setTimeout(() => {
tabHeightFn();
}, 400);
}, { immediate: true });
</script>
<style lang="scss" scoped>
.yphome{
width: 100%;
height: 100%;
padding-top: 15px;
box-sizing: border-box;
color: #000;
.leftbox{
width:500px;
height: 100%;
margin-right: 10px;
background: #fff;
}
.rightbox{
flex: 1 0 0;
background: #fff;
}
}
@mixin common($width: 16px,$opacity:1){
height: $width;
width: $width;
border-radius: 50%;
background: #0386FB;
opacity: $opacity;
}
// 共同
.title{
display: flex;
align-items: center;
justify-content: center;
height: 60px;
font-size: 24px;
position: relative;
.sircle{
display: inline-block;
}
.sircleL1{
@include common(8px,0.5);
}
.sircleL2{
@include common(12px,0.75);
}
.sircleL3{
@include common(16px);
}
.sircleR1{
@include common(16px);
}
.sircleR2{
@include common(12px,0.75);
}
.sircleR3{
@include common(8px,0.5);
}
.btn{
position: absolute;
top: 50%;
right: 10px;
transform: translateY(-50%);
}
}
.commCnt{
height: calc(100% - 60px);
overflow: hidden;
overflow-y: auto;
padding: 10px 20px;
box-sizing: border-box;
.comm-title{
position: relative;
font-size: 20px;
&::before{
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 78px;
height: 4px;
background: linear-gradient( 90deg, #3596F9 0%, rgba(53,150,249,0) 100%);
border-radius: 4px 4px 4px 4px;
}
}
.echartsBox{
height: calc(100% - 30px);
margin-top: 4px;
}
}
.listBox{
margin-top: 4px;
border-radius: 10px;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
overflow: hidden;
overflow-y: auto;
.list-item{
width: 49.5%;
height: calc(100% / 2 - 5px);
box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.02);
border-radius: 8px 8px 8px 8px;
border: 1px solid #E8EDF6;
padding: 4px 4px;
box-sizing: border-box;
margin-bottom: 5px;
.title-s{
font-size: 16px;
}
.list-table{
height: calc(100% - 30px);
margin-top: 5px;
}
}
.list-item:nth-child(2n+1){
margin-right: 1%;
}
}
::v-deep .searchBox{
margin-bottom:0 !important;
padding: 2px !important;
}
::v-deep .el-table .table_blue_row {
background: #fff !important;
}
::v-deep .el-table th.el-table__cell{
font-size: 13px;
background: #EFF5F7;
}
::v-deep .el-table__empty-block{
width: 100%!important;
}
::v-deep .el-scrollbar__view{
border-right: none;
}
::v-deep .el-table .el-table__cell{
padding: 0;
}
::v-deep .el-table th.el-table__cell>.cell{
padding: 8px 0;
}
::v-deep .el-link {
margin: 3px;
}
</style>