fix: 优化查阅历史的事件名展示

fix: 优化详情时 历史无法查阅
This commit is contained in:
lonewolfyx 2025-01-13 14:34:12 +08:00
parent 733f5e32ad
commit 9e50f95feb
7 changed files with 100 additions and 510 deletions

View File

@ -105,3 +105,31 @@ export const getVisitTrendStatistics = (data) => {
}
})
}
// 获取本月综合统计
export const getVisitComprehensiveStatistics = () => {
return request({
method: 'get',
url: '/visiting/visit/stat',
})
}
// 根据身份证获取历史访问次数
export const getVisitHistoryCount = (data) => {
return request({
method: 'post',
url: '/visiting/visit/stat_history',
data,
isEncrypt: false
})
}
// 获取合并的历史访问记录
export const getIdCardVisitHistory = (data) => {
return request({
method: 'post',
url: '/visiting/visit/list_history',
data,
isEncrypt: false
})
}

View File

@ -1,36 +0,0 @@
<!-- ChangePasswordDialog.vue -->
<template>
<el-dialog v-model="isShowSelect" width="60%" :destroy-on-close="true">
<template #header="{ close, titleClass }">
<h4 :class="titleClass">您的密码已超过60天未修改建议修改密码以保证安全</h4>
</template>
<resetPwd @hidedialog="closeDialog"/>
</el-dialog>
</template>
<script setup>
import resetPwd from "./resetPwd.vue";
import useUserStore from '@/store/modules/user'
const userStore = useUserStore()
const isShowSelect = ref(false)
const closeDialog = async () => {
isShowSelect.value = false
// 退
// userStore.logOut().then(() => {
// location.href = '/index';
// })
}
const showDialog = async () => {
isShowSelect.value = true
}
defineExpose({showDialog})
</script>
<style scoped>
h4{margin: 10px 0;}
</style>

View File

