This commit is contained in:
lcw
2025-10-09 21:33:58 +08:00
parent 93c711dca6
commit 5e18952b55
69 changed files with 421 additions and 152 deletions

View File

@ -24,7 +24,7 @@
<span style="color: #0072ff;" @click="handleClick(row)">{{ row.xwcs }}</span>
</template>
<template #bqYs="{ row }">
<DictTag :value="row.bqYs" :tag="false" :options="D_GS_SSYJ" />
<DictTag :value="row.bqys" :tag="false" :options="D_GS_SSYJ" />
</template>
<template #controls="{ row }">
<el-link type="primary">下发指令</el-link>
@ -115,7 +115,7 @@ const getList = () =>{
qcckGet(queryFrom.value,'/mosty-gsxt/yjzxXwyj/getPageList').then((res)=>{
pageData.total = res.total || 0;
pageData.tableConfiger.loading = false;
pageData.tableData = res.records || [];
// pageData.tableData = res.records || [];
}).catch(()=>{
pageData.tableConfiger.loading = false;
})

View File

@ -6,25 +6,40 @@
<span>{{ changetText(props.item.yjJb) }}</span>
</div>
<div>
<el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="props.item.yjTp"
:preview-src-list="[props.item.yjTp]" />
<el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="item.yjTp"
:preview-src-list="[item.yjTp]" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/car.png" width="65" height="80" v-if="item.yjLx == 2" />
<img src="@/assets/images/default_male.png" width="80" height="110" v-else />
</div>
</template>
</el-image>
</div>
<div>
<span class="smallbtn" @click.stop="() => { }">全息档案{{ props.item.id }}</span>
<span class="smallbtn" @click.stop="() => { }">全息档案</span>
</div>
</div>
<div class="infoBox">
<div style="height: 110px">
<div class="flex nowrap align-center just-between linItem">
<div class="wichAlian3">{{ props.item.yjRyxm }}</div>
<div>|</div>
<div class="wichAlian3">
<span v-if="item.yjLx == 2" >{{ props.item.yjClcph }}</span>
<span v-else >{{ props.item.yjRyxm }}</span>
</div>
<template v-if="item.yjLx == 1">
<div>|</div>
<div class="wichAlian">{{ IdCard(props.item.yjRysfzh, 2) }}</div>
<div>|</div>
<div class="wichAlian2"> {{ IdCard(props.item.yjRysfzh, 3) }}</div>
<div>|</div>
</template>
<div class="wichAlian3"> <span class="bqbox ml6">{{ props.item.yjbq }}</span></div>
</div>
<div class="linItem">身份证号{{ props.item.yjRysfzh }}</div>
<div class="linItem" v-if="item.yjLx == 1">身份证号{{ props.item.yjRysfzh }}</div>
<div class="linItem">预警时间{{ props.item.yjSj }}</div>
<div class="linItem flex nowrap align-center just-between">预警次数{{ props.item.yjCs }}<div></div>
<div>相似度90%</div>
@ -39,7 +54,7 @@
v-if="props.item.yjJb != 10 && props.item.czzt == '03'"> 查看反馈 </span>
<div>
<span class="smllbtn" v-if="track" @click.stop="showDetail(props.item)">发送指令</span>
<span class="smllbtn" v-else @click.stop="openTrack(props.item)">历史轨迹</span>
<span class="smllbtn" v-else @click.stop="openTrack(props.item)">历史轨迹</span>
</div>
</div>
<!-- <div class="items">
@ -105,7 +120,7 @@ watch(() => props.item, (newVal) => {
console.log(newVal);
}
},{deep:true})
}, { deep: true })
const deptLevel = ref(null)
const emit = defineEmits(['showDetail'])
const showDetail = (val) => {
@ -158,9 +173,9 @@ const changetText = (type) => {
return "不关注";
}
};
const showTrack=ref(false)
const showTrack = ref(false)
const openTrack = () => {
showTrack.value=true
showTrack.value = true
};
// <!-- 虚拟触发 -->
// <!-- <el-popover ref="popoverRef" :visible="isShowVisble" :width="400" :virtual-ref="buttonRef" trigger="click" title="反馈" virtual-triggering >

