Browse Source

寝室

master
wwp 4 months ago
parent
commit
5686453cea
15 changed files with 1031 additions and 84 deletions
  1. +50
    -0
      SafeCampus.WEB/src/api/interface/sys/usermanage/dormitory.ts
  2. +1
    -0
      SafeCampus.WEB/src/api/interface/sys/usermanage/index.ts
  3. +1
    -3
      SafeCampus.WEB/src/api/modules/monitor/live.ts
  4. +77
    -0
      SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts
  5. +1
    -0
      SafeCampus.WEB/src/api/modules/usermanage/index.ts
  6. +13
    -13
      SafeCampus.WEB/src/views/home/index.vue
  7. +3
    -2
      SafeCampus.WEB/src/views/monitor/live/index.scss
  8. +30
    -9
      SafeCampus.WEB/src/views/monitor/live/index.vue
  9. +58
    -47
      SafeCampus.WEB/src/views/sysconfig/ability/index.vue
  10. +137
    -0
      SafeCampus.WEB/src/views/userManage/dormitory/components/form/form_basic.vue
  11. +119
    -0
      SafeCampus.WEB/src/views/userManage/dormitory/components/form/index.vue
  12. +107
    -0
      SafeCampus.WEB/src/views/userManage/dormitory/components/formClass/index.vue
  13. +116
    -0
      SafeCampus.WEB/src/views/userManage/dormitory/components/formTeacher/index.vue
  14. +285
    -0
      SafeCampus.WEB/src/views/userManage/dormitory/index.vue
  15. +33
    -10
      SafeCampus.WEB/src/views/warn/zjrq/index.vue

+ 50
- 0
SafeCampus.WEB/src/api/interface/sys/usermanage/dormitory.ts View File

@@ -0,0 +1,50 @@
/**
* @description 用户管理接口
* @license Apache License Version 2.0
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
* @remarks
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关
*/

import { ReqPage } from "@/api";
/**
* @Description: 寝室管理接口
* @Author: wwp
* @Date: 2024-07-24 15:34:54
*/

export namespace SysDormitory {
// 宿舍楼树信息
export interface DormitoryInfo {
id?: string | number | undefined;
name?: string | undefined;
gender?: boolean | undefined;
createTime?: string | undefined;
}
// 寝室列表传参
export interface Page extends ReqPage {
buildId?: string | undefined | number;
gender?: any;
name?: string | undefined;
}
// 寝室列表信息
export interface ChamberInfo {
id?: string | undefined | number;
name?: string | undefined;
gender?: boolean | undefined;
buildId?: string | undefined | number;
personCount?: string | undefined | number;
createTime?: string | undefined;
}
// 寝室分配人员
export interface ChamberPersonnel {
dormitoryId: string | undefined | number;
personIds: Array<string | number>;
}
}

+ 1
- 0
SafeCampus.WEB/src/api/interface/sys/usermanage/index.ts View File

@@ -14,3 +14,4 @@
*/ */
export * from "./personnel"; export * from "./personnel";
export * from "./clothing"; export * from "./clothing";
export * from "./dormitory";

+ 1
- 3
SafeCampus.WEB/src/api/modules/monitor/live.ts View File

@@ -86,9 +86,7 @@ const monitorLiveButtonCode = {
/** 删除监控 */ /** 删除监控 */
delete: "monitorLiveDelete", delete: "monitorLiveDelete",
/** 批量删除监控 */ /** 批量删除监控 */
batchDelete: "monitorLiveBatchDelete",
/** 复制监控 */
copy: "monitorLiveCopy"
batchDelete: "monitorLiveBatchDelete"
}; };


export { monitorLIVEApi, monitorLiveButtonCode }; export { monitorLIVEApi, monitorLiveButtonCode };

+ 77
- 0
SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts View File

@@ -0,0 +1,77 @@
/**
* @description 单页管理接口
* @license Apache License Version 2.0
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
* @remarks
* SimpleAdmin 基于 Apache License Version 2.0 协议发布,可用于商业项目,但必须遵守以下补充条款:
* 1.请不要删除和修改根目录下的LICENSE文件。
* 2.请不要删除和修改SimpleAdmin源码头部的版权声明。
* 3.分发源码时候,请注明软件出处 https://gitee.com/dotnetmoyu/SimpleAdmin
* 4.基于本软件的作品,只能使用 SimpleAdmin 作为后台服务,除外情况不可商用且不允许二次分发或开源。
* 5.请不得将本软件应用于危害国家安全、荣誉和利益的行为,不能以任何形式用于非法为目的的行为不要删除和修改作者声明。
* 6.任何基于本软件而产生的一切法律纠纷和责任,均于我司无关
* @see https://gitee.com/dotnetmoyu/SimpleAdmin
*/
import { moduleRequest } from "@/api/request";
import { ReqId, ResPage, ReqPersonId, SysDormitory } from "@/api/interface";
const http = moduleRequest("/business/building/");
const httpChamber = moduleRequest("/business/dormitory/");