@ -1,64 +0,0 @@
<template>
<el-form ref="pwdRef" :model="user" :rules="rules" label-width="80px">
<el-row>
<el-col :span="24">
<el-form-item label="旧密码" prop="oldPassword">
<el-input v-model="user.oldPassword" placeholder="请输入旧密码" type="password" show-password />
</el-form-item>
<el-form-item label="新密码" prop="newPassword">
<el-input v-model="user.newPassword" placeholder="请输入新密码" type="password" show-password />
</el-form-item>
<el-form-item label="确认密码" prop="confirmPassword">
<el-input v-model="user.confirmPassword" placeholder="请确认新密码" type="password" show-password/>
</el-form-item>
</el-col>
<el-col :span="20"></el-col>
<el-col :span="4" style="text-align: right;">
<el-button type="primary" @click="submit">保存</el-button>
</el-col>
</el-row>
</el-form>
</template>
<script setup>
import { updateUserPwd } from "@/api/system/user";
const { proxy } = getCurrentInstance();
const user = reactive({
oldPassword: undefined,
newPassword: undefined,
confirmPassword: undefined
});
const equalToPassword = (rule, value, callback) => {
if (user.newPassword !== value) {
callback(new Error("两次输入的密码不一致"));
} else {
callback();
}
};
const rules = ref({
oldPassword: [{ required: true, message: "旧密码不能为空", trigger: "blur" }],
newPassword: [{ required: true, message: "新密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: "长度在 5 到 20 个字符", trigger: "blur" },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }],
confirmPassword: [{ required: true, message: "确认密码不能为空", trigger: "blur" }, { required: true, validator: equalToPassword, trigger: "blur" }]
});
//
const emit = defineEmits(['hidedialog'])
/** 提交按钮 */
function submit() {
proxy.$refs.pwdRef.validate(valid => {
if (valid) {
updateUserPwd(user.oldPassword, user.newPassword).then(response => {
proxy.$modal.msgSuccess("修改成功");
emit('hidedialog', '编辑')
});
}
});
};
</script>

View File

@ -1,142 +0,0 @@
<template>
<div>
<easy-player
ref="player"
:video-url="videoUrl"
:showEnterprise="false"
style="width:400px;height:300px"
>
</easy-player>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
const videoUrl = ref("http://192.168.0.151:18000/flv/live/stream_26_0.flv");
const isPlay = ref(false);
const config = ref({
hasAudio: true,
isLive: true,
MSE: false,
WCS: false,
});
let playerInfo = null;
const playerBox = ref(null);
const playCreate = () => {
const container = playerBox.value;
const easyplayer = new EasyPlayerPro(container, {
isLive: config.value.isLive,
bufferTime: 0.2,
stretch: false,
MSE: config.value.MSE,
WCS: config.value.WCS,
hasAudio: config.value.hasAudio,
watermark: { text: { content: "easyplayer-pro" }, right: 10, top: 10 },
});
easyplayer.on("fullscreen", (flag) => {
console.log("is fullscreen", flag);
});
playerInfo = easyplayer;
};
const toggleAudio = () => {
config.value.hasAudio = !config.value.hasAudio;
if (isPlay.value) {
destroyPlayer().then(() => {
playCreate();
onPlayer();
});
}
};
const setFullscreen = () => {
if (playerInfo) playerInfo.setFullscreen(true);
};
const onPause = () => {
if (playerInfo) playerInfo.pause();
};
const onMute = () => {
if (playerInfo) playerInfo.setMute(true);
};
const onPlayer = () => {
isPlay.value = true;
setTimeout(() => {
playerInfo?.play(videoUrl.value).catch((e) => console.error(e));
}, 0);
};
const onPlayerPlayback = () => {
destroyPlayer().then(() => {
playCreate();
config.value.isLive = false;
setTimeout(() => {
playerInfo?.play(videoUrl.value).catch((e) => console.error(e));
}, 0);
});
};
const onStop = () => {
isPlay.value = false;
destroyPlayer().then(() => {
playCreate();
});
};
const onReplay = () => {
destroyPlayer().then(() => {
playCreate();
onPlayer();
});
};
const destroyPlayer = () => {
return new Promise((resolve) => {
if (playerInfo) {
playerInfo.destroy();
playerInfo = null;
}
setTimeout(() => resolve(), 100);
});
};
onMounted(() => {
playCreate();
});
onBeforeUnmount(() => {
destroyPlayer();
});
</script>
<style scoped>
/* Your styles here */
.player_container {
display: grid;
width:400px;height: 300px;
}
.player_item {
position: relative;
padding-bottom: 56%;
background-color: #000;
border: 1px #fff solid;
}
.inputs {
width: 100%;
max-width: 600px;
}
.df {
display: flex;
align-items: center;
}
</style>

View File

@ -1,202 +0,0 @@
<template>
<div>
<el-row :gutter="props.space" class="main-video">
<el-col
v-for="item in videoNum"
:key="item"
:span="getSpan(videoNum)"
class="video-container"
>
<div :id="'Player_' + item" class="video-item"></div>
<el-button
type="primary"
icon="el-icon-camera"
@click="takeSnapshot(item)"
class="snapshot-btn"
>
截屏
</el-button>
</el-col>
</el-row>
<template v-if="videoNum === 0">
<div>暂无视频数据</div>
</template>
</div>
</template>
<script setup>
import { nextTick, watchEffect, ref, onBeforeUnmount } from "vue";
import { ElMessage } from "element-plus";
const props = defineProps({
videoUrl: {
type: Array,
default: () => [],
},
lineType: {
type: String,
default: "alone",
validator: (value) =>
["alone", "fourWays", "nineWays", "sixteen"].includes(value)
? true
: "无效参数",
},
space: {
type: Number,
default: 5,
},
margin: {
type: Number,
default: 2,
},
isBackPlay: {
type: Boolean,
default: true,
},
});
const MHeight = ref(window.innerHeight - 84);
const videoNum = ref(0);
const BigClass = ref();
const videoList = ref({});
//
const init = () => {
switch (props.lineType) {
case "alone":
videoNum.value = 1;
break;
case "fourWays":
videoNum.value = 4;
break;
case "nineWays":
videoNum.value = 9;
break;
case "sixteen":
videoNum.value = 16;
break;
default:
videoNum.value = 1;
break;
}
nextTick(() => {
if (videoNum.value > 0) {
for (let i = 0; i < videoNum.value; i++) {
if (i < props.videoUrl.length) {
const dom = new WasmPlayer(null, "Player_" + (i + 1), null);
dom.play(props.videoUrl[i], 1);
videoList.value["Player_" + (i + 1)] = dom;
updatePlayerDomSize(i + 1);
}
}
visibilitychange();
}
});
};
//
const updatePlayerDomSize = (id) => {
let ways = 1;
switch (videoNum.value) {
case 1:
ways = 1;
break;
case 4:
ways = 2;
break;
case 9:
ways = 3;
break;
case 16:
ways = 4;
break;
}
let dom = document.getElementById("Player_" + id);
dom.style.height =
(MHeight.value - props.space * (ways - 1) - props.margin * 2) / ways + "px";
dom.style.paddingTop = 0;
};
//
const takeSnapshot = (id) => {
const player = videoList.value["Player_" + id];
if (player) {
const snapshot = player.snapshot();
if (snapshot) {
//
ElMessage.success("快照成功!");
} else {
ElMessage.error("快照失败!");
}
}
};
//
const visibilitychange = () => {
if (props.isBackPlay) return;
document.addEventListener("visibilitychange", function () {
if (document.visibilityState === "hidden") {
for (let key in videoList.value) {
videoList.value[key].pause();
}
}
if (document.visibilityState === "visible") {
for (let key in videoList.value) {
videoList.value[key].play(videoList.value[key].url, 1);
}
}
});
};
//
const getSpan = (videoNum) => {
switch (videoNum) {
case 1:
return 24;
case 4:
return 12;
case 9:
return 8;
case 16:
return 6;
}
};
watchEffect(() => {
init();
});
onBeforeUnmount(() => {
for (let key in videoList.value) {
videoList.value[key].destroy();
}
if (!props.isBackPlay) {
document.removeEventListener("visibilitychange", visibilitychange);
}
});
</script>
<style scoped>
.main-video {
width: 100%;
height: 100%;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.video-container {
position: relative;
height: 100%;
}
.video-item {
width: 100%;
height: 100%;
background-color: #000;
border-radius: 5px;
}
.snapshot-btn {
position: absolute;
bottom: 10px;
right: 10px;
}
</style>

View File

@ -1,47 +0,0 @@
<template>
<div class="page-header">
<span class="page-title">{{ title }}</span>
</div>
</template>
<script setup>
const props = defineProps({
title: {
required: true,
type: String,
default: ''
},
border: {
type: Boolean,
default: true
}
})
onMounted(async () => {
await nextTick();//
if (props.border == false) {
const pageHeaders = document.querySelectorAll('.page-header');
pageHeaders.forEach(function (item) {
item.style.borderBottom = 'none';
item.style.paddingBottom = 0;
});
}
});
</script>
<style scoped lang="scss">
.page-header {
position: relative;
padding-bottom: 1rem;
margin-bottom: 1.375rem;
border-bottom: 1px solid var(--el-fill-color-light);
.page-title {
font-size: 1.125rem;
line-height: 1.625rem;
font-weight: bold;
}
}
</style>

View File

@ -29,14 +29,13 @@
label-position="left"
require-asterisk-position="right"
:rules="rules"
:disabled="isView"
v-if="showRegistration"
>
<DividerHeader title="基本信息"/>
<el-row :gutter="24">
<el-col :span="12">
<el-form-item label="姓名" required prop="visitorName">
<el-input placeholder="请填写上访人姓名" v-model="queryParams.visitorName"/>
<el-input placeholder="请填写上访人姓名" v-model="queryParams.visitorName" :disabled="isView"/>
</el-form-item>
</el-col>
<el-col :span="12">
@ -47,17 +46,26 @@
placeholder="请选择上访时间"
value-format="YYYY-MM-DD hh:mm:ss"
:disabled-date="disableDate"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="电话">
<el-input placeholder="请填写上访人电话号码" v-model="queryParams.visitorMobile"/>
<el-input
placeholder="请填写上访人电话号码"
v-model="queryParams.visitorMobile"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="工作单位或住址">
<el-input placeholder="请填写上访人工作单位或住址" v-model="queryParams.visitorContact"/>
<el-input
placeholder="请填写上访人工作单位或住址"
v-model="queryParams.visitorContact"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="12">
@ -65,6 +73,7 @@
<el-select
v-model="queryParams.visitorSex"
placeholder="请选择性别"
:disabled="isView"
>
<el-option
v-for="item in sys_user_sex"
@ -80,6 +89,7 @@
<el-select
v-model="queryParams.visitorDegree"
placeholder="请选择学历"
:disabled="isView"
>
<el-option
v-for="item in people_degree"
@ -92,17 +102,27 @@
</el-col>
<el-col :span="12">
<el-form-item label="来源">
<el-input placeholder="请填写来源" v-model="queryParams.source"/>
<el-input placeholder="请填写来源" v-model="queryParams.source" :disabled="isView"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="年龄">
<el-input placeholder="请填写年龄" type="number" :min="1" v-model="queryParams.visitorAge"/>
<el-input
placeholder="请填写年龄"
type="number"
:min="1"
v-model="queryParams.visitorAge"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="接待人">
<el-input placeholder="请填写接待人" v-model="queryParams.receptionist"/>
<el-input
placeholder="请填写接待人"
v-model="queryParams.receptionist"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="12">
@ -110,6 +130,7 @@
<el-select
v-model="queryParams.receptionistType"
placeholder="请选择接待人类型"
:disabled="isView"
>
<el-option
v-for="item in receptionist_type"
@ -122,29 +143,35 @@
</el-col>
<el-col :span="24">
<el-form-item label="联系住址">
<el-input placeholder="请填写联系住址" v-model="queryParams.visitorAddress"/>
<el-input
placeholder="请填写联系住址"
v-model="queryParams.visitorAddress"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-row :gutter="24">
<el-col :span="19">
<el-col :span="16">
<el-form-item label="身份证号码">
<el-input
placeholder="请填写上访人身份证号码"
v-model="queryParams.visitorCode"
type="number"
@change="idCardChangeHandle"
:disabled="isView"
/>
</el-form-item>
</el-col>
<el-col :span="3">
<el-col :span="8">
<!-- @click="visitHistoryRef.showVisitHistory(queryForm.sfzId)" -->
<el-button
type="primary"
type="text"
:disabled="viewHistoryDisable"
@click="visitHistoryRef.showVisitHistory(queryParams.visitorCode)"
>
异地历史信访
异地访问: {{ queryParams.otherPlaces }} , 本地访问: {{ queryParams.locals }}
</el-button>
</el-col>
</el-row>
@ -158,6 +185,7 @@
<el-select
v-model="queryParams.type"
placeholder="请选择来访类型"
:disabled="isView"
>
<el-option
v-for="item in visit_type"
@ -176,6 +204,7 @@
type="textarea"
v-model="queryParams.demand"
:autosize="{ minRows: 3, maxRows: 9999 }"
:disabled="isView"
/>
</el-form-item>
</el-col>
@ -186,6 +215,7 @@
type="textarea"
v-model="queryParams.reply"
:autosize="{ minRows: 3, maxRows: 9999 }"
:disabled="isView"
/>
</el-form-item>
</el-col>
@ -194,6 +224,7 @@
<el-select
v-model="queryParams.field"
placeholder="请选择领域"
:disabled="isView"
>
<el-option
v-for="item in visit_field"
@ -209,6 +240,7 @@
<el-select
v-model="queryParams.replyType"
placeholder="请选择答复形式"
:disabled="isView"
>
<el-option
v-for="item in visit_reply_type"
@ -221,7 +253,7 @@
</el-col>
<el-col :span="12">
<el-form-item label="是否重点人员" label-position="top">
<el-radio-group v-model="queryParams.isKeyPerson">
<el-radio-group v-model="queryParams.isKeyPerson" :disabled="isView">
<el-radio-button
v-for="item in boolean_yes_no"
:value="item.value"
@ -236,6 +268,7 @@
<el-select
v-model="queryParams.level"
placeholder="请选择来访级别"
:disabled="isView"
>
<el-option
v-for="item in visit_level"
@ -261,7 +294,13 @@
<script setup>
import {getCurrentInstance, useTemplateRef} from 'vue';
import {addVisit, getRegisterList, getVisitInfo, updateVisit} from '@/api/RegistVisitApi/RegistVisitApi.js';
import {
addVisit,
getRegisterList,
getVisitHistoryCount,
getVisitInfo,
updateVisit
} from '@/api/RegistVisitApi/RegistVisitApi.js';
import dayjs from 'dayjs';
import DividerHeader from '@/components/DividerHeader/DividerHeader.vue';
import {ArrowRight} from '@element-plus/icons-vue';
@ -297,8 +336,8 @@ const isShow = ref(false)
const isEdit = ref(false)
const isView = ref(false)
const isCreate = ref(false)
const showRegistrationList = ref(true)
const showRegistration = ref(false)
const showRegistrationList = ref(false)
const showRegistration = ref(true)
//
const viewHistoryDisable = ref(true)
@ -341,7 +380,11 @@ const defaultParams = {
//
receptionist: '',
//
receptionistType: ''
receptionistType: '',
// 访
locals: 0,
// 访
otherPlaces: 0
}
const queryParams = ref({...defaultParams})
const registerList = ref([])
@ -450,8 +493,18 @@ const updateHandle = async (elForm) => {
}
//
const idCardChangeHandle = (value) => {
viewHistoryDisable.value = !value;
const idCardChangeHandle = async (value) => {
if (value) {
const res = await getVisitHistoryCount({
idCard: value,
endTime: dayjs().format('YYYY-MM-DD hh:mm:ss')
})
queryParams.value.otherPlaces = res.data.otherPlaces
queryParams.value.locals = res.data.locals
viewHistoryDisable.value = false;
} else {
viewHistoryDisable.value = true;
}
}
//