View File

@ -2,7 +2,7 @@
<div class="systemBox">
<GdMap></GdMap>
<!-- 头部筛选 -->
<div class="topSearch">
<!-- <div class="topSearch">
<el-form v-model="listQuery">
<MOSTY.Select v-model="listQuery.sd" :dictEnum="search.xd" />
<MOSTY.Select v-model="listQuery.zs" :dictEnum="search.zs" />
@ -10,7 +10,7 @@
<MOSTY.Select v-model="listQuery.dz" :dictEnum="search.dz" />
</el-form>
<el-button type="primary">搜索</el-button>
</div>
</div> -->
<div class="systemBox">
<!-- 左边列表 -->
<div class="leftList">
@ -30,9 +30,10 @@
</template>
</el-input>
</div>
<!-- @click.stop="showDetail(item)" -->
<ul class="listContent noScollLine mt10" v-infinite-scroll="loadList" style="overflow: auto"
v-loading="loading">
<!-- @click.stop="showDetail(item)" -->
<li v-for="(item, index) in personList" :key="index" @click="markAbove(item)">
<YjItem :item="item" type="yj" :dic="{ D_BZ_YJCZZT }" @showDetail="showDetail"></YjItem>
</li>

View File

@ -7,8 +7,16 @@
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
<template #yjTp="{ row }">
<el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="row.yjTp"
:preview-src-list="[row.yjTp]" />
<el-image style="width: 80px; height:120px" :src="row.yjTp" :preview-src-list="[row.yjTp]" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/car.png" width="65" height="70" v-if="row.yjLx == 2"/>
<img src="@/assets/images/default_male.png" width="65" height="70" v-else/>
</div>
</template>
</el-image>
<!-- <el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="row.yjTp"
:preview-src-list="[row.yjTp]" /> -->
</template>
<template #nl="{ row }">
{{ IdCard(row.yjRysfzh, 3) }}
@ -61,7 +69,7 @@ const pageData = reactive({
}, //分页
controlsWidth: 160, //操作栏宽度
tableColumn: [
{ label: "人像照片", prop: "yjTp", showSolt: true },
{ label: "预警图片", prop: "yjTp", showSolt: true },
{ label: "姓名", prop: "yjRyxm" },
{ label: "年龄", prop: "nl", showSolt: true },
{ label: "性别", prop: "xb", showSolt: true },

View File

@ -44,8 +44,19 @@
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="500"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth">
<template #yjTp="{ row }">
<el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="row.yjTp"
:preview-src-list="[row.yjTp]" />
<el-image style="width: 80px; height:120px" :src="row.yjTp" :preview-src-list="[row.yjTp]" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/car.png" width="65" height="70" v-if="row.yjLx == 2"/>
<img src="@/assets/images/default_male.png" width="65" height="70" v-else/>
</div>
</template>
</el-image>
<!-- <el-image :preview-teleported="true" style="width: 80px; height: 110px" :src="row.yjTp"
:preview-src-list="[row.yjTp]" /> -->
</template>
<template #nl="{ row }">
{{ IdCard(row.yjRysfzh, 3) }}
@ -133,7 +144,7 @@ const pageData = reactive({
}, //分页
controlsWidth: 160, //操作栏宽度
tableColumn: [
{ label: "人像照片", prop: "yjTp", showSolt: true },
{ label: "预警图片", prop: "yjTp", showSolt: true },
{ label: "姓名", prop: "yjRyxm" },
{ label: "年龄", prop: "nl", showSolt: true },
{ label: "性别", prop: "xb", showSolt: true },
@ -211,42 +222,42 @@ const exportExcel = () => {
const handleExport = () => {
// 创建一个临时表格用于导出
const tempTable = document.createElement('table');
// 创建表头
const thead = document.createElement('thead');
const headerRow = document.createElement('tr');
// 添加序号列
const indexTh = document.createElement('th');
indexTh.textContent = '序号';
headerRow.appendChild(indexTh);
// 添加其他列头
pageData.tableColumn.forEach(column => {
const th = document.createElement('th');
th.textContent = column.label;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
tempTable.appendChild(thead);
// 创建表体
const tbody = document.createElement('tbody');
// 处理表格数据
pageData.tableData.forEach((row, index) => {
const tr = document.createElement('tr');
// 添加序号
const indexTd = document.createElement('td');
indexTd.textContent = index + 1;
tr.appendChild(indexTd);
// 添加其他单元格数据
pageData.tableColumn.forEach(column => {
const td = document.createElement('td');
// 处理自定义插槽的情况
if (column.showSolt) {
if (column.prop === 'yjTp') {
@ -269,15 +280,15 @@ const handleExport = () => {
// 普通字段
td.textContent = row[column.prop] || '';
}
tr.appendChild(td);
});
tbody.appendChild(tr);
});
tempTable.appendChild(tbody);
// 执行Excel导出
let xlsxParam = { raw: true };
let wb = XLSX.utils.table_to_book(tempTable, xlsxParam);
@ -286,7 +297,7 @@ const handleExport = () => {
bookSST: true,
type: "array"
});
// 保存文件
try {
const exportTime = new Date().toLocaleString('zh-CN').replace(/\//g, '-').replace(/:/g, '-');

View File

@ -1,7 +1,17 @@
<template>
<div class="warning-card ">
<div class="warning-image flex">
<img :src="item.yjTp" width="65" height="70" />
<el-image style="width: 65px; height: 70px" :src="item.yjTp" :preview-src-list="[item.yjTp]" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/car.png" width="65" height="70" v-if="item.yjLx == 2"/>
<img src="@/assets/images/default_male.png" width="65" height="70" v-else/>
</div>
</template>
</el-image>
<div class="ml10 warning-info">
<div class="flex just-between align-center">
<div class="flex align-center mt4" v-if="item.yjLx == 2">
@ -71,7 +81,7 @@ const changeBG = (str) => {
box-sizing: border-box;
.warning-image {
//
//
// width: 80px;
// height: 100px;
@ -84,7 +94,7 @@ const changeBG = (str) => {
.warning-info {
flex: 1;
.tag {
padding: 1px 6px;
background: #0072FF;
@ -98,6 +108,27 @@ const changeBG = (str) => {
background: #e9e9e9;
}
}
// 图片错误状态样式
.image-slot {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
background-color: #f5f5f5;
border-radius: 4px;
}
// 主图错误和预览图错误的样式
.image-slot.error,
.image-slot.viewer-error {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.warning-boder{
border-bottom: 2px dashed #0958b2;
}

View File

@ -1,7 +1,15 @@
<template>
<div class="warning-card flex align-center" :class="changeBG(item.yjJb)">
<div class="warning-image">
<img :src="item.yjTp" width="80" height="120" alt="" />
<el-image style="width: 80px; height:120px" :src="item.yjTp" :preview-src-list="[item.yjTp]" show-progress>
<template #error>
<div class="image-slot error">
<img src="@/assets/images/car.png" width="65" height="70" v-if="item.yjLx == 2"/>
<img src="@/assets/images/default_male.png" width="65" height="70" v-else/>
</div>
</template>
</el-image>
<!-- <img :src="item.yjTp" width="80" height="120" alt="" /> -->
</div>
<div class="warning-info">
<div class="flex just-between align-center">

View File

@ -54,33 +54,33 @@ function startAutoTooltip() {
if (!props.autoTooltip) {
return;
}
if (!props.data) {
// console.warn('自动提示框未启动 - 缺少数据');
return;
}
if (!props.data.xDate || props.data.xDate.length === 0) {
// console.warn('自动提示框未启动 - xDate数据为空');
return;
}
if (!props.data.list || props.data.list.length === 0) {
// console.warn('自动提示框未启动 - list数据为空');
return;
}
if (!myChart.value) {
// console.warn('自动提示框未启动 - 图表实例不存在');
return;
}
// 清除之前的定时器
stopAutoTooltip();
const dataLength = props.data.xDate.length;
currentTooltipIndex.value = 0;
// console.log(`开始自动提示框循环 - 数据长度: ${dataLength}, 间隔: ${props.tooltipInterval}ms`);
// console.log('数据预览:', {
// xDate: props.data.xDate.slice(0, 3),
@ -88,7 +88,7 @@ function startAutoTooltip() {
// firstSeriesName: props.data.list[0]?.name,
// firstSeriesValueCount: props.data.list[0]?.value?.length
// });
tooltipTimer.value = setInterval(() => {
try {
// 检查图表实例是否仍然存在
@ -97,18 +97,18 @@ function startAutoTooltip() {
stopAutoTooltip();
return;
}
// 检查是否暂停
if (isPaused.value) {
// console.log('提示框循环已暂停');
return;
}
// 先隐藏当前提示框
myChart.value.dispatchAction({
type: 'hideTip'
});
// 延迟一点时间再显示新的提示框,确保动画效果
setTimeout(() => {
if (myChart.value && !isPaused.value) {
@ -116,21 +116,21 @@ function startAutoTooltip() {
// 获取当前数据点信息
const currentData = props.data.xDate[currentTooltipIndex.value];
const currentValues = props.data.list.map(series => series.value[currentTooltipIndex.value]);
// 验证数据有效性
if (currentData === undefined) {
// console.error(`数据索引 ${currentTooltipIndex.value} 超出范围`);
stopAutoTooltip();
return;
}
// 显示当前索引的提示框 - 使用第一个系列
myChart.value.dispatchAction({
type: 'showTip',
seriesIndex: 0,
dataIndex: currentTooltipIndex.value
});
// console.log(`✓ 显示提示框 [${currentTooltipIndex.value}/${dataLength-1}] - ${currentData}:`, currentValues);
} catch (error) {
// console.error('显示提示框时出错:', error);
@ -139,7 +139,7 @@ function startAutoTooltip() {
}
}
}, 100);
// 更新索引,循环展示
currentTooltipIndex.value = (currentTooltipIndex.value + 1) % dataLength;
} catch (error) {
@ -147,7 +147,7 @@ function startAutoTooltip() {
stopAutoTooltip();
}
}, props.tooltipInterval);
// console.log(`✓ 自动提示框已启动 - 间隔: ${props.tooltipInterval}ms, 数据长度: ${dataLength}`);
}
@ -229,22 +229,23 @@ function lineChartFn(xDate, legend, series) {
// 获取当前数据点的所有系列信息
const dataIndex = params.dataIndex;
const categoryName = params.name;
let result = `<div style="margin-bottom: 8px; font-weight: bold; color: #00d4ff; font-size: 14px; border-bottom: 1px solid #00d4ff; padding-bottom: 4px;">${categoryName}</div>`;
// 遍历所有系列,显示该数据点的所有信息
if (props.data && props.data.list) {
props.data.list.forEach((seriesData, index) => {
const value = seriesData.value[dataIndex];
const color = seriesData.color ? seriesData.color[0] : '#00d4ff';
result += `<div style="margin: 4px 0; display: flex; align-items: center;">
<span style="display: inline-block; width: 12px; height: 12px; background: ${color}; border-radius: 50%; margin-right: 8px; border: 1px solid rgba(255,255,255,0.3);"></span>
<span style="color: #fff; margin-right: 8px; min-width: 60px;">${seriesData.name}:</span>
<span style="display: inline-block; width: 12px; height: 12px; background: ${color};
border-radius: 50%; margin-right: 8px; border: 1px solid rgba(255,255,255,0.3);"></span>
<span style="color: #fff; margin-right: 8px; min-width: 60px;">${categoryName}:</span>
<span style="color: #00d4ff; font-weight: bold; font-size: 14px;">${value}</span>
</div>`;
});
}
return result;
},
// 确保提示框能够正确显示
@ -256,17 +257,17 @@ function lineChartFn(xDate, legend, series) {
// 计算提示框位置,避免超出边界
let x = point[0] + 15;
let y = point[1] - 10;
// 如果右侧空间不够,显示在左侧
if (x + size.contentSize[0] > size.viewSize[0]) {
x = point[0] - size.contentSize[0] - 15;
}
// 如果上方空间不够,显示在下方
if (y < 0) {
y = point[1] + 20;
}
return [x, y];
}
},
@ -316,30 +317,30 @@ function lineChartFn(xDate, legend, series) {
],
series: series
};
option && myChart.value.setOption(option);
// 添加鼠标事件监听
if (props.pauseOnHover) {
myChart.value.on('mouseover', () => {
pauseAutoTooltip();
});
myChart.value.on('mouseout', () => {
resumeAutoTooltip();
});
}
// 启动自动循环展示
if (props.autoTooltip) {
setTimeout(() => {
startAutoTooltip();
}, 1000); // 延迟1秒启动确保图表完全渲染
}
window.onresize = function () {
window.onresize = function () {
if (myChart.value) {
myChart.value.resize();
myChart.value.resize();
}
};
}

View File

@ -85,7 +85,7 @@
</div>
</ul>
</div>
</div>
</template>
@ -131,7 +131,7 @@ const router = useRouter();
const route = useRoute();
const btns = reactive({
rightBtn: ["四色预警", "重点人群"],
leftBtn: ["预警布控",'研判首页'],
leftBtn: ["智能布控",'研判首页'],
moreBtn:['退出登录',]
});
const btnsActive = ref("");
@ -159,8 +159,8 @@ const handleBtns = (val) => {
btnsActive.value = val;
switch (val) {
case "预警布控":
router.push("/warningControl");
case "智能布控":
router.push("/DeploymentArea");
break;
case "四色预警":
router.push("/IdentityManage");
@ -172,8 +172,9 @@ const handleBtns = (val) => {
router.push("/editPassword");
break;
case "重点人群":
const NPShref = router.resolve({ path: '/KeyPopulations', query: {}});
window.open(NPShref.href, "_blank");
router.push("/mpvPeo");
// const NPShref = router.resolve({ path: '/KeyPopulations', query: {}});
// window.open(NPShref.href, "_blank");
break;
case "退出登录":
window.opener = null;

View File

@ -44,6 +44,7 @@ onMounted(()=>{
})
onUnmounted(() => {
if (intervalId.value) clearInterval(intervalId.value)// 清理定时器
stopAutoScroll()
})
// 自动滚动
const autoScroll = () => {

View File

@ -3,7 +3,7 @@
<script setup>
import { ref, onMounted } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { useRoute } from "vue-router";
import {
setItem
} from "@/utils/storage";
@ -11,16 +11,19 @@ const loginDialog = ref(false);
const deptList = ref([]);
const store = useStore();
function redirectAuth() {
let token = location.hash.slice(20) || null;
// 从路由参数中获取token
const route = useRoute();
let token = route.query.token || null;
if (token != null) {
token = token.replace(/\ +/g, "");
setItem("SSOTOKEN", token)
handleLogin({ token: token});
} else {
window.location.href = `http://155.240.22.102:40992`;
window.location.href = `http://155.240.22.188:9020`;
}
}
const handleLogin = (e) => {
store.dispatch("user/oatuhLogin", e).then((res) => {
// 登录后操作

View File

@ -0,0 +1,69 @@
<template>
<div class="sso-redirect-container">
<div class="loading-wrapper">
<div class="loading-text">正在跳转...</div>
</div>
</div>
</template>
<script setup>
import { onMounted } from "vue";
import { useRoute,useRouter } from "vue-router";
import { getItem, setItem } from "@/utils/storage";
const route = useRoute();
const router = useRouter();
// 获取路由参数url
const getUrlParam = () => {
return route.query.url || '';
};
// 检查token并进行跳转
const checkTokenAndRedirect = () => {
// 获取路由参数url
const redirectUrl = getUrlParam();
// 检查localStorage中是否存在token
const token = getItem('SSOTOKEN') || getItem('token');
if (token) {
// 如果存在token直接跳转到url参数指定的地址
if (redirectUrl) {
router.push(redirectUrl);
} else {
// 如果没有url参数跳转到首页
router.push("/");
}
} else {
setItem("FounderUrl", redirectUrl);
// 如果不存在token跳转到SSO登录地址
window.location.href = "http://192.168.0.231:8006/mosty-api/mosty-base/fzSsoLogin";
}
};
// 页面挂载时执行检查
onMounted(() => {
checkTokenAndRedirect();
});
</script>
<style scoped>
.sso-redirect-container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
}
.loading-wrapper {
text-align: center;
}
.loading-text {
font-size: 16px;
color: #666;
margin-top: 20px;
}
</style>

View File

@ -0,0 +1,83 @@
<template></template>
<script setup>
import { ref, onMounted } from "vue";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import {
getCookie
} from "@/utils/cookie";
import {
setItem
} from "@/utils/storage";
import { getSessionForSfzh, idCardNoLogin } from "@/api/user-manage";
import {
setTimeStamp
} from "@/utils/auth";
const loginDialog = ref(false);
const deptList = ref([]);
const store = useStore();
function redirectAuth() {
handleLogin();
}
const handleLogin = (e) => {
// 先尝试获取cookie中的clientKey
const token = getCookie("clientKey");
if (token) {
// 使用clientKey获取会话信息
getSessionForSfzh({ cookie: token }).then((res) => {
// 使用获取到的idEntityCard进行免登
idCardNoLogin({
idCardNo: res
}).then((resIdCard) => {
// 登录成功后设置token和用户信息到store
store.commit("user/setToken", resIdCard.jwtToken);
store.commit("user/setDeptList", resIdCard.deptList);
store.commit("user/setUserName", resIdCard.userName);
store.commit("user/setMenuList", resIdCard.menuList);
store.commit("user/setUserInfo", {
token: resIdCard.jwtToken,
permission: {
buttonPermission: ["removeTest", "viewTest"],
menus: resIdCard.menuCodeSet
},
menuList: resIdCard.menuList,
deptList: resIdCard.deptList
});
// 保存用户信息到本地存储
setItem("USERNAME", resIdCard.userName);
setItem("SFRH", resIdCard.sfrh);
setItem("USERID", resIdCard.userId);
setItem("menusPermission", resIdCard.menuCodeSet);
setItem("idEntityCard", resIdCard.idEntityCard);
setItem("deptId", resIdCard.deptList);
// 保存登录时间
setTimeStamp();
// 重定向到首页
setTimeout(() => {
window.location.hash = "/";
}, 1000);
}).catch((error) => {
console.error("免登失败:", error);
// 免登失败时重定向到登录页面
// window.location.hash = "/login";
});
}).catch((error) => {
console.error("获取会话信息失败:", error);
// 获取会话信息失败时重定向到登录页面
// window.location.hash = "/login";
});
} else {
console.error("没有找到clientKey cookie");
// 没有cookie时重定向到登录页面
window.location.hash = "/login";
}
};
onMounted(() => {
redirectAuth();
});
</script>
<style></style>