/**
* @Description: 单页管理
* @Author: wwp
* @Date: 2023-12-15 15:34:54
*/
const userManageDormitoryApi = {
// 获取宿舍楼树
list(params: any) {
return http.get("getNoPageList", params);
},
// 新增宿舍楼
addDormitory(params: any) {
return http.post("add", params);
},
// 修改宿舍楼
updateDormitory(params: any) {
return http.put("update", params);
},
// 删除宿舍楼
deleteDormitory(params: ReqId) {
return http.delete("delete", params);
},
// 获取寝室列表
page(params: SysDormitory.Page) {
return httpChamber.get("getPageList", params);
},
/** 新增寝室 */
add(params: SysDormitory.ChamberInfo) {
return httpChamber.post("add", params);
},
/** 修改寝室 */
update(params: SysDormitory.ChamberInfo) {
return httpChamber.put("update", params);
},
/** 删除寝室 */
delete(params: ReqId) {
return httpChamber.delete("delete", params);
},
/**寝室分配人员*/
assignPersonnel(params: SysDormitory.ChamberPersonnel) {
return httpChamber.post("assignPersonnel", params);
}
/** 获取单页详情 */
// detail(params: ReqId) {
// return http.get("getPersionById", params);
// },
};

const dormitoryButtonCode = {
/** 新增人员 */
add: "userManageDormitoryAdd",
/** 删除人员 */
edit: "userManageDormitoryEdit",
/** 删除人员 */
delete: "userManageDormitoryDelete"
};

export { userManageDormitoryApi, dormitoryButtonCode };

+ 1
- 0
SafeCampus.WEB/src/api/modules/usermanage/index.ts View File

@@ -17,3 +17,4 @@ export * from "./classManage";
export * from "./clothing"; export * from "./clothing";
export * from "./teacher"; export * from "./teacher";
export * from "./keyPersonnel"; export * from "./keyPersonnel";
export * from "./dormitory";

+ 13
- 13
SafeCampus.WEB/src/views/home/index.vue View File

