2025年04月12日18:35:52
This commit is contained in:
parent
f82d3934ba
commit
6b04c453d9
2
auto-imports.d.ts
vendored
2
auto-imports.d.ts
vendored
@ -1,5 +1,5 @@
|
|||||||
// Generated by 'unplugin-auto-import'
|
// Generated by 'unplugin-auto-import'
|
||||||
export {}
|
export {}
|
||||||
declare global {
|
declare global {
|
||||||
const ElMessage: typeof import('element-plus/es')['ElMessage']
|
|
||||||
}
|
}
|
||||||
|
22
src/api/index.d.ts
vendored
22
src/api/index.d.ts
vendored
@ -22,6 +22,10 @@ export interface TRoleList {
|
|||||||
createTime?: string
|
createTime?: string
|
||||||
roleMenu?: TRoleMenu[]
|
roleMenu?: TRoleMenu[]
|
||||||
}
|
}
|
||||||
|
export interface TbindWeb {
|
||||||
|
devices: number[]
|
||||||
|
accountId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface TStatisticsDevice {
|
export interface TStatisticsDevice {
|
||||||
@ -131,11 +135,10 @@ export namespace TLogin {
|
|||||||
export namespace TAccount {
|
export namespace TAccount {
|
||||||
export interface IAdd {
|
export interface IAdd {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
|
||||||
phone: string;
|
phone: string;
|
||||||
name: string;
|
name: string;
|
||||||
orgId: number;
|
orgId?: number | string;
|
||||||
roleId: number;
|
roleId: number | string;
|
||||||
status: number;
|
status: number;
|
||||||
}
|
}
|
||||||
export interface IListReq extends Ipaging {
|
export interface IListReq extends Ipaging {
|
||||||
@ -282,6 +285,11 @@ export namespace TOrg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TstatisticsUseCount {
|
||||||
|
defaultCount: number;
|
||||||
|
monitorCount: number;
|
||||||
|
outsideCount: number;
|
||||||
|
}
|
||||||
export namespace TWarnRecord {
|
export namespace TWarnRecord {
|
||||||
|
|
||||||
export interface IListReq extends Ipaging {
|
export interface IListReq extends Ipaging {
|
||||||
@ -314,6 +322,12 @@ export namespace TWarningDetail {
|
|||||||
interface TParams {
|
interface TParams {
|
||||||
id: number | string
|
id: number | string
|
||||||
}
|
}
|
||||||
|
interface THealthData {
|
||||||
|
bo: number
|
||||||
|
hr: number
|
||||||
|
temp: number
|
||||||
|
time: number
|
||||||
|
}
|
||||||
interface TRes {
|
interface TRes {
|
||||||
address: string
|
address: string
|
||||||
adminName: string
|
adminName: string
|
||||||
@ -321,7 +335,7 @@ export namespace TWarningDetail {
|
|||||||
creatUser: string
|
creatUser: string
|
||||||
createTime: string
|
createTime: string
|
||||||
deviceId: string
|
deviceId: string
|
||||||
healthData: string
|
healthData: THealthData[]
|
||||||
id: number
|
id: number
|
||||||
lat: number
|
lat: number
|
||||||
lng: number
|
lng: number
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import request from '../utils/request';
|
import request from '../utils/request';
|
||||||
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord, TWarningDetail, TWarningConfirm, TDeviceConfigModify, TDeviceConfig, THealthLatestData, TLocateRecord, TSetUseStatus, TRoleMenuList, TRoleModify } from "./index.d";
|
import { TLogin, TAccount, IpagingRes, TDevice, TOrg, TRoleList, TStatisticsDevice, statisticsContentReq, statisticsContentRes, TStatisticsCount, TWarnRecord, TWarningDetail, TWarningConfirm, TDeviceConfigModify, TDeviceConfig, THealthLatestData, TLocateRecord, TSetUseStatus, TRoleMenuList, TRoleModify, TbindWeb, TstatisticsUseCount } from "./index.d";
|
||||||
|
|
||||||
export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => {
|
export const fetchLogin = (p: TLogin.Ireq): Promise<TLogin.IRes> => {
|
||||||
return request({
|
return request({
|
||||||
@ -76,6 +76,14 @@ export const accountList = (p: TAccount.IListReq): Promise<IpagingRes<TAccount.I
|
|||||||
params: p
|
params: p
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 获取组织下账号列表
|
||||||
|
export const accountListOrg = (orgId: number): Promise<TAccount.IListRes[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/v1/api/account/list/org',
|
||||||
|
method: 'get',
|
||||||
|
params: { orgId }
|
||||||
|
});
|
||||||
|
};
|
||||||
// 重置密码
|
// 重置密码
|
||||||
export const passwordReset = (p: TAccount.IResetPwd): Promise<null> => {
|
export const passwordReset = (p: TAccount.IResetPwd): Promise<null> => {
|
||||||
return request({
|
return request({
|
||||||
@ -173,6 +181,13 @@ export const orgList = (p?: TOrg.IListReq): Promise<IpagingRes<TOrg.IOrgRecordRe
|
|||||||
params: p
|
params: p
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 机构列表
|
||||||
|
export const orgAllList = (): Promise<TOrg.IOrgRecordRes[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/v1/api/org/list',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 删除机构
|
// 删除机构
|
||||||
export const orgDelete = (p?: TOrg.Idel): Promise<null> => {
|
export const orgDelete = (p?: TOrg.Idel): Promise<null> => {
|
||||||
@ -183,6 +198,15 @@ export const orgDelete = (p?: TOrg.Idel): Promise<null> => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// web设备绑定管理员
|
||||||
|
export const bindWeb = (p: TbindWeb): Promise<null> => {
|
||||||
|
return request({
|
||||||
|
url: '/v1/api/device/web/bind/web',
|
||||||
|
method: 'post',
|
||||||
|
data: p
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 获取角色列表
|
// 获取角色列表
|
||||||
export const roleList = (): Promise<TRoleList[]> => {
|
export const roleList = (): Promise<TRoleList[]> => {
|
||||||
return request({
|
return request({
|
||||||
@ -251,6 +275,14 @@ export const warnRecord = (p: TWarnRecord.IListReq): Promise<IpagingRes<TWarnRec
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取设备使用数量
|
||||||
|
export const statisticsUseCount = (): Promise<TstatisticsUseCount> => {
|
||||||
|
return request({
|
||||||
|
url: '/v1/api/statistics/useCount',
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// 预警记录
|
// 预警记录
|
||||||
export const warningDetail = (p: TWarningDetail.TParams): Promise<TWarningDetail.TRes> => {
|
export const warningDetail = (p: TWarningDetail.TParams): Promise<TWarningDetail.TRes> => {
|
||||||
return request({
|
return request({
|
||||||
|
Binary file not shown.
BIN
src/assets/img/avatar.png
Normal file
BIN
src/assets/img/avatar.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 166 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.0 KiB |
@ -47,7 +47,6 @@ const emit = defineEmits(["close", "confirm"]);
|
|||||||
|
|
||||||
const handleAudioEnd = () => {
|
const handleAudioEnd = () => {
|
||||||
emit("close");
|
emit("close");
|
||||||
|
|
||||||
// if (audioPlayer.value) {
|
// if (audioPlayer.value) {
|
||||||
// audioPlayer.value.play().catch((error) => {
|
// audioPlayer.value.play().catch((error) => {
|
||||||
// console.error("自动播放被阻止:", error);
|
// console.error("自动播放被阻止:", error);
|
||||||
@ -56,23 +55,11 @@ const handleAudioEnd = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 确保在DOM完全加载后播放音频
|
if (audioPlayer.value) {
|
||||||
// if (audioPlayer.value) {
|
audioPlayer.value.play().catch((error) => {
|
||||||
// setTimeout(() => {
|
console.error("自动播放被阻止:", error);
|
||||||
// audioPlayer.value.play();
|
});
|
||||||
// });
|
}
|
||||||
// audioPlayer.value.play();
|
|
||||||
// // 设置音频静音,浏览器允许自动播放
|
|
||||||
// audioPlayer.value
|
|
||||||
// .play()
|
|
||||||
// .then(() => {
|
|
||||||
// // 自动播放成功后取消静音
|
|
||||||
// audioPlayer.value.muted = false;
|
|
||||||
// })
|
|
||||||
// .catch((error) => {
|
|
||||||
// console.log("自动播放失败", error);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{{ item }}{{ index != tab.list.length - 1 ? " / " : "" }}
|
{{ item }}{{ index != tab.list.length - 1 ? " / " : "" }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="web-time">{{ format(time) }} 更新</div>
|
<div class="web-time">{{ format(comm.time) }} 更新</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<div class="header-user-con">
|
<div class="header-user-con">
|
||||||
@ -33,7 +33,7 @@
|
|||||||
<!-- 用户名下拉菜单 -->
|
<!-- 用户名下拉菜单 -->
|
||||||
<el-dropdown class="user-name" trigger="click" @command="handleCommand">
|
<el-dropdown class="user-name" trigger="click" @command="handleCommand">
|
||||||
<span class="el-dropdown-link">
|
<span class="el-dropdown-link">
|
||||||
{{ user.username }}
|
{{ comm.user.username }}
|
||||||
<el-icon class="el-icon--right">
|
<el-icon class="el-icon--right">
|
||||||
<arrow-down />
|
<arrow-down />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
@ -49,23 +49,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted } from "vue";
|
import { inject, onMounted } from "vue";
|
||||||
import { useSidebarStore } from "../store/sidebar";
|
import { useSidebarStore } from "../store/sidebar";
|
||||||
import { useCommonStore } from "../store/common";
|
import { useCommonStore } from "../store/common";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
import imgurl from "../assets/img/img.jpg";
|
import imgurl from "../assets/img/avatar.png";
|
||||||
import { useTabsStore } from "@/store/tabs";
|
import { useTabsStore } from "@/store/tabs";
|
||||||
import { routes } from "@/router/index";
|
import { routes } from "@/router/index";
|
||||||
import { RouteRecordRaw } from "vue-router";
|
|
||||||
import { format } from "@/utils";
|
import { format } from "@/utils";
|
||||||
|
|
||||||
|
const ws: any = inject("ws");
|
||||||
const tab = useTabsStore();
|
const tab = useTabsStore();
|
||||||
|
|
||||||
const username: string | null = localStorage.getItem("vuems_name");
|
const username: string | null = localStorage.getItem("vuems_name");
|
||||||
|
|
||||||
const message: number = 2;
|
const message: number = 2;
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
const { user, time, clearStore } = useCommonStore();
|
const comm = useCommonStore();
|
||||||
|
|
||||||
// onMounted(() => {
|
// onMounted(() => {
|
||||||
// if (document.body.clientWidth < 1500) {
|
// if (document.body.clientWidth < 1500) {
|
||||||
// sidebar.handleCollapse();
|
// sidebar.handleCollapse();
|
||||||
@ -76,8 +77,9 @@ const { user, time, clearStore } = useCommonStore();
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const handleCommand = (command: string) => {
|
const handleCommand = (command: string) => {
|
||||||
if (command == "loginout") {
|
if (command == "loginout") {
|
||||||
clearStore();
|
comm.clearStore();
|
||||||
router.push("/login");
|
router.push("/login");
|
||||||
|
ws.close();
|
||||||
} else if (command == "user") {
|
} else if (command == "user") {
|
||||||
router.push("/ucenter");
|
router.push("/ucenter");
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,16 @@
|
|||||||
table-layout="auto"
|
table-layout="auto"
|
||||||
>
|
>
|
||||||
<template v-for="item in columns" :key="item.prop">
|
<template v-for="item in columns" :key="item.prop">
|
||||||
<el-table-column v-if="item.visible" :prop="item.prop" :label="item.label" :width="item.width" :type="item.type" :align="item.align || 'center'">
|
<el-table-column
|
||||||
|
v-if="item.visible"
|
||||||
|
:prop="item.prop"
|
||||||
|
:label="item.label"
|
||||||
|
:width="item.width"
|
||||||
|
:type="item.type"
|
||||||
|
:align="item.align || 'center'"
|
||||||
|
:fixed="item.fixed"
|
||||||
|
:reserve-selection="item.reserveSelection"
|
||||||
|
>
|
||||||
<template #default="{ row, column, $index }" v-if="item.type === 'index'">
|
<template #default="{ row, column, $index }" v-if="item.type === 'index'">
|
||||||
{{ getIndex($index) }}
|
{{ getIndex($index) }}
|
||||||
</template>
|
</template>
|
||||||
@ -144,6 +153,10 @@ const props = defineProps({
|
|||||||
type: Function,
|
type: Function,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
|
selectionChange: {
|
||||||
|
type: Function,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
editFunc: {
|
editFunc: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
@ -178,8 +191,10 @@ const tableRowClassName = ({ row, rowIndex }: { row: TableItem; rowIndex: number
|
|||||||
|
|
||||||
// 当选择项发生变化时会触发该事件
|
// 当选择项发生变化时会触发该事件
|
||||||
const multipleSelection = ref([]);
|
const multipleSelection = ref([]);
|
||||||
|
|
||||||
const handleSelectionChange = (selection: any[]) => {
|
const handleSelectionChange = (selection: any[]) => {
|
||||||
multipleSelection.value = selection;
|
multipleSelection.value = selection;
|
||||||
|
props.selectionChange(selection);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 当前页码变化的事件
|
// 当前页码变化的事件
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="app-wrapper">
|
|
||||||
<audio ref="audioRef" autoplay loop hidden>
|
|
||||||
<source src="../assets/audio/alarm.mp3" type="video/mp3" />
|
|
||||||
</audio>
|
|
||||||
<el-button @click="playAudio">Default</el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from "vue";
|
|
||||||
const audioSrc = ref(new URL("@/assets/audio/alarm.mp3", import.meta.url).href);
|
|
||||||
const audioRef = ref(null);
|
|
||||||
|
|
||||||
const playAudio = (context) => {
|
|
||||||
audioRef.value.play().catch((err) => {
|
|
||||||
// console.log(err, "暂停失败");
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
@ -1,120 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="app-wrapper">
|
|
||||||
<v-sidebar />
|
|
||||||
<v-header />
|
|
||||||
<div class="main-container">
|
|
||||||
<div class="app-main" :class="{ 'content-collapse': sidebar.collapse }">
|
|
||||||
<router-view v-slot="{ Component }">
|
|
||||||
<transition name="move" mode="out-in">
|
|
||||||
<keep-alive :include="[]">
|
|
||||||
<component :is="Component"></component>
|
|
||||||
</keep-alive>
|
|
||||||
</transition>
|
|
||||||
</router-view>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <audio ref="audioPlayer" src="../assets/audio/alarm.mp3" hidden /> -->
|
|
||||||
<audio ref="audioPlayer" autoplay loop hidden>
|
|
||||||
<source src="../assets/audio/alarm.mp3" type="audio/mpeg" />
|
|
||||||
</audio>
|
|
||||||
<!-- <Alarm ref="alarmRef" v-if="visible" @close="close" /> -->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { useSidebarStore } from "@/store/sidebar";
|
|
||||||
import vHeader from "@/components/header.vue";
|
|
||||||
import vSidebar from "@/components/sidebar.vue";
|
|
||||||
import Alarm from "@/components/alarm.vue";
|
|
||||||
import { ref } from "vue";
|
|
||||||
|
|
||||||
// import useWebSocket from "@/utils/webSocket";
|
|
||||||
// const { onMessage } = useWebSocket();
|
|
||||||
// onMessage((res) => {
|
|
||||||
// console.log(res, "WebSocket 接收服务器消息");
|
|
||||||
// if (res.cmd == "warning") {
|
|
||||||
// console.log("预警弹窗");
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
|
||||||
const alarmRef = ref(null);
|
|
||||||
const audioPlayer = ref(null);
|
|
||||||
const visible = ref(true);
|
|
||||||
|
|
||||||
const getInclude = (routeList: any) => {
|
|
||||||
if (!routeList) return [];
|
|
||||||
let list = [];
|
|
||||||
routeList.forEach((item) => {
|
|
||||||
if (item.meta && item.meta.keepAlive) {
|
|
||||||
list.push(item.name);
|
|
||||||
}
|
|
||||||
if (item.children && item.children.length) {
|
|
||||||
list = [...list, ...getInclude(item.children)];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return list;
|
|
||||||
};
|
|
||||||
const close = async () => {
|
|
||||||
try {
|
|
||||||
audioPlayer.value.play();
|
|
||||||
console.log(1111);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error, 2222);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// setTimeout(() => {
|
|
||||||
// audioRef.value.play().catch((error) => {
|
|
||||||
// console.error("自动播放被阻止:", error);
|
|
||||||
// });
|
|
||||||
// }, 5000);
|
|
||||||
const playAudio = () => {
|
|
||||||
if (audioPlayer.value) {
|
|
||||||
audioPlayer.value.play().catch((error) => {
|
|
||||||
console.error("自动播放被阻止:", error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// const include = getInclude(routes[0].children);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="less">
|
|
||||||
// @media screen and (max-width: 800px) {
|
|
||||||
// .main-container {
|
|
||||||
// margin-left: 0 !important;
|
|
||||||
// }
|
|
||||||
// .sidebar-container {
|
|
||||||
// width: 0 !important;
|
|
||||||
// }
|
|
||||||
// .app-wrapper-header {
|
|
||||||
// width: 100% !important;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
.app-wrapper {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: 100vh;
|
|
||||||
background: #f0f2f5;
|
|
||||||
overflow: hidden;
|
|
||||||
.main-container {
|
|
||||||
height: 100vh;
|
|
||||||
margin-left: 210px;
|
|
||||||
min-height: 100%;
|
|
||||||
position: relative;
|
|
||||||
transition: 0.3s;
|
|
||||||
background-color: #f2f4fa;
|
|
||||||
}
|
|
||||||
.app-main {
|
|
||||||
// height: 100vh;
|
|
||||||
height: calc(100vh - 90px);
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
// padding-top: 70px;
|
|
||||||
margin-top: 70px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -13,8 +13,7 @@
|
|||||||
</router-view>
|
</router-view>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<Alarm ref="alarmRef" v-if="visible" @close="visible = false" />
|
||||||
<!-- <Alarm ref="alarmRef" v-if="visible" @close="close" /> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@ -22,7 +21,9 @@ import { useSidebarStore } from "@/store/sidebar";
|
|||||||
import vHeader from "@/components/header.vue";
|
import vHeader from "@/components/header.vue";
|
||||||
import vSidebar from "@/components/sidebar.vue";
|
import vSidebar from "@/components/sidebar.vue";
|
||||||
import Alarm from "@/components/alarm.vue";
|
import Alarm from "@/components/alarm.vue";
|
||||||
import { ref } from "vue";
|
import { inject, onBeforeUnmount, onMounted, ref } from "vue";
|
||||||
|
import { ElMessageBox } from "element-plus";
|
||||||
|
const ws: any = inject("ws");
|
||||||
|
|
||||||
// import useWebSocket from "@/utils/webSocket";
|
// import useWebSocket from "@/utils/webSocket";
|
||||||
// const { onMessage } = useWebSocket();
|
// const { onMessage } = useWebSocket();
|
||||||
@ -30,13 +31,14 @@ import { ref } from "vue";
|
|||||||
// console.log(res, "WebSocket 接收服务器消息");
|
// console.log(res, "WebSocket 接收服务器消息");
|
||||||
// if (res.cmd == "warning") {
|
// if (res.cmd == "warning") {
|
||||||
// console.log("预警弹窗");
|
// console.log("预警弹窗");
|
||||||
|
// visible.value = true;
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
const alarmRef = ref(null);
|
const alarmRef = ref(null);
|
||||||
const audioPlayer = ref(null);
|
const audioPlayer = ref(null);
|
||||||
const visible = ref(true);
|
const visible = ref(false);
|
||||||
|
|
||||||
const getInclude = (routeList: any) => {
|
const getInclude = (routeList: any) => {
|
||||||
if (!routeList) return [];
|
if (!routeList) return [];
|
||||||
@ -51,27 +53,35 @@ const getInclude = (routeList: any) => {
|
|||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
};
|
};
|
||||||
const close = async () => {
|
|
||||||
try {
|
const handleBeforeUnload = (event: any) => {
|
||||||
audioPlayer.value.play();
|
localStorage.removeItem("isReload");
|
||||||
console.log(1111);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error, 2222);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
setTimeout(() => {
|
onMounted(() => {
|
||||||
audioPlayer.value.play().catch((error) => {
|
const isReload = localStorage.getItem("isReload");
|
||||||
console.error("自动播放被阻止:", error);
|
// if (isReload !== "true") {
|
||||||
});
|
// ElMessageBox.alert("由于浏览器安全策略,用户必须点击屏幕才能播放告警声音", "提示", {
|
||||||
}, 5000);
|
// confirmButtonText: "OK",
|
||||||
const playAudio = () => {
|
// callback: () => {
|
||||||
if (audioPlayer.value) {
|
// localStorage.setItem("isReload", "true");
|
||||||
audioPlayer.value.play().catch((error) => {
|
// },
|
||||||
console.error("自动播放被阻止:", error);
|
// });
|
||||||
});
|
// }
|
||||||
}
|
|
||||||
};
|
// if (ws.socket == null) {
|
||||||
|
// ws.connect();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
||||||
|
});
|
||||||
|
|
||||||
// const include = getInclude(routes[0].children);
|
// const include = getInclude(routes[0].children);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -7,12 +7,14 @@ import { usePermissStore } from './store/permiss';
|
|||||||
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
|
||||||
import 'element-plus/dist/index.css';
|
import 'element-plus/dist/index.css';
|
||||||
import './assets/css/icon.css';
|
import './assets/css/icon.css';
|
||||||
|
import WebSocketService from "@/utils/webSocket.js";
|
||||||
|
const ws = new WebSocketService()
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
const pinia = createPinia();
|
const pinia = createPinia();
|
||||||
pinia.use(piniaPluginPersistedstate);
|
pinia.use(piniaPluginPersistedstate);
|
||||||
app.use(pinia);
|
app.use(pinia);
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
app.provide('ws', ws)
|
||||||
|
|
||||||
// 注册elementplus图标
|
// 注册elementplus图标
|
||||||
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
|
@ -17,7 +17,7 @@ import m4_a from "@/assets/img/m4_a.png";
|
|||||||
export const routes: RouteRecordRaw[] = [
|
export const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
component: Layout,
|
component: () => import('@/layout/index.vue'),
|
||||||
redirect: '/statisticalCenter',
|
redirect: '/statisticalCenter',
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
@ -123,14 +123,12 @@ const router = createRouter({
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
|
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
const permiss = usePermissStore();
|
const permiss = usePermissStore();
|
||||||
const comm = useCommonStore();
|
const comm = useCommonStore();
|
||||||
const tab = useTabsStore();
|
const tab = useTabsStore();
|
||||||
tab.setTabsItem(to.meta.tabs);
|
tab.setTabsItem(to.meta.tabs);
|
||||||
comm.setTime()
|
comm.setTime()
|
||||||
|
|
||||||
if (typeof to.meta.permiss == 'string' && !permiss.key.includes(to.meta.permiss)) {
|
if (typeof to.meta.permiss == 'string' && !permiss.key.includes(to.meta.permiss)) {
|
||||||
// 如果没有权限,则进入403
|
// 如果没有权限,则进入403
|
||||||
next('/403');
|
next('/403');
|
||||||
|
@ -18,5 +18,6 @@ export interface FormOptionList {
|
|||||||
activeText?: string;
|
activeText?: string;
|
||||||
inactiveText?: string;
|
inactiveText?: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
|
defalut?: any;
|
||||||
validator?: Function;
|
validator?: Function;
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ export class MapCustom {
|
|||||||
}
|
}
|
||||||
// 多边形回显
|
// 多边形回显
|
||||||
polyEditor(list, fn) {
|
polyEditor(list, fn) {
|
||||||
|
if (!list) return;
|
||||||
this.map.clearMap();
|
this.map.clearMap();
|
||||||
let pathList = [];
|
let pathList = [];
|
||||||
list.forEach((item, index) => {
|
list.forEach((item, index) => {
|
||||||
|
@ -22,6 +22,8 @@ service.interceptors.request.use(
|
|||||||
service.interceptors.response.use(
|
service.interceptors.response.use(
|
||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
const { data, headers } = response;
|
const { data, headers } = response;
|
||||||
|
if (headers['content-type'] === "application/vnd.ms-excel;charset=utf-8") return data
|
||||||
|
|
||||||
if (data.code !== 200) {
|
if (data.code !== 200) {
|
||||||
ElMessage.error(data.msg)
|
ElMessage.error(data.msg)
|
||||||
|
|
||||||
|
@ -1,33 +1,32 @@
|
|||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { useCommonStore } from "@/store/common";
|
||||||
|
export default class WebSocketService {
|
||||||
class WebSocketService {
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.url = import.meta.env.VITE_APP_URL_WEBSOCKET;
|
this.url = import.meta.env.VITE_APP_URL_WEBSOCKET;
|
||||||
this.socket = null;
|
this.socket = null;
|
||||||
this.isAlive = false; // 用于判断心跳是否正常
|
this.isAlive = false; // 用于判断心跳是否正常
|
||||||
this.reconnectAttempts = 0; // 重连尝试次数
|
this.reconnectAttempts = 0; // 重连尝试次数
|
||||||
this.MAX_RECONNECT_ATTEMPTS = 5; // 最大重连次数
|
this.MAX_RECONNECT_ATTEMPTS = 5; // 最大重连次数
|
||||||
this.HEARTBEAT_INTERVAL = 5000; // 心跳间隔时间 (30秒)
|
// this.HEARTBEAT_INTERVAL = 5000; // 心跳间隔时间 (30秒)
|
||||||
// this.HEARTBEAT_INTERVAL = 30000; // 心跳间隔时间 (30秒)
|
this.HEARTBEAT_INTERVAL = 30000; // 心跳间隔时间 (30秒)
|
||||||
this.heartbeatTimer = null;
|
this.heartbeatTimer = null;
|
||||||
this.reconnectTimer = null;
|
this.reconnectTimer = null;
|
||||||
|
|
||||||
this.connect();
|
// this.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
this.socket = new WebSocket(this.url);
|
this.socket = new WebSocket(this.url);
|
||||||
|
|
||||||
this.socket.onopen = () => {
|
this.socket.onopen = () => {
|
||||||
console.log('WebSocket已连接');
|
console.log('WebSocket已连接');
|
||||||
this.webScoketLogin();
|
this.webScoketLogin();
|
||||||
this.reconnectAttempts = 0; // 成功连接后重置重试次数
|
this.reconnectAttempts = 0; // 成功连接后重置重试次数
|
||||||
this.startHeartbeat(); // 开始心跳检测
|
this.startHeartbeat(); // 开始心跳检测
|
||||||
};
|
};
|
||||||
|
this.onMessage()
|
||||||
this.socket.onmessage = (event) => {
|
this.socket.onmessage = (event) => {
|
||||||
// 处理接收到的消息
|
// 处理接收到的消息
|
||||||
console.log('Message received:', event.data);
|
console.log('WebSocket收到消息:', event.data);
|
||||||
|
this.receivePong()
|
||||||
};
|
};
|
||||||
|
|
||||||
this.socket.onclose = () => {
|
this.socket.onclose = () => {
|
||||||
@ -49,8 +48,9 @@ class WebSocketService {
|
|||||||
cmd: "webLogin",
|
cmd: "webLogin",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 开始发送心跳
|
||||||
startHeartbeat() {
|
startHeartbeat() {
|
||||||
|
console.log('开始发送心跳');
|
||||||
if (!this.heartbeatTimer) {
|
if (!this.heartbeatTimer) {
|
||||||
this.heartbeatTimer = setInterval(() => {
|
this.heartbeatTimer = setInterval(() => {
|
||||||
if (this.socket.readyState === WebSocket.OPEN) {
|
if (this.socket.readyState === WebSocket.OPEN) {
|
||||||
@ -60,7 +60,7 @@ class WebSocketService {
|
|||||||
}, this.HEARTBEAT_INTERVAL);
|
}, this.HEARTBEAT_INTERVAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 关闭发送心态
|
||||||
stopHeartbeat() {
|
stopHeartbeat() {
|
||||||
if (this.heartbeatTimer) {
|
if (this.heartbeatTimer) {
|
||||||
clearInterval(this.heartbeatTimer);
|
clearInterval(this.heartbeatTimer);
|
||||||
@ -69,8 +69,6 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendPing() {
|
sendPing() {
|
||||||
console.log('发送心跳', JSON.stringify({ cmd: 'heartbeat' }));
|
|
||||||
|
|
||||||
this.socket.send(JSON.stringify({ cmd: 'heartbeat' }));
|
this.socket.send(JSON.stringify({ cmd: 'heartbeat' }));
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!this.isAlive) {
|
if (!this.isAlive) {
|
||||||
@ -83,25 +81,39 @@ class WebSocketService {
|
|||||||
receivePong() {
|
receivePong() {
|
||||||
this.isAlive = true;
|
this.isAlive = true;
|
||||||
}
|
}
|
||||||
|
// 重新连接
|
||||||
attemptReconnect() {
|
attemptReconnect() {
|
||||||
|
const comm = useCommonStore();
|
||||||
|
if (!comm.user.token) return
|
||||||
if (this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
|
if (this.reconnectAttempts < this.MAX_RECONNECT_ATTEMPTS) {
|
||||||
this.reconnectAttempts++;
|
this.reconnectAttempts++;
|
||||||
console.log(`Attempting to reconnect (${this.reconnectAttempts})...`);
|
console.log(`正在尝试重新连接 (${this.reconnectAttempts})...`);
|
||||||
this.reconnectTimer = setTimeout(() => {
|
this.reconnectTimer = setTimeout(() => {
|
||||||
this.connect();
|
this.connect();
|
||||||
}, 1000 * this.reconnectAttempts); // 指数退避算法
|
}, 1000 * this.reconnectAttempts); // 指数退避算法
|
||||||
} else {
|
} else {
|
||||||
console.error('Max reconnect attempts reached');
|
console.error('达到的最大重连尝试数');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 发送消息
|
||||||
sendMessage(message) {
|
sendMessage(message) {
|
||||||
|
console.log('sendMessage');
|
||||||
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
||||||
this.socket.send(JSON.stringify(message));
|
this.socket.send(JSON.stringify(message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMessage = (callback) => {
|
||||||
|
this.socket.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
if (data.cmd == "webLogin" && !data.code == 200) return this.webScoketLogin()
|
||||||
|
callback && callback(data);
|
||||||
|
if (event.data.includes('heartbeat')) {
|
||||||
|
this.receivePong();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// 关闭连接
|
||||||
close() {
|
close() {
|
||||||
this.stopHeartbeat();
|
this.stopHeartbeat();
|
||||||
if (this.reconnectTimer) {
|
if (this.reconnectTimer) {
|
||||||
@ -115,44 +127,3 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function useWebSocket() {
|
|
||||||
const ws = new WebSocketService();
|
|
||||||
|
|
||||||
const message = ref(null);
|
|
||||||
const isConnected = ref(false);
|
|
||||||
|
|
||||||
const onMessage = (callback) => {
|
|
||||||
ws.socket.onmessage = (event) => {
|
|
||||||
const data = JSON.parse(event.data);
|
|
||||||
if (data.cmd == "webLogin" && !data.code == 200) return ws.webScoketLogin()
|
|
||||||
|
|
||||||
callback(data);
|
|
||||||
if (event.data.includes('heartbeat')) {
|
|
||||||
ws.receivePong();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClose = () => {
|
|
||||||
ws.socket.onclose()
|
|
||||||
};
|
|
||||||
|
|
||||||
const onOpen = (callback) => {
|
|
||||||
ws.socket.onopen = () => {
|
|
||||||
isConnected.value = true;
|
|
||||||
callback();
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// onMounted(() => {
|
|
||||||
// onOpen(() => console.log('Connected'));
|
|
||||||
// onClose(() => console.log('Disconnected'));
|
|
||||||
// onMessage((data) => console.log('Received:', data));
|
|
||||||
// });
|
|
||||||
|
|
||||||
// onUnmounted(() => {
|
|
||||||
// ws.close();
|
|
||||||
// });
|
|
||||||
|
|
||||||
return { isConnected, message, sendMessage: ws.sendMessage.bind(ws), onMessage, onClose };
|
|
||||||
}
|
|
@ -5,6 +5,7 @@
|
|||||||
<div class="map-content">
|
<div class="map-content">
|
||||||
<div class="map" id="mapcontainer"></div>
|
<div class="map" id="mapcontainer"></div>
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
|
<div class="title">设备生理数据</div>
|
||||||
<div ref="chartRef" style="width: 100%; height: 100%"></div>
|
<div ref="chartRef" style="width: 100%; height: 100%"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -20,7 +21,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="info-text">绑定关联人名称:{{ curData.username }}</div>
|
<div class="info-text">绑定关联人名称:{{ curData.username }}</div>
|
||||||
<div class="info-text">绑定关联人警号:{{ curData.userNumber }}</div>
|
<div class="info-text">绑定关联人警号:{{ curData.userNumber }}</div>
|
||||||
<div class="info-text">状态:{{ statusEnum[curData.status] }}</div>
|
<div class="info-text">
|
||||||
|
状态:
|
||||||
|
<el-tag :type="curData.status == 1 ? 'success' : 'danger'">
|
||||||
|
{{ statusEnum[curData.status] }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
<div class="info-text">紧急电话:{{ curData.adminPhone }}</div>
|
<div class="info-text">紧急电话:{{ curData.adminPhone }}</div>
|
||||||
<div class="info-text">隶属辖区:{{ curData.orgName }}</div>
|
<div class="info-text">隶属辖区:{{ curData.orgName }}</div>
|
||||||
|
|
||||||
@ -77,13 +83,14 @@
|
|||||||
<script setup lang="ts" name="incidentDispose">
|
<script setup lang="ts" name="incidentDispose">
|
||||||
import location from "@/assets/img/location.png";
|
import location from "@/assets/img/location.png";
|
||||||
import { MapCustom } from "@/utils/mapCustom";
|
import { MapCustom } from "@/utils/mapCustom";
|
||||||
import { onMounted, ref, reactive, watch } from "vue";
|
import { onMounted, ref, reactive, watch, onDeactivated, onUnmounted } from "vue";
|
||||||
import Upload from "@/components/upload-img.vue";
|
import Upload from "@/components/upload-img.vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import { warningDetail, warningConfirm } from "@/api/index";
|
import { warningDetail, warningConfirm } from "@/api/index";
|
||||||
import { TWarningConfirm, TWarningDetail } from "@/api/index.d";
|
import { TWarningConfirm, TWarningDetail } from "@/api/index.d";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { ElMessage, FormInstance, FormRules } from "element-plus";
|
import { ElMessage, FormInstance, FormRules } from "element-plus";
|
||||||
|
import { debounce, format } from "@/utils";
|
||||||
|
|
||||||
// 定义一个响应式变量
|
// 定义一个响应式变量
|
||||||
enum unitEnum {
|
enum unitEnum {
|
||||||
@ -109,29 +116,70 @@ const chartRef = ref(null);
|
|||||||
const disabled = ref(false);
|
const disabled = ref(false);
|
||||||
const ruleFormRef = ref<FormInstance>();
|
const ruleFormRef = ref<FormInstance>();
|
||||||
let map = null;
|
let map = null;
|
||||||
|
let myChart = null;
|
||||||
|
|
||||||
const ringOptions = {
|
const options = {
|
||||||
title: {
|
tooltip: {
|
||||||
text: "Stacked Line",
|
trigger: "axis",
|
||||||
left: "3%",
|
formatter: function (params) {
|
||||||
|
let unit = { 0: "次/分", 1: "%", 2: "℃" };
|
||||||
|
var res = format(options.times[params[0].dataIndex]) + "<br/>";
|
||||||
|
res += params
|
||||||
|
.map(function (param, index) {
|
||||||
|
return param.marker + param.seriesName + ":" + param.value + unit[index] + "<br/>";
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
return res;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: ["心率", "体表温度", "血氧"],
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: "0%",
|
||||||
|
right: "4%",
|
||||||
|
bottom: "3%",
|
||||||
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
boundaryGap: false,
|
||||||
|
data: [],
|
||||||
},
|
},
|
||||||
|
times: [],
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
},
|
},
|
||||||
grid: {
|
|
||||||
left: "10%",
|
|
||||||
right: "4%",
|
|
||||||
bottom: "10%",
|
|
||||||
},
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
data: [820, 932, 901, 934, 1290, 1330, 1320],
|
itemStyle: {
|
||||||
|
color: "#FF4241",
|
||||||
|
},
|
||||||
|
name: "心率",
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
showSymbol: false,
|
||||||
|
data: [],
|
||||||
|
time: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemStyle: {
|
||||||
|
color: "#12CCA2",
|
||||||
|
},
|
||||||
|
name: "血氧",
|
||||||
|
type: "line",
|
||||||
|
showSymbol: false,
|
||||||
|
data: [],
|
||||||
|
time: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemStyle: {
|
||||||
|
color: "#FF7D00",
|
||||||
|
},
|
||||||
|
showSymbol: false,
|
||||||
|
name: "体表温度",
|
||||||
|
type: "line",
|
||||||
|
data: [],
|
||||||
|
time: [],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
@ -149,7 +197,7 @@ let curData = ref<TWarningDetail.TRes>({
|
|||||||
creatUser: "",
|
creatUser: "",
|
||||||
createTime: "",
|
createTime: "",
|
||||||
deviceId: "",
|
deviceId: "",
|
||||||
healthData: "",
|
healthData: [],
|
||||||
id: 0,
|
id: 0,
|
||||||
lat: 0,
|
lat: 0,
|
||||||
lng: 0,
|
lng: 0,
|
||||||
@ -195,6 +243,16 @@ const getData = async () => {
|
|||||||
let icon = map.newIcon(location);
|
let icon = map.newIcon(location);
|
||||||
let marker = map.marker({ icon, position: [116.406315, 39.908775] });
|
let marker = map.marker({ icon, position: [116.406315, 39.908775] });
|
||||||
marker.setMap(map.map);
|
marker.setMap(map.map);
|
||||||
|
if (res.healthData && res.healthData.length) {
|
||||||
|
res.healthData.forEach((item) => {
|
||||||
|
options.times.push(item.time);
|
||||||
|
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
|
||||||
|
options.series[0].data.push(item.hr);
|
||||||
|
options.series[1].data.push(item.bo);
|
||||||
|
options.series[2].data.push(item.temp);
|
||||||
|
});
|
||||||
|
myChart.setOption(options);
|
||||||
|
}
|
||||||
} catch (error) {}
|
} catch (error) {}
|
||||||
};
|
};
|
||||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
@ -208,14 +266,22 @@ const submitForm = async (formEl: FormInstance | undefined) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleResize = debounce(() => {
|
||||||
|
myChart.resize();
|
||||||
|
}, 200);
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getData();
|
getData();
|
||||||
map = new MapCustom({ dom: "mapcontainer", center: [116.406315, 39.908775] });
|
map = new MapCustom({ dom: "mapcontainer", center: [116.406315, 39.908775] });
|
||||||
if (chartRef.value) {
|
if (chartRef.value) {
|
||||||
const myChart = echarts.init(chartRef.value);
|
myChart = echarts.init(chartRef.value);
|
||||||
myChart.setOption(ringOptions);
|
myChart.setOption(options);
|
||||||
|
window.addEventListener("resize", handleResize);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
window.removeEventListener("resize", handleResize);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@ -245,6 +311,21 @@ onMounted(() => {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
position: relative;
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
left: 0px;
|
||||||
|
top: 20px;
|
||||||
|
&::before {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 10px;
|
||||||
|
content: "";
|
||||||
|
width: 2px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 20px;
|
||||||
|
background: #061451;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,9 +51,9 @@ const rules = reactive<FormRules<typeof ruleForm>>({
|
|||||||
|
|
||||||
const submitForm = async (formEl: FormInstance | undefined) => {
|
const submitForm = async (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
|
|
||||||
await formEl.validate((valid, fields) => {
|
await formEl.validate((valid, fields) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
localStorage.setItem("isReload", "true");
|
||||||
fetchLogin(ruleForm).then((res) => {
|
fetchLogin(ruleForm).then((res) => {
|
||||||
comm.setUser(res);
|
comm.setUser(res);
|
||||||
comm.getRoleList();
|
comm.getRoleList();
|
||||||
|
@ -2,17 +2,17 @@
|
|||||||
<div class="device">
|
<div class="device">
|
||||||
<div class="device-head">
|
<div class="device-head">
|
||||||
<div class="title">设备列表</div>
|
<div class="title">设备列表</div>
|
||||||
<el-select class="select" v-model="paging.mode" @change="handelMode">
|
<el-select class="select" v-model="props.paging.mode" @change="handelMode">
|
||||||
<el-option label="全部" :value="undefined" />
|
<el-option label="全部" value="" />
|
||||||
<el-option label="常规模式" value="0" />
|
<el-option label="常规模式" value="0" />
|
||||||
<el-option label="审讯模式" value="1" />
|
<el-option label="审讯模式" value="1" />
|
||||||
<el-option label="户外押送" value="2" />
|
<el-option label="户外押送" value="2" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<div v-infinite-scroll="load" :infinite-scroll-immediate="false" class="device-list noScrollbar infinite-list" style="overflow: auto">
|
<div v-infinite-scroll="load" :infinite-scroll-immediate="false" class="device-list noScrollbar infinite-list" style="overflow: auto">
|
||||||
<el-popover :width="350" class="box-item" placement="bottom" v-for="item in list" :key="item.id">
|
<el-popover :width="350" class="box-item" placement="right" v-for="item in props.list" :key="item.id">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<div class="item" :class="{ active: deviceId === item.deviceId }" @click="emit('click', item)">
|
<div class="item" :class="{ active: props.deviceInfo?.deviceId === item.deviceId }" @click="emit('click', item)">
|
||||||
<div class="item-img">
|
<div class="item-img">
|
||||||
<img src="@/assets/img/handcuffs.png" alt="" srcset="" />
|
<img src="@/assets/img/handcuffs.png" alt="" srcset="" />
|
||||||
</div>
|
</div>
|
||||||
@ -75,7 +75,9 @@ enum modeEnum {
|
|||||||
"户外押送",
|
"户外押送",
|
||||||
}
|
}
|
||||||
const emit = defineEmits(["click"]);
|
const emit = defineEmits(["click"]);
|
||||||
const { list, paging, api, deviceId } = defineProps({
|
// const { list, paging, api, deviceInfo }
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
list: {
|
list: {
|
||||||
type: Array<TDevice.IListRes>,
|
type: Array<TDevice.IListRes>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
@ -88,19 +90,19 @@ const { list, paging, api, deviceId } = defineProps({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
deviceId: {
|
deviceInfo: {
|
||||||
type: Number || String,
|
type: Object,
|
||||||
default: () => "",
|
default: undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handelMode = () => {
|
const handelMode = () => {
|
||||||
paging.page += 1;
|
props.paging.page += 1;
|
||||||
api();
|
props.api();
|
||||||
};
|
};
|
||||||
const load = () => {
|
const load = () => {
|
||||||
paging.page += 1;
|
props.paging.page += 1;
|
||||||
api();
|
props.api();
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
<div class="title">当前设备告警记录</div>
|
<div class="title">当前设备告警记录</div>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<el-select class="select" placeholder="请选择事件类型" v-model="paging.warnType" style="width: 150px; margin-right: 20px" @change="handelChange">
|
<el-select class="select" placeholder="请选择事件类型" v-model="paging.warnType" style="width: 150px; margin-right: 20px" @change="handelChange">
|
||||||
<el-option label="全部" :value="undefined" />
|
<el-option label="全部" value="" />
|
||||||
<el-option v-for="(item, index) in warnTypeList" :key="index" :label="item" :value="index" />
|
<el-option v-for="(item, index) in warnTypeList" :key="index" :label="item" :value="index" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-select class="select" placeholder="请选择处理状态" v-model="paging.status" style="width: 150px" @change="handelChange">
|
<el-select class="select" placeholder="请选择处理状态" v-model="paging.status" style="width: 150px" @change="handelChange">
|
||||||
<el-option label="全部" :value="undefined" />
|
<el-option label="全部" value="" />
|
||||||
<el-option label="待处理" value="0" />
|
<el-option label="待处理" value="0" />
|
||||||
<el-option label="已处理" value="1" />
|
<el-option label="已处理" value="1" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<el-row class="el-row" :gutter="20">
|
<el-row class="el-row" :gutter="20">
|
||||||
<el-col :span="6" class="el-row-left"
|
<el-col :span="6" class="el-row-left"
|
||||||
><DeviceInfo :deviceId="deviceInfo?.deviceId" :paging="devicePaging" :api="getdeviceList" :list="deviceData" @click="handelClickDevice"
|
><DeviceInfo :deviceInfo="deviceInfo" :paging="devicePaging" :api="getdeviceList" :list="deviceData" @click="handelClickDevice"
|
||||||
/></el-col>
|
/></el-col>
|
||||||
<el-col :span="18" class="el-row-right scrollbar">
|
<el-col :span="18" class="el-row-right scrollbar">
|
||||||
<MonitoringTop :funcList="funcList" />
|
<MonitoringTop :funcList="funcList" />
|
||||||
@ -48,7 +48,7 @@ import { MapCustom } from "@/utils/mapCustom";
|
|||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import { deviceList, healthLatestData, warningRecord, locateRecord } from "@/api/index";
|
import { deviceList, healthLatestData, warningRecord, locateRecord } from "@/api/index";
|
||||||
import { TDevice, THealthLatestData } from "@/api/index.d";
|
import { TDevice, THealthLatestData } from "@/api/index.d";
|
||||||
import { onMounted, onDeactivated, ref, reactive } from "vue";
|
import { onMounted, onDeactivated, ref, reactive, onUnmounted } from "vue";
|
||||||
import { debounce, format } from "@/utils";
|
import { debounce, format } from "@/utils";
|
||||||
import heart from "@/assets/img/heart.png";
|
import heart from "@/assets/img/heart.png";
|
||||||
import temperature from "@/assets/img/temperature.png";
|
import temperature from "@/assets/img/temperature.png";
|
||||||
@ -58,6 +58,7 @@ import location from "@/assets/img/location.png";
|
|||||||
const chartRef = ref(null);
|
const chartRef = ref(null);
|
||||||
let myChart = null;
|
let myChart = null;
|
||||||
let newMap = null;
|
let newMap = null;
|
||||||
|
let Interval = null;
|
||||||
let funcList = ref([
|
let funcList = ref([
|
||||||
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
{ title: "当前心率", en: "DANGQIANXINLV", icon: heart, unit: "次/分", num: 0, color: "#FF0303" },
|
||||||
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
{ title: "当前血氧", en: "DANGQIANXUEYANG", icon: blood, unit: "%", num: 0, color: "#8B51FD" },
|
||||||
@ -67,7 +68,18 @@ let funcList = ref([
|
|||||||
const options = {
|
const options = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
|
formatter: function (params) {
|
||||||
|
let unit = { 心率: "次/分", 血氧: "%", 体表温度: "℃" };
|
||||||
|
var res = format(options.times[params[0].dataIndex]) + "<br/>";
|
||||||
|
res += params
|
||||||
|
.map(function (param, index) {
|
||||||
|
return param.marker + param.seriesName + ":" + param.value + unit[param.seriesName] + "<br/>";
|
||||||
|
})
|
||||||
|
.join("");
|
||||||
|
return res;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
times: [],
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: [],
|
data: [],
|
||||||
@ -83,6 +95,7 @@ const options = {
|
|||||||
name: "",
|
name: "",
|
||||||
data: [],
|
data: [],
|
||||||
type: "line",
|
type: "line",
|
||||||
|
showSymbol: false,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
color: "#ff4567", // 设置线条颜色
|
color: "#ff4567", // 设置线条颜色
|
||||||
},
|
},
|
||||||
@ -107,6 +120,7 @@ const getdeviceList = async () => {
|
|||||||
deviceInfo.value = res.records[1];
|
deviceInfo.value = res.records[1];
|
||||||
getHealthLatestData();
|
getHealthLatestData();
|
||||||
getLocateRecord();
|
getLocateRecord();
|
||||||
|
IntervalFn();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -134,6 +148,7 @@ const getOptionsData = (list: { time: string; value: number }[], name: string, c
|
|||||||
options.series.data = [];
|
options.series.data = [];
|
||||||
if (list && list.length) {
|
if (list && list.length) {
|
||||||
list.forEach((item) => {
|
list.forEach((item) => {
|
||||||
|
options.times.push(item.time);
|
||||||
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
|
options.xAxis.data.push(format(item.time, "HH:mm:ss"));
|
||||||
options.series.data.push(item.value);
|
options.series.data.push(item.value);
|
||||||
});
|
});
|
||||||
@ -166,7 +181,12 @@ const getLocateRecord = () => {
|
|||||||
const handleResize = debounce(() => {
|
const handleResize = debounce(() => {
|
||||||
myChart.resize();
|
myChart.resize();
|
||||||
}, 200);
|
}, 200);
|
||||||
|
const IntervalFn = () => {
|
||||||
|
Interval = setInterval(() => {
|
||||||
|
getHealthLatestData();
|
||||||
|
getLocateRecord();
|
||||||
|
}, 60000);
|
||||||
|
};
|
||||||
const handelClickDevice = (val: TDevice.IListRes) => {
|
const handelClickDevice = (val: TDevice.IListRes) => {
|
||||||
deviceInfo.value = val;
|
deviceInfo.value = val;
|
||||||
getHealthLatestData();
|
getHealthLatestData();
|
||||||
@ -180,7 +200,8 @@ onMounted(() => {
|
|||||||
window.addEventListener("resize", handleResize);
|
window.addEventListener("resize", handleResize);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onDeactivated(() => {
|
onUnmounted(() => {
|
||||||
|
clearInterval(Interval);
|
||||||
window.removeEventListener("resize", handleResize);
|
window.removeEventListener("resize", handleResize);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -30,7 +30,7 @@ interface TPaging {
|
|||||||
page: number;
|
page: number;
|
||||||
size: number;
|
size: number;
|
||||||
total: number;
|
total: number;
|
||||||
deviceId?: number;
|
deviceId?: number | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
@ -39,15 +39,17 @@ import StatisticsWarning from "./statisticsWarning.vue";
|
|||||||
import EmergencyList from "./emergencyList.vue";
|
import EmergencyList from "./emergencyList.vue";
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import { MapCustom } from "@/utils/mapCustom";
|
import { MapCustom } from "@/utils/mapCustom";
|
||||||
import { statisticsDevice, statisticsContent, statisticsCount, statisticsWarningapi, warnRecord } from "@/api/index";
|
import { statisticsDevice, statisticsContent, statisticsCount, statisticsWarningapi, warnRecord, statisticsUseCount } from "@/api/index";
|
||||||
import { onMounted, ref, reactive, onDeactivated } from "vue";
|
import { onMounted, ref, reactive, onDeactivated, onUnmounted } from "vue";
|
||||||
import { debounce } from "@/utils";
|
import { debounce, format } from "@/utils";
|
||||||
import { TWarnRecord } from "@/api/index.d";
|
import { TWarnRecord } from "@/api/index.d";
|
||||||
import handcuffs from "@/assets/img/handcuffs.png";
|
import handcuffs from "@/assets/img/handcuffs.png";
|
||||||
import onLine from "@/assets/img/onLine.png";
|
import onLine from "@/assets/img/onLine.png";
|
||||||
import report from "@/assets/img/report.png";
|
import report from "@/assets/img/report.png";
|
||||||
import newly from "@/assets/img/newly.png";
|
import newly from "@/assets/img/newly.png";
|
||||||
|
|
||||||
|
let d = new Date();
|
||||||
|
|
||||||
const chartRef = ref(null);
|
const chartRef = ref(null);
|
||||||
const chartRef1 = ref(null);
|
const chartRef1 = ref(null);
|
||||||
const chartRef2 = ref(null);
|
const chartRef2 = ref(null);
|
||||||
@ -95,9 +97,9 @@ let option1 = ref({
|
|||||||
type: "pie",
|
type: "pie",
|
||||||
radius: ["20%", "50%"],
|
radius: ["20%", "50%"],
|
||||||
data: [
|
data: [
|
||||||
{ value: 1048, name: "常规模式" },
|
{ value: 0, name: "常规模式" },
|
||||||
{ value: 735, name: "户外押送" },
|
{ value: 0, name: "户外押送" },
|
||||||
{ value: 580, name: "审讯模式" },
|
{ value: 0, name: "审讯模式" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -122,12 +124,13 @@ let option2 = ref({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const paging = reactive({
|
const paging = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
deviceId: "",
|
deviceId: "",
|
||||||
|
startDate: `${format(d, "YYYY-MM-DD")} 00:00:00`,
|
||||||
|
endDate: `${format(d, "YYYY-MM-DD")} 23:59:59`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const tableData = ref<TWarnRecord.IListRes[]>([]);
|
const tableData = ref<TWarnRecord.IListRes[]>([]);
|
||||||
@ -156,6 +159,16 @@ const getStatisticsWarningApi = () => {
|
|||||||
myChart2.setOption(option2.value);
|
myChart2.setOption(option2.value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const getStatisticsUseCount = () => {
|
||||||
|
statisticsUseCount().then((res) => {
|
||||||
|
option1.value.series.data = [
|
||||||
|
{ value: res.defaultCount, name: "常规模式" },
|
||||||
|
{ value: res.outsideCount, name: "户外押送" },
|
||||||
|
{ value: res.monitorCount, name: "审讯模式" },
|
||||||
|
];
|
||||||
|
myChart1.setOption(option1.value);
|
||||||
|
});
|
||||||
|
};
|
||||||
const getStatisticsContent = (res) => {
|
const getStatisticsContent = (res) => {
|
||||||
statisticsContent(res).then((res) => {
|
statisticsContent(res).then((res) => {
|
||||||
option.value.xAxis.data = res?.times;
|
option.value.xAxis.data = res?.times;
|
||||||
@ -212,6 +225,7 @@ onMounted(() => {
|
|||||||
getData();
|
getData();
|
||||||
getStatisticsCount();
|
getStatisticsCount();
|
||||||
getStatisticsWarningApi();
|
getStatisticsWarningApi();
|
||||||
|
getStatisticsUseCount();
|
||||||
|
|
||||||
new MapCustom({ dom: "mapcontainer" });
|
new MapCustom({ dom: "mapcontainer" });
|
||||||
|
|
||||||
@ -228,7 +242,7 @@ onMounted(() => {
|
|||||||
window.addEventListener("resize", handleResize);
|
window.addEventListener("resize", handleResize);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onDeactivated(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener("resize", handleResize);
|
window.removeEventListener("resize", handleResize);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<template #header>
|
<template #header>
|
||||||
<div class="card-header">使用记录</div>
|
<div class="card-header">使用记录</div>
|
||||||
</template>
|
</template>
|
||||||
<TableCustom :hasToolbar="false" :columns="record" :tableData="tableData" :total="paging.total" :currentPage="paging.page" :changePage="changePage">
|
<TableCustom :hasToolbar="false" :columns="record" :tableData="tableData" :paging="paging" :changePage="changePage">
|
||||||
<template #status="{ rows }">
|
<template #status="{ rows }">
|
||||||
{{ recordStatusEnum[rows.status] }}
|
{{ recordStatusEnum[rows.status] }}
|
||||||
</template>
|
</template>
|
||||||
|
103
src/views/synthesizeManage/deviceManage/bindArea.vue
Normal file
103
src/views/synthesizeManage/deviceManage/bindArea.vue
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="ruleFormRef" label-position="top" :model="ruleForm" status-icon :rules="rules" label-width="auto" class="demo-ruleForm">
|
||||||
|
<el-form-item label="已选择手铐">
|
||||||
|
<div>{{ deviceNames }}</div>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="辖区" prop="org">
|
||||||
|
<el-select v-model="ruleForm.org" placeholder="请选择辖区" @change="getAccountListOrg">
|
||||||
|
<el-option v-for="item in orgAllData" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="人员" prop="accountId">
|
||||||
|
<el-select v-model="ruleForm.accountId" placeholder="请选择人员">
|
||||||
|
<el-option v-for="item in accountLis" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item class="footr">
|
||||||
|
<el-button type="primary" @click="submitForm(ruleFormRef)"> 保存 </el-button>
|
||||||
|
<el-button @click="emit('close')">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, onMounted, PropType, reactive, ref, watch } from "vue";
|
||||||
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
|
import { TDevice, TOrg } from "@/api/index.d";
|
||||||
|
import { accountListOrg } from "@/api/index";
|
||||||
|
interface IForm {
|
||||||
|
devices: number[];
|
||||||
|
org: number | string;
|
||||||
|
accountId: number | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ruleFormRef = ref<FormInstance>();
|
||||||
|
const accountLis = ref([]);
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
orgAllData: {
|
||||||
|
type: Array as PropType<TOrg.IOrgRecordRes[]>,
|
||||||
|
dfault: () => {},
|
||||||
|
},
|
||||||
|
selectDeviceList: {
|
||||||
|
type: Array as PropType<TDevice.IListRes[]>,
|
||||||
|
dfault: () => {},
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["close"]);
|
||||||
|
|
||||||
|
const getAccountListOrg = (orgId: number, accountId?: number) => {
|
||||||
|
accountLis.value = [];
|
||||||
|
ruleForm.accountId = "";
|
||||||
|
accountListOrg(orgId).then((res) => {
|
||||||
|
accountLis.value = res;
|
||||||
|
if (accountId) {
|
||||||
|
ruleForm.accountId = accountId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const deviceNames = computed(() => props.selectDeviceList.map((item) => item.deviceId).join("、"));
|
||||||
|
|
||||||
|
const ruleForm = reactive<IForm>({
|
||||||
|
devices: props.selectDeviceList.map((item) => item.deviceId),
|
||||||
|
org: "",
|
||||||
|
accountId: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.selectDeviceList.length == 1) {
|
||||||
|
let item = props.selectDeviceList[0];
|
||||||
|
ruleForm.org = item.orgId;
|
||||||
|
getAccountListOrg(item.orgId, item.accountId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive<FormRules<typeof ruleForm>>({
|
||||||
|
org: [{ required: true, message: "请选择辖区", trigger: "blur" }],
|
||||||
|
accountId: [{ required: true, message: "请选择人员", trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
props.api(ruleForm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.footr {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.footr :deep(.el-form-item__content) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -2,10 +2,10 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<TableCustom :columns="columns" :tableData="tableData" :paging="paging" :changePage="changePage">
|
<TableCustom :selection-change="handleSelect" :columns="columns" :tableData="tableData" :paging="paging" :changePage="changePage">
|
||||||
<template #toolbarBtn>
|
<template #toolbarBtn>
|
||||||
<!-- <el-button type="primary" @click="handleAdd">新增</el-button> -->
|
<!-- <el-button type="primary" @click="handleAdd">新增</el-button> -->
|
||||||
<el-button @click="handleEdit">手铐关联</el-button>
|
<el-button @click="handleEdit()">设备关联</el-button>
|
||||||
<!-- <el-button>地图位置</el-button> -->
|
<!-- <el-button>地图位置</el-button> -->
|
||||||
<!-- <el-button>导出</el-button> -->
|
<!-- <el-button>导出</el-button> -->
|
||||||
</template>
|
</template>
|
||||||
@ -41,18 +41,22 @@
|
|||||||
<!-- <TableEdit :form-data="rowData" :options="controlOptions" :update="updateData" /> -->
|
<!-- <TableEdit :form-data="rowData" :options="controlOptions" :update="updateData" /> -->
|
||||||
<DeviceControl v-model="controlForm" @change="handelControl" />
|
<DeviceControl v-model="controlForm" @change="handelControl" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog title="设备关联" v-model="visible2" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
||||||
|
<BindArea :orgAllData="orgAllData" :selectDeviceList="selectDeviceList" @close="visible2 = false" :api="bindWebFn" />
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="basetable">
|
<script setup lang="ts" name="basetable">
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, onMounted } from "vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { deviceList, setMode, deviceGetLocation, deviceControl, setUseStatus, setStatus } from "@/api/index";
|
import { deviceList, setMode, deviceGetLocation, deviceControl, setUseStatus, setStatus, orgAllList, bindWeb } from "@/api/index";
|
||||||
import { TDevice } from "@/api/index.d";
|
import { TbindWeb, TDevice, TOrg } from "@/api/index.d";
|
||||||
import TableCustom from "@/components/table-custom.vue";
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableSearch from "@/components/table-search.vue";
|
import TableSearch from "@/components/table-search.vue";
|
||||||
import TableEdit from "@/components/table-edit.vue";
|
import TableEdit from "@/components/table-edit.vue";
|
||||||
import DeviceControl from "./deviceControl.vue";
|
import DeviceControl from "./deviceControl.vue";
|
||||||
|
import BindArea from "./bindArea.vue";
|
||||||
import { TableItem } from "@/types/table";
|
import { TableItem } from "@/types/table";
|
||||||
import { FormOption, FormOptionList } from "@/types/form-option";
|
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||||
import { useRouter } from "vue-router";
|
import { useRouter } from "vue-router";
|
||||||
@ -82,9 +86,8 @@ let TableEditOptions = ref<FormOption>({
|
|||||||
const addOp = [{ type: "input", label: "唯一编码", prop: "name", required: true }];
|
const addOp = [{ type: "input", label: "唯一编码", prop: "name", required: true }];
|
||||||
const editOp = [
|
const editOp = [
|
||||||
{ type: "select", label: "选择手铐", prop: "name", required: true },
|
{ type: "select", label: "选择手铐", prop: "name", required: true },
|
||||||
{ type: "input", label: "唯一编码", prop: "name1" },
|
{ type: "select", label: "辖区列表", prop: "name2" },
|
||||||
{ type: "select", label: "辖区绑定", prop: "name2" },
|
{ type: "select", label: "账号列表", prop: "name3" },
|
||||||
{ type: "input", label: "紧急电话", prop: "name3" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// 查询相关
|
// 查询相关
|
||||||
@ -125,24 +128,24 @@ const searchOpt = ref<FormOptionList[]>([
|
|||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
changePage(1);
|
changePage(1);
|
||||||
};
|
};
|
||||||
|
const selectDeviceList = ref<TDevice.IListRes[]>([]);
|
||||||
// 表格相关
|
// 表格相关
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ type: "selection" },
|
{ type: "selection", reserveSelection: true },
|
||||||
{ type: "index", label: "序号", width: 55, align: "center" },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: "deviceId", label: "手铐IMEI", width: 120 },
|
{ prop: "deviceId", label: "IMEI", width: 120 },
|
||||||
{ prop: "adminName", label: "绑定警察名称", width: 180 },
|
{ prop: "adminName", label: "绑定警察名称", width: 180 },
|
||||||
{ prop: "adminUsername", label: "绑定警察账户", width: 120 },
|
{ prop: "adminUsername", label: "绑定警察账户", width: 120 },
|
||||||
|
{ prop: "orgName", label: "关联辖区", width: 120 },
|
||||||
{ prop: "battery", label: "电量", width: 100 },
|
{ prop: "battery", label: "电量", width: 100 },
|
||||||
{ prop: "deviceVersion", label: "版本号", width: 100 },
|
{ prop: "deviceVersion", label: "版本号", width: 100 },
|
||||||
{ prop: "status", label: "设备状态", width: 100 },
|
{ prop: "status", label: "设备状态", width: 100 },
|
||||||
{ prop: "mode", label: "当前模式", width: 100 },
|
{ prop: "mode", label: "当前模式", width: 100 },
|
||||||
{ prop: "useStatus", label: "使用状态", width: 100 },
|
{ prop: "useStatus", label: "使用状态", width: 100 },
|
||||||
{ prop: "deviceSwitch", label: "启用开关", width: 100 },
|
{ prop: "deviceSwitch", label: "启用开关", width: 100 },
|
||||||
{ prop: "orgName", label: "关联辖区编号", width: 120 },
|
|
||||||
{ prop: "createTime", label: "最新通信时间", width: 180 },
|
{ prop: "createTime", label: "最新通信时间", width: 180 },
|
||||||
{ prop: "createTime", label: "创建时间", width: 180 },
|
{ prop: "createTime", label: "创建时间", width: 180 },
|
||||||
{ prop: "operator", label: "操作", width: 400 },
|
{ prop: "operator", label: "操作", width: 400, fixed: "right" },
|
||||||
]);
|
]);
|
||||||
const paging = reactive({
|
const paging = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
@ -155,18 +158,32 @@ const controlForm = reactive({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const tableData = ref<TDevice.IListRes[]>([]);
|
const tableData = ref<TDevice.IListRes[]>([]);
|
||||||
|
const orgAllData = ref<TOrg.IOrgRecordRes[]>([]);
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await deviceList({ ...paging, ...query });
|
const res = await deviceList({ ...paging, ...query });
|
||||||
tableData.value = res.records;
|
tableData.value = res.records;
|
||||||
paging.total = res.total;
|
paging.total = res.total;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const bindWebFn = (val: TbindWeb) => {
|
||||||
|
bindWeb(val).then(() => {
|
||||||
|
ElMessage.success("操作成功");
|
||||||
|
visible2.value = false;
|
||||||
|
getData();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = (val: TDevice.IListRes[]) => {
|
||||||
|
selectDeviceList.value = val;
|
||||||
|
};
|
||||||
|
|
||||||
const changePage = (val: number) => {
|
const changePage = (val: number) => {
|
||||||
paging.page = val;
|
paging.page = val;
|
||||||
getData();
|
getData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const visible1 = ref(false);
|
const visible1 = ref(false);
|
||||||
|
const visible2 = ref(false);
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const rowData = ref<TDevice.IListRes>();
|
const rowData = ref<TDevice.IListRes>();
|
||||||
@ -178,10 +195,11 @@ const handleAdd = () => {
|
|||||||
|
|
||||||
// 编辑
|
// 编辑
|
||||||
const handleEdit = (row?: TDevice.IListRes) => {
|
const handleEdit = (row?: TDevice.IListRes) => {
|
||||||
rowData.value = { ...row };
|
if (row) {
|
||||||
TableEditOptions.value.list = editOp;
|
selectDeviceList.value = [row];
|
||||||
isEdit.value = true;
|
}
|
||||||
visible.value = true;
|
if (selectDeviceList.value.length == 0) return ElMessage.warning("请选择设备");
|
||||||
|
visible2.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handelRow = (row?: TDevice.IListRes) => {
|
const handelRow = (row?: TDevice.IListRes) => {
|
||||||
@ -199,6 +217,12 @@ const handelSwitch = (val: TDevice.IListRes, type: number) => {
|
|||||||
ElMessage.success("操作成功");
|
ElMessage.success("操作成功");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getOrgAllList = () => {
|
||||||
|
orgAllList().then((res) => {
|
||||||
|
orgAllData.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
const handelControl = (type: number) => {
|
const handelControl = (type: number) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 4:
|
case 4:
|
||||||
@ -247,6 +271,7 @@ const closeDialog = () => {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getData();
|
getData();
|
||||||
|
getOrgAllList();
|
||||||
});
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -82,10 +82,8 @@ let InfoWin = null;
|
|||||||
|
|
||||||
const params = reactive<TLocateRecord.TReq>({
|
const params = reactive<TLocateRecord.TReq>({
|
||||||
deviceId: query.deviceId as string,
|
deviceId: query.deviceId as string,
|
||||||
// startDate: `${format(d, "YYYY-MM-DD")} 00:00:00`,
|
startDate: `${format(d, "YYYY-MM-DD")} 00:00:00`,
|
||||||
// endDate: `${format(d, "YYYY-MM-DD")} 23:59:59`,
|
endDate: `${format(d, "YYYY-MM-DD")} 23:59:59`,
|
||||||
startDate: "2021-04-14 00:00:00",
|
|
||||||
endDate: "2025-05-14 23:59:59",
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const weekChange = (val: any) => {
|
const weekChange = (val: any) => {
|
||||||
|
104
src/views/synthesizeManage/userManage/addUser.vue
Normal file
104
src/views/synthesizeManage/userManage/addUser.vue
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="用户名称" prop="name">
|
||||||
|
<el-input v-model="ruleForm.name" placeholder="请输入用户名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="电话号码" prop="phone">
|
||||||
|
<el-input :maxlength="11" v-model="ruleForm.phone" placeholder="请输入电话号码" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="警员号" prop="username">
|
||||||
|
<el-input :maxlength="20" v-model="ruleForm.username" placeholder="请输入警员号" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="类型" prop="roleId">
|
||||||
|
<el-select v-model="ruleForm.roleId" placeholder="请选择人员">
|
||||||
|
<el-option v-for="item in comm.roleList" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="辖区" prop="orgId">
|
||||||
|
<el-select v-model="ruleForm.orgId" placeholder="请选择辖区">
|
||||||
|
<el-option v-for="item in orgAllData" :label="item.name" :value="item.id" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态" prop="status">
|
||||||
|
<el-switch v-model="ruleForm.status" :active-value="1" :inactive-value="0" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item class="footr">
|
||||||
|
<el-button type="primary" @click="submitForm(ruleFormRef)"> 保存 </el-button>
|
||||||
|
<el-button @click="emit('close')">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, PropType, reactive, ref } from "vue";
|
||||||
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
|
import { TDevice, TOrg } from "@/api/index.d";
|
||||||
|
import { useCommonStore } from "@/store/common";
|
||||||
|
import { TAccount } from "@/api/index.d";
|
||||||
|
|
||||||
|
const comm = useCommonStore();
|
||||||
|
const ruleFormRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const { orgAllData, formData, api } = defineProps({
|
||||||
|
orgAllData: {
|
||||||
|
type: Array as PropType<TOrg.IOrgRecordRes[]>,
|
||||||
|
dfault: () => {},
|
||||||
|
},
|
||||||
|
formData: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["close"]);
|
||||||
|
|
||||||
|
const ruleForm = reactive(
|
||||||
|
formData
|
||||||
|
? { ...formData }
|
||||||
|
: {
|
||||||
|
name: "",
|
||||||
|
phone: "",
|
||||||
|
username: "",
|
||||||
|
roleId: "",
|
||||||
|
orgId: "",
|
||||||
|
status: 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {});
|
||||||
|
const rules = reactive<FormRules<typeof ruleForm>>({
|
||||||
|
name: [{ required: true, message: "请输入用户名称", trigger: "blur" }],
|
||||||
|
phone: [
|
||||||
|
{ required: true, message: "请输入电话号码", trigger: "blur" },
|
||||||
|
{ min: 11, message: "请输入11位手机号", trigger: "blur" },
|
||||||
|
],
|
||||||
|
username: [
|
||||||
|
{ required: true, message: "请输入警员号", trigger: "blur" },
|
||||||
|
{ min: 5, message: "警员号长度不能小于5位", trigger: "blur" },
|
||||||
|
],
|
||||||
|
roleId: [{ required: true, message: "请选择人员", trigger: "blur" }],
|
||||||
|
orgId: [{ required: true, message: "请选择辖区", trigger: "blur" }],
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
api(ruleForm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.footr {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.footr :deep(.el-form-item__content) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -38,7 +38,10 @@
|
|||||||
</TableCustom>
|
</TableCustom>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="dialogTitle" v-model="visible" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
<el-dialog :title="dialogTitle" v-model="visible" width="700px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
||||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" @close="closeDialog" />
|
<AddUser :orgAllData="orgAllData" :form-data="rowData" :api="updateData" @close="closeDialog" />
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog title="重置密码" v-model="visible1" width="700px" destroy-on-close :close-on-click-modal="false" @close="visible1 = false">
|
||||||
|
<ResetPwd :api="handleResetPwd" @close="visible1 = false" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="编辑类型" v-model="typeVisible" width="800px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
<el-dialog title="编辑类型" v-model="typeVisible" width="800px" destroy-on-close :close-on-click-modal="false" @close="closeDialog">
|
||||||
<UserType :typeHeadList="typeHeadList" :roleListData="roleListData" @complete="saveType" @addType="addType" />
|
<UserType :typeHeadList="typeHeadList" :roleListData="roleListData" @complete="saveType" @addType="addType" />
|
||||||
@ -50,16 +53,18 @@
|
|||||||
<script setup lang="ts" name="basetable">
|
<script setup lang="ts" name="basetable">
|
||||||
import { ref, reactive, onMounted } from "vue";
|
import { ref, reactive, onMounted } from "vue";
|
||||||
import { ElMessage, ElMessageBox } from "element-plus";
|
import { ElMessage, ElMessageBox } from "element-plus";
|
||||||
import { accountAdd, accountModify, accountList, accountDeletet, passwordReset, roleList, roleMenuList, roleModify, roleAdd } from "@/api/index";
|
import { accountAdd, accountModify, accountList, accountDeletet, passwordReset, roleList, roleMenuList, roleModify, roleAdd, orgAllList } from "@/api/index";
|
||||||
import TableCustom from "@/components/table-custom.vue";
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableSearch from "@/components/table-search.vue";
|
import TableSearch from "@/components/table-search.vue";
|
||||||
import TableEdit from "@/components/table-edit.vue";
|
import TableEdit from "@/components/table-edit.vue";
|
||||||
import BatchImp from "@/components/batch-imp.vue";
|
import BatchImp from "@/components/batch-imp.vue";
|
||||||
|
import AddUser from "./addUser.vue";
|
||||||
import { useCommonStore } from "@/store/common";
|
import { useCommonStore } from "@/store/common";
|
||||||
import UserType from "./userType.vue";
|
import UserType from "./userType.vue";
|
||||||
|
import ResetPwd from "./resetPwd.vue";
|
||||||
import { TableItem } from "@/types/table";
|
import { TableItem } from "@/types/table";
|
||||||
import { FormOption, FormOptionList } from "@/types/form-option";
|
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||||
import { TAccount, TRoleList, TRoleMenuList, TRoleModify } from "@/api/index.d";
|
import { TAccount, TOrg, TRoleList, TRoleMenuList, TRoleModify } from "@/api/index.d";
|
||||||
// import { Hide, View } from "@element-plus/icons-vue";
|
// import { Hide, View } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
enum roleEnum {
|
enum roleEnum {
|
||||||
@ -70,14 +75,15 @@ enum roleEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const comm = useCommonStore();
|
const comm = useCommonStore();
|
||||||
|
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
|
const visible1 = ref(false);
|
||||||
const typeVisible = ref(false);
|
const typeVisible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const dialogTitle = ref("");
|
const dialogTitle = ref("");
|
||||||
const rowData = ref<TAccount.IListRes | undefined>();
|
const rowData = ref<TAccount.IListRes | undefined>();
|
||||||
// 类型列表头列表
|
// 类型列表头列表
|
||||||
let typeHeadList = ref<TRoleMenuList.TRes[]>([]);
|
let typeHeadList = ref<TRoleMenuList.TRes[]>([]);
|
||||||
|
const orgAllData = ref<TOrg.IOrgRecordRes[]>([]);
|
||||||
// 查询相关
|
// 查询相关
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
name: "",
|
name: "",
|
||||||
@ -125,51 +131,12 @@ let columns = ref([
|
|||||||
{ prop: "phone", label: "手机号" },
|
{ prop: "phone", label: "手机号" },
|
||||||
// { prop: "password", label: "密码", width: 120 },
|
// { prop: "password", label: "密码", width: 120 },
|
||||||
{ prop: "roleId", label: "类型" },
|
{ prop: "roleId", label: "类型" },
|
||||||
|
{ prop: "orgName", label: "辖区" },
|
||||||
{ prop: "createTime", label: "创建时间" },
|
{ prop: "createTime", label: "创建时间" },
|
||||||
{ prop: "status", label: "状态" },
|
{ prop: "status", label: "状态" },
|
||||||
{ prop: "operator", label: "操作", width: 250 },
|
{ prop: "operator", label: "操作", width: 250 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let addOpt = {
|
|
||||||
labelWidth: "100px",
|
|
||||||
span: 24,
|
|
||||||
list: [
|
|
||||||
{ placeholder: "请输入用户名称", type: "input", label: "用户名称", prop: "name", required: true },
|
|
||||||
{ placeholder: "请输入电话号码", type: "input", label: "电话号码", prop: "phone", required: true },
|
|
||||||
{ placeholder: "请输入警员号", type: "input", label: "警员号", prop: "username", required: true },
|
|
||||||
{
|
|
||||||
placeholder: "请选择类型",
|
|
||||||
type: "select",
|
|
||||||
label: "类型",
|
|
||||||
opts: [
|
|
||||||
{ label: "管理员", value: -1 },
|
|
||||||
{ label: "警察", value: 1 },
|
|
||||||
{ label: "辅警", value: 2 },
|
|
||||||
{ label: "协警", value: 3 },
|
|
||||||
],
|
|
||||||
prop: "roleId",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{ placeholder: "请输入密码", type: "password", label: "密码", prop: "password", required: true },
|
|
||||||
{ type: "switch", label: "状态", prop: "status", activeValue: 1, inactiveValue: 0 },
|
|
||||||
// { placeholder: "请输入确认密码", type: "password", label: "确认密码", prop: "confirmpassword" },
|
|
||||||
// { placeholder: "请输入备注", type: "textarea", label: "备注", prop: "mon8ey" },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
// 新增/编辑弹窗相关
|
|
||||||
let options = ref<FormOption>();
|
|
||||||
// 重置密码
|
|
||||||
let pwdOpt = {
|
|
||||||
labelWidth: "100px",
|
|
||||||
span: 24,
|
|
||||||
list: [
|
|
||||||
// { type: "password", label: "原始密码", prop: "name1", required: true },
|
|
||||||
{ type: "password", label: "新密码", prop: "password", required: true },
|
|
||||||
// { type: "password", label: "确认密码", prop: "money3", required: true },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleImp = () => {
|
const handleImp = () => {
|
||||||
batchImpRef.value.dialogVisible = true;
|
batchImpRef.value.dialogVisible = true;
|
||||||
};
|
};
|
||||||
@ -182,15 +149,7 @@ const changePage = (val: number) => {
|
|||||||
paging.page = val;
|
paging.page = val;
|
||||||
getData();
|
getData();
|
||||||
};
|
};
|
||||||
const roleListFn = () => {
|
|
||||||
roleList().then((res) => {
|
|
||||||
roleListData.value = res;
|
|
||||||
let opts = res?.map((item) => {
|
|
||||||
return { label: item.name, value: item.id };
|
|
||||||
});
|
|
||||||
addOpt.list[3].opts = opts;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await accountList({ ...paging, ...query });
|
const res = await accountList({ ...paging, ...query });
|
||||||
tableData.value = res.records?.map((item) => {
|
tableData.value = res.records?.map((item) => {
|
||||||
@ -200,6 +159,11 @@ const getData = async () => {
|
|||||||
paging.total = res.total;
|
paging.total = res.total;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getOrgAllList = () => {
|
||||||
|
orgAllList().then((res) => {
|
||||||
|
orgAllData.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
// 删除相关
|
// 删除相关
|
||||||
const handelDel = (row: TableItem) => {
|
const handelDel = (row: TableItem) => {
|
||||||
ElMessageBox.confirm("确定要删除吗?", "提示", {
|
ElMessageBox.confirm("确定要删除吗?", "提示", {
|
||||||
@ -219,7 +183,7 @@ const updateData = (res) => {
|
|||||||
p = { ...res, id: rowData.value.id };
|
p = { ...res, id: rowData.value.id };
|
||||||
msg = "重置成功";
|
msg = "重置成功";
|
||||||
} else {
|
} else {
|
||||||
p = { ...res, orgId: comm.user.orgId };
|
p = { ...res };
|
||||||
api = isEdit.value ? accountModify : accountAdd;
|
api = isEdit.value ? accountModify : accountAdd;
|
||||||
msg = isEdit.value ? "修改成功" : "新增成功";
|
msg = isEdit.value ? "修改成功" : "新增成功";
|
||||||
}
|
}
|
||||||
@ -230,41 +194,44 @@ const updateData = (res) => {
|
|||||||
getData();
|
getData();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
const handleResetPwd = (res) => {
|
||||||
|
passwordReset({ ...res, id: rowData.value.id }).then((res) => {
|
||||||
|
ElMessage.success("密码重置成功");
|
||||||
|
visible1.value = true;
|
||||||
|
});
|
||||||
|
};
|
||||||
const saveType = (row: TRoleModify.Ireq) => {
|
const saveType = (row: TRoleModify.Ireq) => {
|
||||||
const api = row.id ? roleModify : roleAdd;
|
const api = row.id ? roleModify : roleAdd;
|
||||||
api(row).then(() => {
|
api(row).then(() => {
|
||||||
ElMessage.success("保存成功");
|
ElMessage.success("保存成功");
|
||||||
comm.getRoleList();
|
comm.getRoleList();
|
||||||
// roleListFn();
|
|
||||||
// typeVisible.value = false;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const addType = () => {
|
const addType = () => {
|
||||||
roleListData.value.push({ name: "", roleMenu: [] });
|
roleListData.value.push({ name: "", roleMenu: [] });
|
||||||
};
|
};
|
||||||
|
const roleListFn = () => {
|
||||||
|
roleList().then((res) => {
|
||||||
|
roleListData.value = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
const closeDialog = () => {
|
const closeDialog = () => {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
isEdit.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handelRow = (name: string, row?: TAccount.IListRes) => {
|
const handelRow = (name: string, row?: TAccount.IListRes) => {
|
||||||
if (name == "add") {
|
if (name == "add") {
|
||||||
dialogTitle.value = "新增用户";
|
dialogTitle.value = "新增用户";
|
||||||
options.value = { ...addOpt };
|
|
||||||
rowData.value = undefined;
|
rowData.value = undefined;
|
||||||
isEdit.value = false;
|
visible.value = true;
|
||||||
} else if (name == "pwd") {
|
} else if (name == "pwd") {
|
||||||
dialogTitle.value = "重置密码";
|
|
||||||
options.value = { ...pwdOpt };
|
|
||||||
rowData.value = { ...row };
|
rowData.value = { ...row };
|
||||||
isEdit.value = true;
|
visible1.value = true;
|
||||||
} else if (name == "edit") {
|
} else if (name == "edit") {
|
||||||
dialogTitle.value = "编辑";
|
dialogTitle.value = "编辑";
|
||||||
isEdit.value = true;
|
|
||||||
options.value = { ...addOpt };
|
|
||||||
rowData.value = { ...row };
|
rowData.value = { ...row };
|
||||||
|
visible.value = true;
|
||||||
}
|
}
|
||||||
visible.value = true;
|
|
||||||
};
|
};
|
||||||
const getRoleMenuList = () => {
|
const getRoleMenuList = () => {
|
||||||
roleMenuList().then((res) => {
|
roleMenuList().then((res) => {
|
||||||
@ -272,9 +239,10 @@ const getRoleMenuList = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
roleListFn();
|
|
||||||
getData();
|
getData();
|
||||||
getRoleMenuList();
|
getRoleMenuList();
|
||||||
|
getOrgAllList();
|
||||||
|
roleListFn();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
58
src/views/synthesizeManage/userManage/resetPwd.vue
Normal file
58
src/views/synthesizeManage/userManage/resetPwd.vue
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<template>
|
||||||
|
<el-form ref="ruleFormRef" :model="ruleForm" :rules="rules" label-width="100px">
|
||||||
|
<el-form-item label="新密码" prop="password">
|
||||||
|
<el-input v-model="ruleForm.password" type="password" placeholder="请输入新密码" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item class="footr">
|
||||||
|
<el-button type="primary" @click="submitForm(ruleFormRef)"> 保存 </el-button>
|
||||||
|
<el-button @click="emit('close')">取消</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, reactive, ref } from "vue";
|
||||||
|
import type { FormInstance } from "element-plus";
|
||||||
|
|
||||||
|
const ruleFormRef = ref<FormInstance>();
|
||||||
|
|
||||||
|
const { api } = defineProps({
|
||||||
|
api: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emit = defineEmits(["close"]);
|
||||||
|
|
||||||
|
const ruleForm = reactive({
|
||||||
|
password: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(() => {});
|
||||||
|
const rules = reactive({
|
||||||
|
password: [
|
||||||
|
{ required: true, message: "请输入新密码", trigger: "blur" },
|
||||||
|
{ min: 6, message: "密码长度不能小于6位", trigger: "blur" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.validate((valid) => {
|
||||||
|
if (valid) {
|
||||||
|
api(ruleForm);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.footr {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.footr :deep(.el-form-item__content) {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: flex-end;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
31
sta.html
31
sta.html
@ -1,31 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh-CN">
|
|
||||||
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>背景音乐示例</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<h1>欢迎来到我的网站</h1>
|
|
||||||
<!-- 插入背景音乐 -->
|
|
||||||
<audio id="bgm" loop controls>
|
|
||||||
<source src="./src/assets/audio/alarm.mp3" type="audio/mpeg">
|
|
||||||
您的浏览器不支持 audio 标签。
|
|
||||||
</audio>
|
|
||||||
|
|
||||||
<!-- 点击页面播放音乐js -->
|
|
||||||
<script>
|
|
||||||
document.addEventListener('click', function () {
|
|
||||||
var audioElement = document.getElementById('bgm');
|
|
||||||
if (audioElement.paused) { // 检查音频是否已播放
|
|
||||||
audioElement.volume = 0.5; // 设置音量
|
|
||||||
audioElement.play(); // 播放音频
|
|
||||||
}
|
|
||||||
}, { once: true }); // 确保事件处理器只执行一次
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
|
Loading…
x
Reference in New Issue
Block a user