@@ -27,7 +27,7 @@
</div> </div>
<div class="home-bg-content-item-content"> <div class="home-bg-content-item-content">
<div class="home-bg-content-item-title">告警信息总量</div> <div class="home-bg-content-item-title">告警信息总量</div>
<div class="home-bg-content-item-value">197218</div>
<div class="home-bg-content-item-value">1972</div>
</div> </div>
</div></el-col </div></el-col
> >
@@ -350,27 +350,27 @@ const columns: ColumnProps<ZJRQ.WarnInfo>[] = [
const tableData = ref([ const tableData = ref([
{ {
type: "今日", type: "今日",
warntotal: "828",
lowrisk: "675",
highrisk: "153"
warntotal: "20",
lowrisk: "10",
highrisk: "10"
}, },
{ {
type: "本周", type: "本周",
warntotal: "828",
lowrisk: "675",
highrisk: "153"
warntotal: "50",
lowrisk: "20",
highrisk: "30"
}, },
{ {
type: "本月", type: "本月",
warntotal: "19813",
lowrisk: "17671",
highrisk: "2129"
warntotal: "198",
lowrisk: "176",
highrisk: "22"
}, },
{ {
type: "上月", type: "上月",
warntotal: "21789",
lowrisk: "0",
highrisk: "0"
warntotal: "10",
lowrisk: "5",
highrisk: "5"
}, },


{ {


+ 3
- 2
SafeCampus.WEB/src/views/monitor/live/index.scss View File

@@ -30,7 +30,8 @@
.node-label { .node-label {
width: 100px; width: 100px;
overflow: hidden; overflow: hidden;
font-size: 16px;

// font-size: 16px;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
@@ -50,7 +51,7 @@
} }
} }
:deep(.el-tree-node__content) { :deep(.el-tree-node__content) {
height: 50px;
height: 33px;
} }
} }
.el-input { .el-input {


+ 30
- 9
SafeCampus.WEB/src/views/monitor/live/index.vue View File

@@ -30,12 +30,12 @@
<span class="custom-tree-node"> <span class="custom-tree-node">
<span class="node-label" :title="node.label">{{ node.label }}</span> <span class="node-label" :title="node.label">{{ node.label }}</span>
<span v-if="data.id && data.id != '-1'"> <span v-if="data.id && data.id != '-1'">
<!-- <el-icon size="16" title="添加" @click.stop="append('add', data)"><CirclePlus /></el-icon> -->
<el-icon size="16" title="编辑" @click.stop="append('edit', data)" style="margin-left: 8px"><Edit /></el-icon>
<el-icon size="16" title="添加分组" @click.stop="append('addChild', data)"><CirclePlus /></el-icon>
<el-icon size="16" title="编辑分组" @click.stop="append('edit', data)" style="margin-left: 8px"><Edit /></el-icon>
<el-icon size="16" title="设置推送人" @click.stop="pushPerson(FormOptEnum.GroupPushPerson, data)" style="margin-left: 8px" <el-icon size="16" title="设置推送人" @click.stop="pushPerson(FormOptEnum.GroupPushPerson, data)" style="margin-left: 8px"
><UserFilled ><UserFilled
/></el-icon> /></el-icon>
<el-icon size="16" title="删除" @click.stop="remove(data.id, '删除该分组')" style="margin-left: 8px"><Delete /></el-icon>
<el-icon size="16" title="删除分组" @click.stop="remove(data.id, '删除该分组')" style="margin-left: 8px"><Delete /></el-icon>
</span> </span>
</span> </span>
</template> </template>
@@ -235,7 +235,10 @@ const groupVisible = ref(false); //是否显示表单
const groupTitle = ref("新增分组"); const groupTitle = ref("新增分组");
const groupForm = reactive({ const groupForm = reactive({
name: "", name: "",
id: ""
id: "",
parentId: ""
});
const groupFormRules = ref({
}); });
const groupRules = ref({ const groupRules = ref({
name: [{ required: true, message: "请输入分组名称", trigger: "blur" }] name: [{ required: true, message: "请输入分组名称", trigger: "blur" }]
@@ -245,13 +248,19 @@ const closeGroup = () => {
groupVisible.value = false; groupVisible.value = false;
groupFormRef.value.resetFields(); groupFormRef.value.resetFields();
groupForm.name = ""; groupForm.name = "";
groupForm.id = "";
groupForm.parentId = "";
}; };
const groupFormType = ref<any>(null);
// 新增编辑分组 // 新增编辑分组
const append = (type: string, data: Tree) => { const append = (type: string, data: Tree) => {
groupVisible.value = true; groupVisible.value = true;
groupFormType.value = type
if (type == "edit") { if (type == "edit") {
groupForm.name = data.name; groupForm.name = data.name;
groupForm.id = data.id; groupForm.id = data.id;
} else if(type == "addChild") {
groupForm.parentId = data.id
} }
}; };
// 删除分组 // 删除分组
@@ -265,18 +274,30 @@ const onSubmit = () => {
if (valid) { if (valid) {
let params: any = reactive({ let params: any = reactive({
id: "", id: "",
name: groupForm.name
name: groupForm.name,
parentId: groupForm.parentId
}); });
if (!groupForm.id) {
monitorLIVEApi.addGroup(params).then(res => {
console.log(groupFormType)
if (groupFormType.value == 'add') {
delete params.parentId;
monitorLIVEApi.addGroup(params).then((res:any) => {
if (res.code == 200) { if (res.code == 200) {
getGroupList(); getGroupList();
closeGroup(); closeGroup();
} }
}); });
} else {
} else if(groupFormType.value == 'edit') {
params.id = groupForm.id; params.id = groupForm.id;
monitorLIVEApi.updateGroup(params).then(res => {
delete params.parentId;
monitorLIVEApi.updateGroup(params).then((res:any) => {
if (res.code == 200) {
getGroupList();
closeGroup();
}
});
} else if(groupFormType.value == 'addChild') {
delete params.id;
monitorLIVEApi.addGroup(params).then((res:any) => {
if (res.code == 200) { if (res.code == 200) {
getGroupList(); getGroupList();
closeGroup(); closeGroup();


+ 58
- 47
SafeCampus.WEB/src/views/sysconfig/ability/index.vue View File

@@ -4,63 +4,73 @@
* @Date: 2023-12-15 15:44:05 * @Date: 2023-12-15 15:44:05
!--> !-->
<template> <template>
<div class="abilityBox">
<TreeFilter ref="treeFilter" title="摄像头分组" label="name" id="id" width="300px" :request-api="monitorLIVEApi.groupList" @change="changeGroup">
</TreeFilter>
<div class="table-box">
<div class="abilityBox">
<TreeFilter
ref="treeFilter"
title="摄像头分组"
label="name"
id="id"
width="300px"
:request-api="monitorLIVEApi.groupList"
@change="changeGroup"
>
</TreeFilter>


<TreeFilter
ref="treeFilters"
title="摄像头列表"
label="sensorName"
id="sensorId"
:isData="true"
width="300px"
:data="videoList"
@change="changeVideo"
>
</TreeFilter>
<TreeFilter
ref="treeFilters"
title="摄像头列表"
label="sensorName"
id="sensorId"
:isData="true"
width="300px"
:data="videoList"
@change="changeVideo"
>
</TreeFilter>


<div class="card content-main">
<el-collapse accordion>
<el-collapse-item :name="ins" v-for="(item, ins) in warnGroupList" :key="item.cameraId[0]">
<template #title>
<div class="collapse-title" @click.stop="">
<div class="titlemodel">
<div style="width: 220px; text-align: left">{{ item.name }} {{ item.cameraId[0] }}</div>
<div style="margin-left: 20px">
<el-button @click="pushPerson(FormOptEnum.VideoPushPerson, item)" type="primary" size="small">设置推送人</el-button>
<div class="card content-main">
<el-collapse accordion>
<el-collapse-item :name="ins" v-for="(item, ins) in warnGroupList" :key="item.code">
<template #title>
<div class="collapse-title" @click.stop="">
<div class="titlemodel">
<div style="width: 220px; text-align: left">{{ item.name }}</div>
<div style="margin-left: 20px">
<el-button @click="pushPerson(FormOptEnum.VideoPushPerson, item)" type="primary" size="small">设置推送人</el-button>
</div>
</div>
<div class="btns">
<el-switch v-model="item.state" @change="stateChange" />
</div> </div>
</div> </div>
<div class="btns">
<el-switch v-model="item.state" @change="stateChange" />
</div>
</div>
</template>
<div class="collapse-content">
<!-- <div class="contentinfo" v-for="(v, index) in item.subset" :key="v.code">
</template>
<div class="collapse-content">
<!-- <div class="contentinfo" v-for="(v, index) in item.subset" :key="v.code">
<div class="modellabel">{{ v.name }}</div> <div class="modellabel">{{ v.name }}</div>


<div class="btns"> <div class="btns">
<el-switch v-model="v.state" active-text="开启" inactive-text="关闭" /> <el-switch v-model="v.state" active-text="开启" inactive-text="关闭" />
</div> </div>
</div> --> </div> -->
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="6" v-for="v in item.subset" :key="v.code">
<div class="contentinfo">
<div class="modellabel">{{ v.name }}</div>
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="24" :lg="12" :xl="6" v-for="v in item.subset" :key="v.code">
<div class="contentinfo">
<div class="modellabel">{{ v.name }}</div>


<div class="btns">
<el-switch :disabled="item.state == false" v-model="v.state" @change="stateChange" />
<div class="btns">
<el-switch :disabled="item.state == false" v-model="v.state" @change="stateChange" />
</div>
</div> </div>
</div>
</el-col>
</el-row>
</div>
</el-collapse-item>
</el-collapse>
</el-col>
</el-row>
</div>
</el-collapse-item>
</el-collapse>
</div>
<!-- 人员选择 -->
<userForm ref="userFormRef" />
</div> </div>
<!-- 人员选择 -->
<userForm ref="userFormRef" />
</div> </div>
</template> </template>


@@ -92,7 +102,7 @@ enum FormOptEnum {
} }
onMounted(() => { onMounted(() => {
// 在这里执行其他需要在组件挂载后运行的代码 // 在这里执行其他需要在组件挂载后运行的代码
getwarnGroup();
getwarnGroup('');
getVideoList('') getVideoList('')
}); });
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null); const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null);
@@ -111,6 +121,7 @@ function getVideoList(id:any) {
} }
function changeVideo(val: number | string) { function changeVideo(val: number | string) {
console.log(val) console.log(val)
getwarnGroup(val);
// personSetId.value = val // personSetId.value = val
// proTable.value!.pageable.pageNum = 1; // proTable.value!.pageable.pageNum = 1;
// proTable.value!.searchParam.personSetId = val; // proTable.value!.searchParam.personSetId = val;
@@ -121,9 +132,9 @@ function changeVideo(val: number | string) {


// 获取配置树 // 获取配置树
let warnGroupList = ref<any>([]); let warnGroupList = ref<any>([]);
function getwarnGroup() {
function getwarnGroup(id) {
setTimeout(async () => { setTimeout(async () => {
await abilityApi.warnGroup({}).then((res:any) => {
await abilityApi.warnGroup({cameraId: id}).then((res:any) => {
let { code, data } = res; let { code, data } = res;
if (code == 200) { if (code == 200) {
warnGroupList.value = data; warnGroupList.value = data;


+ 137
- 0
SafeCampus.WEB/src/views/userManage/dormitory/components/form/form_basic.vue View File

@@ -0,0 +1,137 @@
<!--
* @Description: 人员表单
* @Author: syy
* @Date: 2023-12-15 15:45:50
-->
<template>
<div class="userManageForm">
<div>
<el-row :gutter="16">
<el-col :span="12">
<s-form-item label="寝室名称" prop="name">
<s-input v-model="userInfo.name"></s-input>
</s-form-item>
</el-col>
</el-row>
</div>
</div>
</template>

<script setup lang="ts">
import { SysUserPersonnel, userManagePersonnelApi, userManageClassManageApi } from "@/api";
import { Plus } from "@element-plus/icons-vue";
import { useUserStore } from "@/stores/modules";
import type { UploadProps } from "element-plus";
import { ElMessage } from "element-plus";
import { TokenEnum } from "@/enums";
// props
interface FormProps {
modelValue: Partial<SysUserPersonnel.SysUserPerInfo>;
}
const emit = defineEmits(["update:modelValue"]); //定义emit
const props = defineProps<FormProps>(); //定义props
// 人员信息
const userInfo = computed({
get: () => props.modelValue,
set: val => emit("update:modelValue", val)
});
/* */
const userStore = useUserStore();
const { accessToken } = userStore;
const fileList = ref<any>([]);
const faces = ref<SysUserPersonnel.SysUserAvatar[]>([]);
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const treeData = ref<any>([]);
const handleRemove: UploadProps["onRemove"] = (uploadFile: any) => {
const index = faces.value.findIndex(item => item.uid === uploadFile.uid);
if (index > -1) {
faces.value.splice(index, 1);
}
userInfo.value.faces = faces.value;
if (uploadFile.personId) {
userManagePersonnelApi.deleteFace({ personId: uploadFile.personId, faceIds: [uploadFile.uid] }).then(res => {});
}
};

const handlePictureCardPreview: UploadProps["onPreview"] = uploadFile => {
dialogImageUrl.value = uploadFile.url!;
dialogVisible.value = true;
};
const handleAvatarSuccess: UploadProps["onSuccess"] = (response, uploadFile) => {
if (response.code === 200) {
faces.value.push({ faceUrl: response.data, uid: uploadFile.uid });
userInfo.value.faces = faces.value;
ElMessage.success(response.msg);
} else {
ElMessage.error(response.msg);
fileList.value = fileList.value.splice(0, fileList.value.length - 1);
}
};
const handleAvatarError: UploadProps["onError"] = (error, uploadFile, uploadFiles) => {
console.log(error, uploadFile, uploadFiles, "err");
};
// 通用状态选项
const genderOptions = ref([
{
label: "未知",
value: "GENDER_UNKNOWN"
},
{
label: "男",
value: "GENDER_MALE"
},
{
label: "女",
value: "GENDER_FEMALE"
}
]);
const getRequestData = async () => {
const { data } = await userManageClassManageApi.page();
treeData.value = data;
};
onMounted(() => {
// 初始化
userInfo.value.gender = userInfo.value.gender ? userInfo.value.gender : genderOptions.value[0].value;
getRequestData();
if (userInfo.value.personId) {
if (userInfo.value.faces?.length > 0) {
fileList.value = [
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => {
return {
url: item.faceUrl,
uid: item.faceId,
personId: userInfo.value.personId
};
})
];
faces.value = [
...JSON.parse(JSON.stringify(userInfo.value.faces)).map((item: any) => {
return {
faceUrl: item.faceUrl,
uid: item.faceId,
personId: userInfo.value.personId
};
})
];
}
}
});
</script>

<style lang="scss" scoped>
:deep(.el-input__wrapper) {
width: 100% !important;
}
:deep(.el-date-editor.el-input) {
width: 92% !important;
}
:deep(.el-upload-list--picture-card .el-upload-list__item) {
width: 100px !important;
height: 100px !important;
}
:deep(.el-upload--picture-card) {
width: 100px !important;
height: 100px !important;
}
</style>

+ 119
- 0
SafeCampus.WEB/src/views/userManage/dormitory/components/form/index.vue View File

@@ -0,0 +1,119 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visible" :title="`${sysUserProps.opt}人员`" form-size="800px" @close="onClose">
<el-form
ref="sysUserFormRef"
:rules="rules"
:disabled="sysUserProps.disabled"
:model="sysUserProps.record"
:hide-required-asterisk="sysUserProps.disabled"
label-width="auto"
label-suffix=" :"
>
<el-tabs v-model="activeName">
<Basic v-model="sysUserProps.record"></Basic>
</el-tabs>
</el-form>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button v-show="!sysUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
</template>
</form-container>
</div>
</template>

<script setup lang="ts" name="SysUserPersonnelForm">
import { SysUserPersonnel, userManagePersonnelApi } from "@/api";
import { FormOptEnum } from "@/enums";
import { required } from "@/utils/formRules";
import { FormInstance } from "element-plus";
import Basic from "./form_basic.vue";

const visible = ref(false); //是否显示表单
const activeName = ref("basic");
// 表单参数
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.SysUserPerInfo>>({
opt: FormOptEnum.ADD,
record: {},
disabled: false
});

// 表单验证规则
const rules = reactive({
// personId: [required("请输入人员ID")],
name: [required("请输入姓名")],
gender: [required("请选择性别")],
faces: [required("请上传人脸图片")],
phone: [required("请输入手机号")]
// extData: [required("请输入扩展数据")]
});

/**
* 打开表单
* @param props 表单参数
*/
function onOpen(props: FormProps.Base<SysUserPersonnel.SysUserPerInfo>) {
Object.assign(sysUserProps, props); //合并参数
if (props.opt == FormOptEnum.ADD) {
//如果是新增,设置默认值
// sysUserProps.record.sortCode = 99;
}
visible.value = true; //显示表单
if (props.record.personId) {
//如果传了id,就去请求api获取record
userManagePersonnelApi.detail({ id: props.record.personId }).then((res: any) => {
sysUserProps.record = res.data;
});
}
}

// 提交数据(新增/编辑)
const sysUserFormRef = ref<FormInstance>();
/** 提交表单 */
async function handleSubmit() {
sysUserFormRef.value?.validate(async valid => {
if (!valid) return; //表单验证失败
//提交表单
if (sysUserProps.record.faces.length === 0) {
return ElMessage.error("请上传人脸图片");
}
if (sysUserProps.record.personId) {
await userManagePersonnelApi
.update(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
} else {
await userManagePersonnelApi
.add(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
}
});
}

/** 关闭表单*/
function onClose() {
visible.value = false;
activeName.value = "basic";
}

// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>

<style lang="scss" scoped></style>

+ 107
- 0
SafeCampus.WEB/src/views/userManage/dormitory/components/formClass/index.vue View File

@@ -0,0 +1,107 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}宿舍楼`" form-size="400px" @close="onClose">
<el-form
ref="sysUserFormRef"
:rules="rules"
:disabled="sysUserProps.disabled"
:model="sysUserProps.record"
:hide-required-asterisk="sysUserProps.disabled"
label-width="auto"
label-suffix=" :"
>
<div>
<el-row :gutter="16">
<el-col :span="22">
<s-form-item label="宿舍楼名称" prop="personSetName">
<s-input v-model="sysUserProps.record.personSetName"></s-input>
</s-form-item>
</el-col>
</el-row>
</div>
</el-form>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button v-show="!sysUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
</template>
</form-container>
</div>
</template>

<script setup lang="ts" name="SysUserPerformClass">
import { ref } from "vue";
import { SysDormitory, userManageClassManageApi } from "@/api";
import { FormOptEnum } from "@/enums";
import { required } from "@/utils/formRules";
import { FormInstance } from "element-plus";

const visibleClass = ref(false); //是否显示表单
// 表单参数
const sysUserProps = reactive<FormProps.Base<SysDormitory.DormitoryInfo>>({
opt: FormOptEnum.ADD,
record: {},
disabled: false
});
// 表单验证规则
const rules = reactive({
personSetName: [required("请输入班级名称")]
});

/**
* 打开表单
* @param props 表单参数
*/
function onOpen(props: FormProps.Base<SysDormitory.DormitoryInfo>) {
Object.assign(sysUserProps, props); //合并参数
visibleClass.value = true; //显示表单
sysUserProps.record = props.record;
}

// 提交数据(新增/编辑)
const sysUserFormRef = ref<FormInstance>();
/** 提交表单 */
async function handleSubmit() {
sysUserFormRef.value?.validate(async valid => {
if (!valid) return; //表单验证失败
sysUserProps.record.name = sysUserProps.record.personSetName;
//提交表单
if (sysUserProps.record.personSetId) {
sysUserProps.record.id = sysUserProps.record.personSetId;
await userManageClassManageApi
.update(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
} else {
await userManageClassManageApi
.add(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
}
});
}

/** 关闭表单*/
function onClose() {
visibleClass.value = false;
}

// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>

<style lang="scss" scoped></style>

+ 116
- 0
SafeCampus.WEB/src/views/userManage/dormitory/components/formTeacher/index.vue View File

@@ -0,0 +1,116 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visibleClass" :title="`${sysUserProps.opt}`" form-size="400px" @close="onClose">
<el-form
ref="sysUserFormRef"
:rules="rules"
:disabled="sysUserProps.disabled"
:model="sysUserProps.record"
:hide-required-asterisk="sysUserProps.disabled"
label-width="auto"
label-suffix=" :"
>
<div>
<el-row :gutter="16">
<el-col :span="22">
<s-form-item label="班主任" prop="userId">
<s-select v-model="sysUserProps.record.userId" :options="teacherData" label="name" value="userId"></s-select>
</s-form-item>
</el-col>
</el-row>
</div>
</el-form>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button v-show="!sysUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
</template>
</form-container>
</div>
</template>

<script setup lang="ts" name="SysUserPerformClass">
import { ref } from "vue";
import { SysUserPersonnel, userManageTeacherApi } from "@/api";
import { required } from "@/utils/formRules";
import { FormInstance } from "element-plus";
const teacherData = ref<any>([]);
const visibleClass = ref(false); //是否显示表单
// 表单参数
enum FormOptEnum {
/** 新增 */
AddTeacher = "绑定班主任",
/** 编辑 */
UpdateTeacher = "修改班主任"
}
const sysUserProps = reactive<FormProps.Base<SysUserPersonnel.ClassPage>>({
opt: FormOptEnum.AddTeacher,
record: {},
disabled: false
});
// 表单验证规则
const rules = reactive({
userId: [required("请选择班主任名称")]
});

/**
* 打开表单
* @param props 表单参数
*/
function onOpen(props: FormProps.Base<SysUserPersonnel.ClassPage>) {
getRequestData();
Object.assign(sysUserProps, props); //合并参数
visibleClass.value = true; //显示表单
sysUserProps.record = props.record;
}

const getRequestData = async () => {
const { data } = await userManageTeacherApi.page();
teacherData.value = data;
};

// 提交数据(新增/编辑)
const sysUserFormRef = ref<FormInstance>();
/** 提交表单 */
async function handleSubmit() {
sysUserFormRef.value?.validate(async valid => {
if (!valid) return; //表单验证失败
console.log(sysUserProps);
//提交表单
if (sysUserProps.opt === FormOptEnum.UpdateTeacher) {
await userManageTeacherApi
.update(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
} else {
await userManageTeacherApi
.add(sysUserProps.record)
.then(() => {
sysUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
}
});
}

/** 关闭表单*/
function onClose() {
visibleClass.value = false;
}
// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>

<style lang="scss" scoped></style>

+ 285
- 0
SafeCampus.WEB/src/views/userManage/dormitory/index.vue View File

@@ -0,0 +1,285 @@
<!--
* @Description: 寝室管理
* @Author: syy
* @Date: 2024-7-15
-->
<template>
<div class="main-box">
<TreeFilter
ref="treeFilter"
title="宿舍楼管理"
label="name"
id="id"
width="300px"
:show-all="true"
:request-api="userManageDormitoryApi.list"
@change="changeTreeFilter"
>
<template v-slot:header>
<s-button suffix="宿舍楼" @click="addDormitory(FormOptEnum.ADD)" style="margin-bottom: 15px" />
</template>
<template v-slot:label="{ row }">
<span class="custom-tree-node">
<span>{{ row.node.label }}</span>
<span v-if="row.node.label != '全部'">
<a :title="FormOptEnum.EDIT" @click.stop="addDormitory(FormOptEnum.EDIT, row.node.data)">
<el-icon><Edit /></el-icon>
</a>
<a :title="FormOptEnum.DELETE" style="margin-left: 8px" @click.stop="addDelete(row.node.data.personSetId, '删除宿舍楼')">
<el-icon><Delete /></el-icon>
</a>
</span>
</span>
</template>
</TreeFilter>
<div class="table-box">
<ProTable ref="proTable" title="寝室管理" :columns="columns" rowKey="personId" :request-api="userManageDormitoryApi.page">
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<s-button v-auth="dormitoryButtonCode.add" suffix="寝室" @click="onOpen(FormOptEnum.ADD, { personSetId: personSetId })" />
<s-button
v-auth="dormitoryButtonCode.delete"
type="danger"
:opt="FormOptEnum.DELETE"
plain
suffix="寝室"
:disabled="!scope.isSelected"
@click="onDelete(scope.selectedListIds, '删除所选寝室')"
/>
</template>
<!-- 表格操作栏 -->
<template #operation="scope">
<el-space>
<s-button v-auth="dormitoryButtonCode.edit" link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)" />
<s-button v-auth="dormitoryButtonCode.delete" link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.personId], `删除寝室`)" />
<!-- <el-dropdown @command="handleCommand">
<el-link type="primary" :underline="false" :icon="ArrowDown"> 更多 </el-link>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item :command="command(scope.row, cmdEnum.AddFace)"
><el-upload
ref="upload"
class="upload-demo"
action="/api/business/personApi/uploadFile"
:show-file-list="false"
:on-success="handleAvatarSuccess"
accept=".jpg, .jpeg, .png"
:headers="{
Authorization: `${TokenEnum.TOKEN_PREFIX} ${accessToken}`
}"
>
<template #trigger>
{{ cmdEnum.AddFace }}
</template>
</el-upload>
</el-dropdown-item>
<el-dropdown-item :command="command(scope.row, cmdEnum.UnderpantsUnBinding)">
{{ cmdEnum.UnderpantsUnBinding }}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown> -->
</el-space>
</template>
</ProTable>
</div>
<!-- 寝室新增/编辑表单 -->
<Form ref="formRef"></Form>
<!-- 宿舍楼新增/编辑表单 -->
<FormClass ref="formRefC" />
<!-- 班主任绑定/修改 -->
<FormTeacher ref="formRefT" />
<!-- 预览头像 -->
<el-dialog v-model="visible" title="查看头像" width="830px" :before-close="handleClose">
<div style="display: flex; align-items: center; justify-content: center">
<img style="max-width: 100%; max-height: 600px" class="detailpic" :src="faceUrl" alt="" />
</div>
</el-dialog>
</div>
</template>
<script setup lang="tsx" name="SysDormitory">
import { userManageDormitoryApi,dormitoryButtonCode,SysDormitory } from "@/api";
import { useHandleData } from "@/hooks/useHandleData";
import { FormOptEnum } from "@/enums";
import Form from "./components/form/index.vue";
import FormClass from "./components/formClass/index.vue";
import FormTeacher from "./components/formTeacher/index.vue";
import { ArrowDown,More } from "@element-plus/icons-vue";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import TreeFilter from "@/components/TreeFilter/index.vue";
import { useUserStore } from "@/stores/modules";
import { TokenEnum } from "@/enums";
import type { UploadProps } from "element-plus";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const faceUrl = ref('');
const visible = ref(false); //是否显示寝室表单
const proTable = ref<ProTableInstance>();
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null);
const userStore = useUserStore();
const { accessToken } = userStore;
// 表格配置项
const columns: ColumnProps<SysDormitory.ChamberInfo>[] = [
{ type: "selection", fixed: "left", width: 50 },
{
prop: "name",
label: "寝室名称"
},
{
prop: "personId",
label: "寝室数量"
},
// { prop: "operation", label: "操作", width: 250, fixed: "right" }
];
const viewHeadImage = (scope: any) => {
faceUrl.value = scope.row.faces[0].faceUrl;
visible.value = true
console.log(faceUrl);
};
const handleClose = () => {
visible.value = false;
};
const tableData = ref([
{
name: "203",
personId: "20",
},
]);

// 寝室表单引用
const formRef = ref<InstanceType<typeof Form> | null>(null);
// 宿舍楼表单引用
const formRefC = ref<InstanceType<typeof FormClass> | null>(null);
// 宿舍楼表单引用
const formRefT = ref<InstanceType<typeof FormTeacher> | null>(null);

/**
* 打开表单
* @param opt 操作类型
* @param record 记录
*/
function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) {
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
}

/**
* 打开宿舍楼表单
* @param opt 操作类型
* @param record 记录
*/

function addDormitory(opt: FormOptEnum, record: {} | SysDormitory.DormitoryInfo = {}) {
formRefC.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record)), successful: RefreshTable });
}
/**
* 宿舍楼删除
* @param ids id数组
*/
async function addDelete(id: string[],msg: string) {
// 二次确认 => 请求api => 刷新表格
await useHandleData(userManageClassManageApi.delete, { id }, msg);
RefreshTable(); //刷新表格
}

/**
* 寝室删除
* @param ids id数组
*/
async function onDelete(ids: string[], msg: string) {
if(ids.length === 0){
ElMessage({
message: '请选择要删除的寝室',
type: 'warning'
});
return
}
// 二次确认 => 请求api => 刷新表格
await useHandleData(userManagePersonnelApi.delete, {id: ids.join(",") }, msg);
RefreshTable(); //刷新表格
}

// 刷新表格
const RefreshTable = () => {
proTable.value?.refresh();
treeFilter.value?.refresh(); //刷新树形筛选器
}


/** 更多下拉菜单命令枚举 */
enum cmdEnum {
AddFace = "添加人脸",
UnderpantsUnBinding = "底库解绑"
}
/** 下拉菜单参数接口 */
interface Command {
row: SysDormitory.ChamberInfo;
command: cmdEnum;
}

/**配置command的参数 */
function command(row: SysDormitory.ChamberInfo, command: cmdEnum): Command {
return {
row: row,
command: command
};
}
/**
* 列表更多下拉菜单点击事件
* @param command
*/
const personId = ref<number | string>(); //寝室id
function handleCommand(command: Command) {
switch (command.command) {
case cmdEnum.AddFace:
personId.value = command.row.personId; //获取寝室id
break
case cmdEnum.UnderpantsUnBinding:
userManagePersonnelApi.personUnBindDfie({
personId:command.row.personId,
personSetId: command.row.personSets[0].personSetId
}).then(res=>{
ElMessage.success('底库解绑成功');
RefreshTable()
})
break;
}
}


const handleAvatarSuccess: UploadProps["onSuccess"] = (response) => {
if (response.code === 200) {
userManagePersonnelApi.addFace({
personId: personId.value,
faceUrl: response.data
}).then(res=>{
RefreshTable()
})
} else {
ElMessage.error(response.msg);
}
};

/** 部门切换 */
const personSetId = ref<number | string>()
function changeTreeFilter(val: number | string) {
personSetId.value = val
proTable.value!.pageable.pageNum = 1;
proTable.value!.searchParam.personSetId = val;
proTable.value!.search();
}
</script>
<style scoped lang="scss">
.table-box {
width: 100%;
height: 100%;
}
.custom-tree-node {
display: flex;
flex: 1;
align-items: center;
justify-content: space-between;
padding-right: 8px;
font-size: 14px;
}
</style>

+ 33
- 10
SafeCampus.WEB/src/views/warn/zjrq/index.vue View File

@@ -43,19 +43,26 @@
<img class="detailpic" :src="detailData.snapshotUrl" alt="" /> <img class="detailpic" :src="detailData.snapshotUrl" alt="" />
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12"> <el-col :span="12">
<div class="linebox">告警内容:{{ detailData.alarmTypeDesc }}</div>
<div class="linebox">所属学校:演示学校</div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="linebox">告警时间:{{ detailData.tick }}</div>
<div class="linebox">班级:{{ detailData.personSetName ? detailData.personSetName : "暂无数据" }}</div>
</el-col>
<el-col :span="12">
<div class="linebox">姓名:{{ detailData.personName ? detailData.personName : "暂无数据" }}</div>
</el-col>
<el-col :span="12">
<div class="linebox">告警摄像头:{{ detailData.cameraName }}</div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="linebox">告警位置:{{ detailData.cameraName }}</div>
<div class="linebox">告警类型:{{ detailData.alarmTypeDesc }}</div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="linebox">所属门店:演示设备</div>
<div class="linebox">告警时间:{{ detailData.tick }}</div>
</el-col> </el-col>

<el-col :span="12"> <el-col :span="12">
<div class="linebox">备注信息:{{ detailData.extend }}</div>
<div class="linebox">备注信息:{{ detailData.extend ? detailData.extend : "暂无数据" }}</div>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="linebox"> <div class="linebox">
@@ -165,12 +172,20 @@ const columns: ColumnProps<ZJRQ.WarnInfo>[] = [
return "演示学校"; return "演示学校";
} }
}, },
{ {
prop: "cameraId",
label: "所属摄像头",
render: () => {
return "楼道";
}
prop: "personSetName",
label: "班级",
// render: () => {
// return "楼道";
// }
},
{
prop: "cameraName",
label: "告警摄像头",
// render: () => {
// return "楼道";
// }
}, },
{ {
prop: "snapshotUrl", prop: "snapshotUrl",
@@ -181,6 +196,14 @@ const columns: ColumnProps<ZJRQ.WarnInfo>[] = [
); );
} }
}, },
{
prop: "personName",
label: "姓名",
// render: () => {
// return "楼道";
// }
},
{ {
prop: "alarmType", prop: "alarmType",
label: "告警类型", label: "告警类型",


Loading…
Cancel
Save