王晓寒 hace 1 mes
padre
commit
08edb9f0ba
Se han modificado 40 ficheros con 1755 adiciones y 443 borrados
  1. +1
    -1
      SafeCampus.WEB/.env.development
  2. +1
    -0
      SafeCampus.WEB/package.json
  3. +2
    -0
      SafeCampus.WEB/src/api/interface/sys/usermanage/dormitory.ts
  4. +2
    -0
      SafeCampus.WEB/src/api/interface/sys/warn/zjrq.ts
  5. +18
    -19
      SafeCampus.WEB/src/api/modules/attendance/attendanceApi.ts
  6. +1
    -2
      SafeCampus.WEB/src/api/modules/attendance/index.ts
  7. +2
    -1
      SafeCampus.WEB/src/api/modules/index.ts
  8. +8
    -2
      SafeCampus.WEB/src/api/modules/sysconfig/ability.ts
  9. +4
    -4
      SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts
  10. +1
    -1
      SafeCampus.WEB/src/api/modules/usermanage/personnel.ts
  11. +16
    -0
      SafeCampus.WEB/src/api/modules/violation/index.ts
  12. +45
    -0
      SafeCampus.WEB/src/api/modules/violation/portraitSummary.ts
  13. +4
    -0
      SafeCampus.WEB/src/api/modules/warn/zjrq.ts
  14. +7
    -2
      SafeCampus.WEB/src/api/request/instance.ts
  15. +3
    -2
      SafeCampus.WEB/src/components/Form/SSelect/index.vue
  16. +1
    -0
      SafeCampus.WEB/src/components/Form/SSelect/interface.ts
  17. +10
    -1
      SafeCampus.WEB/src/components/ProTable/index.vue
  18. +37
    -8
      SafeCampus.WEB/src/components/Selectors/ClassUserselector/index.vue
  19. +1
    -1
      SafeCampus.WEB/src/components/TreeFilter/index.vue
  20. +2
    -1
      SafeCampus.WEB/src/main.ts
  21. +9
    -1
      SafeCampus.WEB/src/routers/modules/staticRouter.ts
  22. +14
    -0
      SafeCampus.WEB/src/utils/browser_patch.ts
  23. +9
    -1
      SafeCampus.WEB/src/views/attendance/passenger/components/detailTable/index.vue
  24. +1
    -1
      SafeCampus.WEB/src/views/attendance/passenger/components/form/form_basic.vue
  25. +1
    -1
      SafeCampus.WEB/src/views/attendance/passenger/index.vue
  26. +1
    -1
      SafeCampus.WEB/src/views/attendance/roolcall/index.vue
  27. +56
    -100
      SafeCampus.WEB/src/views/attendance/studentsReturn/components/returnConfirm/index.vue
  28. +117
    -47
      SafeCampus.WEB/src/views/attendance/studentsReturn/index.vue
  29. +8
    -8
      SafeCampus.WEB/src/views/home/index.vue
  30. +1
    -1
      SafeCampus.WEB/src/views/userManage/clothing/index.vue
  31. +35
    -3
      SafeCampus.WEB/src/views/userManage/dormitory/components/formDormitory/index.vue
  32. +0
    -144
      SafeCampus.WEB/src/views/userManage/dormitory/components/formUser/index.vue
  33. +128
    -44
      SafeCampus.WEB/src/views/userManage/dormitory/index.vue
  34. +143
    -0
      SafeCampus.WEB/src/views/violation/analysis/index.vue
  35. +254
    -0
      SafeCampus.WEB/src/views/violation/portrait/detail.vue
  36. +123
    -0
      SafeCampus.WEB/src/views/violation/portrait/index.vue
  37. +539
    -0
      SafeCampus.WEB/src/views/violation/portraitSummary/index.vue
  38. +21
    -35
      SafeCampus.WEB/src/views/warn/statistion/index.vue
  39. +101
    -0
      SafeCampus.WEB/src/views/warn/zjrq/components/handleForm.vue
  40. +28
    -11
      SafeCampus.WEB/src/views/warn/zjrq/index.vue

+ 1
- 1
SafeCampus.WEB/.env.development Ver fichero

@@ -23,5 +23,5 @@ VITE_HTTP_PROXY = true

# 开发环境跨域代理,支持配置多个
# VITE_PROXY = [["/api","http://192.168.10.186:5566","/Files"]]
VITE_PROXY = [["/api","http://192.168.10.186:8003"],["/Files","artc://rts-pull-live.deepeleph.com"]]
VITE_PROXY = [["/api","http://192.168.10.186:8003"],["/Files","http://192.168.10.186:8003/Files"]]


+ 1
- 0
SafeCampus.WEB/package.json Ver fichero

@@ -2,6 +2,7 @@
"name": "simple-admin",
"private": true,
"version": "1.0.0",
"node-version": "18.12.0 - 20.9.0",
"type": "module",
"description": "SimpleAdmin是ElementUI最好看的开源通用业务型后台管理系统",
"author": {


+ 2
- 0
SafeCampus.WEB/src/api/interface/sys/usermanage/dormitory.ts Ver fichero

@@ -26,6 +26,8 @@ export namespace SysDormitory {
name?: string | undefined;
gender?: boolean | undefined;
createTime?: string | undefined;
insCameraId?: string | number | undefined;
outCameraId?: string | number | undefined;
}
// 寝室列表传参
export interface Page extends ReqPage {


+ 2
- 0
SafeCampus.WEB/src/api/interface/sys/warn/zjrq.ts Ver fichero

@@ -41,5 +41,7 @@ export namespace ZJRQ {
rects: string;
/** 扩展字段 */
extend: string;
// 处理意见
remark: string;
}
}

SafeCampus.WEB/src/api/modules/attendance/studentsReturn.ts → SafeCampus.WEB/src/api/modules/attendance/attendanceApi.ts Ver fichero

@@ -1,5 +1,5 @@
/**
* @description 学生归寝
* @description 考勤事件管理
* @license Apache License Version 2.0
* @Copyright (c) 2022-Now 少林寺驻北固山办事处大神父王喇嘛
* @remarks
@@ -13,31 +13,30 @@
* @see https://gitee.com/dotnetmoyu/SimpleAdmin
*/
import { moduleRequest } from "@/api/request";
import { ReqId, SysUserPersonnel } from "@/api/interface";
const http = moduleRequest("/business/dfieldApi/");
const http = moduleRequest("/business/attendanceApi/");

/**
* @Description: 单页管理
* @Author: SYY
* @Author: yxq
* @Date: 2023-12-15 15:34:54
*/
const attendanceStudentsReturn = {
/** 查询底库列表 */
page(params: SysUserPersonnel.ClassPage) {
return http.get("test", params);
const attendanceApi = {
/** 查询考勤记录列表 */
page(params: any) {
return http.get("getPageList", params);
},
/** 删除底库 */
delete(params: ReqId) {
return http.delete("test", params);
/** 查询所有列表 */
list(params: any) {
return http.get("getNoPageList", params);
},
/** 创建底库 */
add(params: SysUserPersonnel.ClassPage) {
return http.post("test", params);
/** 添加考勤记录 */
add(params: any) {
return http.post("add", params);
},
/** 根据楼栋查询出入记录 */
pageByBuild(params: any) {
return http.get("getPageListByBuild", params);
},
/** 更新底库 */
update(params: SysUserPersonnel.ClassPage) {
return http.put("test", params);
}
};

export { attendanceStudentsReturn };
export { attendanceApi };

+ 1
- 2
SafeCampus.WEB/src/api/modules/attendance/index.ts Ver fichero

@@ -15,5 +15,4 @@
export * from "./behaviorTrace";
export * from "./passenger";
export * from "./roolcall";
export * from "./studentsReturn";

export * from "./attendanceApi";

+ 2
- 1
SafeCampus.WEB/src/api/modules/index.ts Ver fichero

@@ -20,4 +20,5 @@ export * from "./monitor";
export * from "./sysconfig";
export * from "./statistion";
export * from "./usermanage";
export * from "./attendance";
export * from "./attendance";
export * from "./violation";

+ 8
- 2
SafeCampus.WEB/src/api/modules/sysconfig/ability.ts Ver fichero

@@ -13,11 +13,11 @@
* @see https://gitee.com/dotnetmoyu/SimpleAdmin
*/
import { moduleRequest } from "@/api/request";
import { ReqId, ResPage, ZJRQ,setWarn } from "@/api/interface";
import { ReqId, ResPage, ZJRQ, setWarn } from "@/api/interface";
const http = moduleRequest("/business/warn/");
const http1 = moduleRequest("/violation/analysis/");

const abilityApi = {
/** 获取告警分组 */
warnGroup(params: ReqId) {
return http.get("getWarnGroup", params);
@@ -26,6 +26,12 @@ const abilityApi = {
setWarnGroup(params: setWarn) {
return http.post("setWarnGroupDevice", params);
},
/* 预警分析报告导出 */
reportExport(params: any) {
return http1.download("reportExport", params, {
showHeader: true
});
}
};

export { abilityApi };

+ 4
- 4
SafeCampus.WEB/src/api/modules/usermanage/dormitory.ts Ver fichero

@@ -53,7 +53,7 @@ const userManageDormitoryApi = {
},
/** 删除寝室 */
delete(params: ReqId) {
return httpChamber.delete("delete", params);
return httpChamber.post("delete", params);
},
/**寝室分配人员*/
setAssignPerson(params: SysDormitory.ChamberPersonnel) {
@@ -68,7 +68,7 @@ const userManageDormitoryApi = {
return httpChamber.get("getReturnInfo", params);
},
/** 获取详情(带寝室人员) */
detail(params: ReqId) {
detail(params: any) {
return httpChamber.get("getInfo", params);
},
/** 设置归寝时间 */
@@ -76,8 +76,8 @@ const userManageDormitoryApi = {
return httpChamber.post("setReturnTime", params);
},
/** 获取归寝时间 */
getReturnTime(params: ReqId) {
return httpChamber.get("getReturnTime", params);
getReturnTime() {
return httpChamber.get("getReturnTime");
}
};



+ 1
- 1
SafeCampus.WEB/src/api/modules/usermanage/personnel.ts Ver fichero

@@ -27,7 +27,7 @@ const userManagePersonnelApi = {
return http.post("pageQuery", params);
},
/** 获取单页详情 */
detail(params: ReqId) {
detail(params: any) {
return http.get("getPersionById", params);
},
/** 删除人员 */


+ 16
- 0
SafeCampus.WEB/src/api/modules/violation/index.ts Ver fichero

@@ -0,0 +1,16 @@
/**
* @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
*/

export * from "./portraitSummary";

+ 45
- 0
SafeCampus.WEB/src/api/modules/violation/portraitSummary.ts Ver fichero

@@ -0,0 +1,45 @@
/**
* @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";
const http = moduleRequest("/violation/portraitSummary/");
/**
* @Description: 学校画像
* @Author: SYY
* @Date: 2024-7-30 15:34:54
*/
const portraitSummaryApi = {
/** 获取学生性别 */
getStudentSex() {
return http.get("getStudentSex");
},
/** 获取学生年龄 */
getStudentAge() {
return http.get("getStudentAge");
},
/** 获取地理位置 */
getAddress() {
return http.get("getAddress");
},
/** 获取属性标签 */
getStudentAttr() {
return http.get("getStudentAttr");
},
/** 获取学生属性标签 */
getStudentDetail(params: any) {
return http.get("getStudentDetail", params);
}
};

export { portraitSummaryApi };

+ 4
- 0
SafeCampus.WEB/src/api/modules/warn/zjrq.ts Ver fichero

@@ -42,6 +42,10 @@ const warnZJRQApi = {
warnType(params: ReqId) {
return http.get("getAlarmType", params);
},
/** 处理告警 */
handWarn(params: ReqId) {
return http.post("handWarn", params);
}
};

export { warnZJRQApi };

+ 7
- 2
SafeCampus.WEB/src/api/request/instance.ts Ver fichero

@@ -22,6 +22,7 @@ import { checkStatus } from "../helper/checkStatus";
import { useUserStore } from "@/stores/modules";
import { AxiosCanceler } from "../helper/axiosCancel";
import router from "@/routers";
import { i } from "vite/dist/node/types.d-jgA8ss1A";

// 自定义 AxiosRequestConfig 接口,增加 noLoading 属性
export interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
@@ -111,7 +112,7 @@ export default class RequestHttp {
(response: AxiosResponse) => {
// 检查并存储授权信息
this.checkAndStoreAuthentication(response);
const { data, config } = response;
const { data, config }: any = response;
const userStore = useUserStore();
axiosCanceler.removePending(config);
tryHideFullScreenLoading();
@@ -140,7 +141,11 @@ export default class RequestHttp {
});
}
// 成功请求(在页面上除非特殊情况,否则不用处理失败逻辑)
return data;
if (config.showHeader) {
return response; //平时用在打印、导出、下载的时候使用
} else {
return data;
}
},
async (error: AxiosError) => {
const { response } = error;


+ 3
- 2
SafeCampus.WEB/src/components/Form/SSelect/index.vue Ver fichero

@@ -4,7 +4,7 @@
* @Date: 2023-12-15 15:38:32
!-->
<template>
<el-select :placeholder="placeholder" class="w-full" v-bind="$attrs" clearable>
<el-select :placeholder="placeholder" :filterable="filterable" class="w-full" v-bind="$attrs" clearable>
<el-option v-for="(item, index) in options" :key="index" :label="item[props.label]" :value="item[props.value]" />
</el-select>
</template>
@@ -20,7 +20,8 @@ const props = withDefaults(defineProps<SSelectProps>(), {
options: [] as any,
value: "value",
label: "label",
button: false
button: false,
filterable: false //是否可搜索
});

const placeholder = computed(() => {


+ 1
- 0
SafeCampus.WEB/src/components/Form/SSelect/interface.ts Ver fichero

@@ -21,4 +21,5 @@ export interface SSelectProps {
label?: string;
/** 选项值 */
value?: string;
filterable?: boolean;
}

+ 10
- 1
SafeCampus.WEB/src/components/ProTable/index.vue Ver fichero

@@ -20,7 +20,15 @@
</div>
</div>
<!-- 表格主体 -->
<el-table ref="tableRef" v-bind="$attrs" :data="processTableData" :border="border" :row-key="rowKey" @selection-change="selectionChange">
<el-table
ref="tableRef"
v-bind="$attrs"
:data="processTableData"
:border="border"
:max-height="maxHeight"
:row-key="rowKey"
@selection-change="selectionChange"
>
<!-- 默认插槽 -->
<slot />
<template v-for="item in tableColumns" :key="item">
@@ -113,6 +121,7 @@ export interface ProTableProps {
rowKey?: string; // 行数据的 Key,用来优化 Table 的渲染,当表格数据多选时,所指定的 id ==> 非必传(默认为 id)
searchCol?: number | Record<BreakPoint, number>; // 表格搜索项 每列占比配置 ==> 非必传 { xs: 1, sm: 2, md: 2, lg: 3, xl: 4 }
pagerCount?: number; // 分页组件显示最大页码按钮数 ==> 非必传(默认为7)
maxHeight?: number | string;
}

// 接受父组件参数,配置默认值


+ 37
- 8
SafeCampus.WEB/src/components/Selectors/ClassUserselector/index.vue Ver fichero

@@ -52,7 +52,7 @@
</el-tabs>
</el-col>
<el-col :span="10">
<ProTable ref="userTable" :columns="columns" :tool-button="false" :init-param="initParam" :request-api="userSelectorApi">
<ProTable ref="userTable" :columns="columns" maxHeight="480" :tool-button="false" :init-param="initParam" :request-api="userSelectorApi">
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<el-button type="primary" @click="addRecords(userTable!.tableData)">添加当前</el-button>
@@ -65,7 +65,15 @@
</ProTable>
</el-col>
<el-col :span="10">
<ProTable ref="chooseTable" :columns="columns" :tool-button="true" :data="chooseDataTmp" @search="searchRecords" @reset="resetRecords">
<ProTable
ref="chooseTable"
:columns="columns"
maxHeight="480"
:tool-button="true"
:data="chooseDataTmp"
@search="searchRecords"
@reset="resetRecords"
>
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<el-button type="danger" @click="delRecords(chooseTable!.tableData)">删除当前</el-button>
@@ -84,12 +92,18 @@
</el-row>
</div>
<template #footer>
<div class="mt-20px">
<div>
<el-button @click="onClose"> 取消 </el-button>
<el-button type="primary" @click="handleOk"> 确定 </el-button>
</div>
</template>
</form-container>
<!-- 预览头像 -->
<el-dialog v-model="imgVisible" 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>
</template>

<script setup lang="tsx" name="UserSelector">
@@ -104,7 +118,16 @@ const emit = defineEmits({ successful: null }); // 自定义事件
// console.log(tab, event);
// };
const visible = ref(false); //是否显示

const imgVisible = ref(false); //是否显示寝室表单
const faceUrl = ref('');
const viewHeadImage = (scope: any) => {
faceUrl.value = scope.row.faces[0].faceUrl;
imgVisible.value = true
console.log(faceUrl);
};
const handleClose = () => {
imgVisible.value = false;
};
// 定义组件props
const props = withDefaults(defineProps<UserSelectProps>(), {
multiple: false,
@@ -112,7 +135,7 @@ const props = withDefaults(defineProps<UserSelectProps>(), {
});

// 根据是否业务显示不同名称
const userName = props.biz ? "人员" : "用户";
const userName = props.biz ? "用户" : "人员";
const positionName = props.biz ? "职位" : "岗位";
const orgName = props.biz ? "机构" : "班级";

@@ -126,13 +149,12 @@ const chooseTable = ref<ProTableInstance>();
const columns: ColumnProps<SysUser.SysUserInfo>[] = [
{ type: "selection", fixed: "left", width: 50 },
{ prop: "operation", label: "操作", width: 80, fixed: "left" },
{ prop: "personSetName", label: "班级" },
{
prop: "faceUrl",
label: "人脸",
render: scope => {
return (
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px;' alt=''/>
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:30px;height:30px;' alt=''/>
);
}
},
@@ -143,7 +165,10 @@ const columns: ColumnProps<SysUser.SysUserInfo>[] = [
return row.row.name;
},
search: { el: "input", span: 2 }
}
},
{ prop: "personSetName", label: "班级" },
{ prop: "dormitoryName", label: "寝室" },
];

/** 显示选择器 */
@@ -162,6 +187,10 @@ function onClose() {

/** 提交数据 */
function handleOk() {
if (chooseData.value.length == 0) {
ElMessage.warning("请选择" + userName);
return;
}
visible.value = false;
console.log(chooseData.value,'提交得数据')
emit("successful", chooseData.value);


+ 1
- 1
SafeCampus.WEB/src/components/TreeFilter/index.vue Ver fichero

@@ -86,8 +86,8 @@ const setSelected = () => {
};

onBeforeMount(async () => {
setSelected();
await getRequestData();
setSelected();
});

// 使用 nextTick 防止打包后赋值不生效,开发环境是正常的


+ 2
- 1
SafeCampus.WEB/src/main.ts Ver fichero

@@ -40,7 +40,8 @@ import hljsCommon from "highlight.js/lib/common";
import hljsVuePlugin from "@highlightjs/vue-plugin";

//解决谷歌浏览器 Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider markin...
import "default-passive-events";
// import "default-passive-events";
import "@/utils/browser_patch";

// import "vue3-video-play/dist/style.css"; // 引入css
const app = createApp(App);


+ 9
- 1
SafeCampus.WEB/src/routers/modules/staticRouter.ts Ver fichero

@@ -43,8 +43,16 @@ export const staticRouter: RouteRecordRaw[] = [
title: "学生点名详情"
},
name: "学生点名详情",
path: "/roolcall/detail",
path: "/attendance/roolcall/detail",
component: () => import("@/views/attendance/roolcall/detail.vue")
},
{
meta: {
title: "学生画像详情"
},
name: "学生画像详情",
path: "/violation/portrait/detail",
component: () => import("@/views/violation/portrait/detail.vue")
}
]
}


+ 14
- 0
SafeCampus.WEB/src/utils/browser_patch.ts Ver fichero

@@ -0,0 +1,14 @@
//去除谷歌浏览器的scroll、wheel等事件警告
(function () {
if (typeof EventTarget !== "undefined") {
let func = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (type, fn, capture) {
this.func = func;
if (typeof capture !== "boolean") {
capture = capture || {};
capture.passive = false;
}
this.func(type, fn, capture);
};
}
})();

+ 9
- 1
SafeCampus.WEB/src/views/attendance/passenger/components/detailTable/index.vue Ver fichero

@@ -6,7 +6,15 @@
<template>
<div>
<form-container v-model="visible" :title="`分片详情`" form-size="800px" @close="onClose">
<ProTable ref="proTable" title="分片详情" height="500px" :data="tableData" :columns="columns"></ProTable>
<ProTable
:toolButton="false"
:pagination="false"
ref="proTable"
title="分片详情"
height="500px"
:data="tableData"
:columns="columns"
></ProTable>
<template #footer>
<el-button @click="onClose"> 关闭 </el-button>
</template>


+ 1
- 1
SafeCampus.WEB/src/views/attendance/passenger/components/form/form_basic.vue Ver fichero

@@ -67,7 +67,7 @@ const splitOptions = ref([
]);
// 摄像头
let cameraldsOptions = ref([]);
monitorLIVEApi.list({ pageSize: 1000, pageNum: 1 }).then(res => {
monitorLIVEApi.list({ pageSize: 1000, pageNum: 1 }).then((res: any) => {
if (res.code == 200) {
cameraldsOptions.value = res.data.list.map(e => {
return {


+ 1
- 1
SafeCampus.WEB/src/views/attendance/passenger/index.vue Ver fichero

@@ -88,7 +88,7 @@ function onOpen(opt: FormOptEnum, record: {} | AttendancePassenger.PassengerInfo
const RefreshTable = () => {
proTable.value?.refresh();
};
const haseExtJson = row => {
const haseExtJson = (row: any) => {
let extJson = JSON.parse(row.extJson);
return extJson.length == 0;
};


+ 1
- 1
SafeCampus.WEB/src/views/attendance/roolcall/index.vue Ver fichero

@@ -91,7 +91,7 @@ const columns: ColumnProps[] = [
];
const onView = (row: any) => {
router.push( {
path:'/roolcall/detail',
path:'/attendance/roolcall/detail',
query: {
taskId: row.taskId,
personSetId:row.personSetId


+ 56
- 100
SafeCampus.WEB/src/views/attendance/studentsReturn/components/returnConfirm/index.vue Ver fichero

@@ -1,21 +1,30 @@
<!--
* @Description: 人脸识别失败表格
* @Description: 未归寝
* @Author: yxq
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visible" row-key="id" :title="`${propsInfo.record.qinshibianhao}归寝确认`" form-size="800px" @close="onClose">
<ProTable ref="noFaceTableRef" title="归寝确认" height="500px" :data="tableData" :columns="columns">
<form-container v-model="visible" row-key="id" :title="`寝室${propsInfo.record.name}归寝确认`" form-size="800px" @close="onClose">
<ProTable
ref="noReturnTableRef"
:request-auto="false"
title="归寝确认"
height="500px"
:pagination="false"
:columns="columns"
:request-api="userManageDormitoryApi.returnDetail"
:data-callback="dataCallback"
>
<!-- 表格 header 按钮 -->
<template #tableHeader="scope">
<s-button
type="primary"
:disabled="!scope.isSelected"
icon="check"
prefix="人工"
suffix="确认"
@click="personConfirm(scope.selectedListIds, '确认已归寝')"
prefix="确认"
suffix="归寝"
@click="personConfirm(scope.selectedList, '确认已归寝')"
/>
</template>
</ProTable>
@@ -26,118 +35,39 @@
<!-- 预览头像 -->
<el-dialog v-model="imgVisible" title="查看头像" width="830px">
<div style="display: flex; align-items: center; justify-content: center">
<img class="detailpic" :src="faceUrl" alt="" />
<img class="detailpic" :src="'/api/' + faceUrl" alt="" />
</div>
</el-dialog>
</div>
</template>
<script setup lang="tsx" name="attendanceStudentsReturn">
import { AttendanceStudentsReturn, attendanceStudentsReturn } from "@/api";
import { ColumnProps, noFaceTableInstance } from "@/components/noFaceTableRef/interface";
import { userManageDormitoryApi,attendanceApi } from "@/api";
import { ColumnProps,ProTableInstance } from "@/components/ProTable/interface";
import { FormOptEnum } from "@/enums";
import { useHandleData } from "@/hooks";
import { formatDate } from "@/utils";

const visible = ref(false); //是否显示
// 弹框参数
const propsInfo = reactive<FormProps.Base<AttendanceStudentsReturn.PassengerInfo>>({
const propsInfo = reactive<FormProps.Base<{}>>({
opt: FormOptEnum.VIEW, //操作类型
record: {}, //弹框数据
disabled: false
});
/**
* 打开弹框
* @param props 弹框参数
*/
function onOpen(props: FormProps.Base<AttendanceStudentsReturn.PassengerInfo>) {
Object.assign(propsInfo, props); //合并参数
visible.value = true; //显示弹框
if (props.record.id) {
//如果传了id,就去请求api获取record
attendanceStudentsReturn.detail({ id: props.record.id }).then(res => {
propsInfo.record = res.data;
});
}
}

const tableData = ref([
{
id:'1',
studentname: "张三",
faces: [
{
faceUrl:
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D"
},
],
louceng:'3',
qinshi:'301',
},
{
id:'2',
studentname: "李四",
faces: [
{
faceUrl:
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D"
},
],
louceng:'3',
qinshi:'302',
},
{
id:'3',
studentname: "张三",
faces: [
{
faceUrl:
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D"
},
],
louceng:'4',
qinshi:'401',
},
{
id:'4',
studentname: "李四",
faces: [
{
faceUrl:
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D"
},
],
louceng:'3',
qinshi:'301',
},
{
id:'5',
studentname: "张三",
faces: [
{
faceUrl:
"http://deepvision.oss-cn-zhangjiakou.aliyuncs.com/dfield-cruising/online/person-set/quanjiang/DEMO00001/8746a847ecd64c1696b37f4cdf617a18/5dc35e4c7af84b3fb5aab70156574873.jpg?Expires=1721375257&OSSAccessKeyId=STS.NTfeBHwzU7kivsSS2EypREace&Signature=c1aTbDc1hNISq%2BV05o0slEfoCTI%3D&security-token=CAIS0wN1q6Ft5B2yfSjIr5fTLvj8mqV0gKmCdFXitzIQdf9%2BqqTIhzz2IHFMf3huCeodsv8%2BlGxS5%2FgelrpqVpZDR03Na8RHwrly1lv5O9KY4x49TRng0s%2FLI3OaLjKm9hi7AYygPgK0GJqEb1TDiVUto9%2FTfimjWFqIKICAjYUdAP0cQgi%2Fa0gwZrJRPRAwh8IGEnHTOP2xUHvtmXGCNFd0nQB%2BhGhjk7TdpPeR8R3Dllb35%2FYIroDqWPieYtJrIY10XqWBvqx%2FfbGT1zVLuVoYtvV6gaFc5zbcv9abRFVf4hiCP6%2Ff6MBuNw5%2Fae94efZNp%2BOukuZj6K6B1db7xhtVI%2BBOUiPZA4mr2IzdBeqvNNcwc7m8F1no9YjXbsGs9EEGGStLaVgVI4F8dyAhWEd9FWjgR%2FX5qAyQUGCKULOY1aw6651xwmjz8MCCT1r1GOTBindGasVnMxh5Z0JMjDK9aNkKfgFUbVJ8BrGTCIh%2FYx0bsq7yowDIEyp71TRMo%2Bbu%2FDBhIifKpO4VN7AxMup1DPwu2wNCxORK3yyybb5sa3aTR6942p%2F%2FF5VxFNPqOx1rmCMf4znuW4yrvNkAVvNcuIqdR8aLhaLIEbHzoKxuEKRnrfsIeBqAAUB%2FCKIuI1UaCj4LYX8DyIYOI8tUKFsMguPHpPENaK9Lcz5ZhB%2BrX6BcQfNWOLhDx7KyRE28vtEs2uolAhLTRaZsZFjbAZE5Ngt09%2FbSXdD%2FR%2BOlGMpQdp752x5lOlvPsJp1skuFLbramyqY4oj4tVwv1OLWpcsEc3AEosPalpAuIAA%3D"
},
],
louceng:'5',
qinshi:'502',
}
]);
// 获取 noFaceTableRef 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const noFaceTableRef = ref<noFaceTableInstance>();
// 获取 noReturnTableRef 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const noReturnTableRef = ref<ProTableInstance>();
// 表格配置项
const columns: ColumnProps[] = [
{ type: "selection" },
{
prop: "louceng",
label: "楼层"
},
{
prop: "qinshi",
label: "寝室编号"
prop: "name",
label: "学生姓名"
},
{
prop: "studentname",
label: "学生姓名"
prop: "personSetName",
label: "班级"
},
{
prop: "faces",
@@ -145,7 +75,7 @@ const columns: ColumnProps[] = [
render: scope => {
return (
<img
src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ""}
src={scope.row.faces.length > 0 ? '/api/'+scope.row.faces[0].faceUrl : ""}
onClick={() => viewHeadImage(scope)}
style="width:50px;height:50px;cursor:pointer"
alt=""
@@ -154,6 +84,25 @@ const columns: ColumnProps[] = [
}
}
];
/**
* 打开弹框
* @param props 弹框参数
*/
function onOpen(props: FormProps.Base<{}>) {
Object.assign(propsInfo, props); //合并参数
visible.value = true; //显示弹框
nextTick(()=>{
noReturnTableRef.value!.searchParam.id = props.record.id;
noReturnTableRef.value!.searchParam.returnTime = props.record.ReturnTime;
noReturnTableRef.value.search()
})
}
const dataCallback = (res:any)=>{
if(!res.attendanceDtos)return res.personInfos
return res.personInfos.filter(e=>{
return !res.attendanceDtos.find(e1=>e1.personId == e.personId)
})
}
// 图片预览
const imgVisible = ref(false);
const faceUrl = ref('');
@@ -162,8 +111,15 @@ const viewHeadImage = (scope: any) => {
imgVisible.value = true
};
/** 人工确认 */
async function personConfirm(ids: string[], msg: string) {
await useHandleData(attendanceStudentsReturn.delete, {id: ids.toString() }, msg);
async function personConfirm(list:any, msg: string) {
list = list.map(e=>{
return {
personSetId:e.personSetId,
personId:e.personId,
tick:formatDate(new Date().valueOf())
}
})
await useHandleData(attendanceApi.add, list, msg);
RefreshTable(); //刷新表格
}
/** 关闭表单*/
@@ -172,7 +128,7 @@ function onClose() {
}
// 刷新表格
const RefreshTable = () => {
noFaceTableRef.value?.refresh();
noReturnTableRef.value?.refresh();
};
// 暴露给父组件的方法
defineExpose({


+ 117
- 47
SafeCampus.WEB/src/views/attendance/studentsReturn/index.vue Ver fichero

@@ -1,72 +1,138 @@
<!--
* @Description: 教师点名
* @Description: 学生归寝
* @Author: yxq
* @Date: 2024-7-16
* @Date: 2024-7-24
-->
<template>
<div class="table-box">
<ProTable ref="proTable" title="教师点名" :columns="columns" :data="data">
<!-- 表格操作栏 -->
<template #operation="scope">
<el-space>
<s-button
:disabled="!scope.row.noFaceNum"
link
prefix="人工"
:opt="FormOptEnum.EDIT"
suffix="确认"
@click="onOpen(FormOptEnum.VIEW, scope.row)"
/>
</el-space>
<div class="main-box">
<TreeFilter
ref="treeFilter"
label="name"
id="id"
width="300px"
:show-all="false"
:isData="true"
:data="treeData"
:default-value="defaultValue"
@change="changeTreeFilter"
>
<template v-slot:header>
<h4 style="margin: 0 0 15px; font-size: 18px; font-weight: bold; color: var(--el-color-info-dark-2); letter-spacing: 0.5px">所属楼栋</h4>
</template>
</ProTable>
<ReturnConfirm ref="ReturnConfirmRef" />
<template v-slot:label="{ row }">
<span class="custom-tree-node">
<span>{{ row.node.label }}</span>
</span>
</template>
</TreeFilter>
<div class="table-box">
<ProTable ref="proTable" title="教师点名" :request-auto="false" :columns="columns" :request-api="userManageDormitoryApi.returnList">
<!-- 表格 header 按钮 -->
<template #tableHeader>
<div style="display: flex; align-items: center">
<el-date-picker
v-model="ReturnTime"
:clearable="false"
value-format="YYYY-MM-DD"
type="date"
placeholder="选择查询日期"
@change="retrunTimeChange"
>
</el-date-picker>
<div style="margin-left: 15px; color: #606266">归寝时间:{{ returnTime }}</div>
</div>
</template>
<!-- 表格操作栏 -->
<template #operation="scope">
<el-space>
<!-- :disabled="!scope.row.noReturnNum" -->
<s-button link prefix="归寝" :opt="FormOptEnum.EDIT" suffix="确认" @click="onOpen(FormOptEnum.VIEW, scope.row)" />
</el-space>
</template>
</ProTable>
<ReturnConfirm ref="ReturnConfirmRef" />
</div>
</div>
</template>
<script setup lang="ts">
import { attendanceStudentsReturn, AttendanceStudentsReturn } from "@/api";
import { userManageDormitoryApi } from "@/api";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import { FormOptEnum } from "@/enums";
import ReturnConfirm from "./components/returnConfirm/index.vue";
const data = ref([
{
louceng: "3",
qinshibianhao: "306",
qinshirenshu: "6",
guiqinNum: "5",
noFaceNum: "1"
},
{
louceng: "3",
qinshibianhao: "307",
qinshirenshu: "8",
guiqinNum: "6",
noFaceNum: "2"
}
]);
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTable = ref<ProTableInstance>();
/**左侧楼栋**/
import TreeFilter from "@/components/TreeFilter/index.vue";
import { formatDate } from "@/utils";
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null);
//楼栋切换
const buildId = ref<number | string>();
function changeTreeFilter(val: number | string) {
console.log(treeFilter.value?.treeData);
buildId.value = val;
proTable.value!.pageable.pageNum = 1;
proTable.value!.searchParam.buildId = val;
proTable.value!.search();
}
// 初始化数据
const treeData = ref([]);
const defaultValue = ref("");
const ReturnTime = ref("");
let ReturnTimeDefault = "";
const returnTime = ref();
onMounted(() => {
// 设置默认查询日期
let date = formatDate(new Date().valueOf());
ReturnTime.value = date.substring(0, 10);
proTable.value!.searchParam.ReturnTime = ReturnTime.value;
ReturnTimeDefault = ReturnTime.value;
// 请求楼栋
userManageDormitoryApi.list().then(res => {
if (res.code == 200) {
if (res.data.length) {
treeData.value = res.data;
defaultValue.value = res.data[0].id.toString();
buildId.value = defaultValue.value;
// 请求表格
proTable.value!.pageable.pageNum = 1;
proTable.value!.searchParam.buildId = defaultValue.value;
proTable.value!.search();
}
}
});
// 归寝时间
userManageDormitoryApi.getReturnTime().then(res => {
if (res.code == 200) {
returnTime.value = res.data.timeBegin + " ~ " + res.data.timeEnd;
}
});
});
// 查询日期修改
const retrunTimeChange = () => {
proTable.value!.pageable.pageNum = 1;
proTable.value!.searchParam.ReturnTime = ReturnTime.value || ReturnTimeDefault;
proTable.value!.search();
};
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
// 表格配置项
const columns: ColumnProps[] = [
{
prop: "louceng",
label: "楼层"
},
{
prop: "qinshibianhao",
prop: "name",
label: "寝室编号"
},
{
prop: "qinshirenshu",
prop: "personCount",
label: "寝室人数"
},
{
prop: "guiqinNum",
prop: "dormitoryCount",
label: "归寝人数"
},
{
prop: "noFaceNum",
label: "未归寝人数"
prop: "noDormitoryCount",
label: "未归寝人数",
render: scope => {
return scope.row.personCount - scope.row.dormitoryCount;
}
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];
@@ -76,10 +142,14 @@ const ReturnConfirmRef = ref<InstanceType<typeof ReturnConfirm> | null>(null);
* @param opt 操作类型
* @param record 弹框数据
*/
function onOpen(opt: FormOptEnum, record: {} | AttendanceStudentsReturn.studentsReturnInfo = {}) {
function onOpen(opt: FormOptEnum, record = {}) {
switch (opt) {
case FormOptEnum.VIEW:
ReturnConfirmRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
ReturnConfirmRef.value?.onOpen({
opt: opt,
record: { ...record, ReturnTime: ReturnTime.value || ReturnTimeDefault },
successful: RefreshTable
});
break;
}
}


+ 8
- 8
SafeCampus.WEB/src/views/home/index.vue Ver fichero

@@ -158,7 +158,7 @@ function getDataChart() {
});
});
}
function getCharts1(data) {
function getCharts1(data: any) {
const chart = echarts.init(chart1.value);
const option = {
tooltip: {
@@ -208,7 +208,7 @@ function getCharts1(data) {
chart.resize();
});
}
function getCharts2(data) {
function getCharts2(data: any) {
const chartstation = echarts.init(chart2.value);
const option = {
tooltip: {
@@ -261,22 +261,22 @@ function getCharts2(data) {

function getWeekData() {
setTimeout(async () => {
await statistionApi.weekstatistion({}).then(res => {
await statistionApi.weekstatistion({}).then((res: any) => {
let { code, data } = res;

if (code == 200) {
// let chartData = data;
let time = data.dataX;
let chartData = data.dataY.map(item => {
let chartData = data.dataY.map((item: any) => {
return {
data: item.data,
name: item.name,
type: "bar",
barWidth: "12px", // 设置柱子粗细
itemStyle: {
normal: {
barBorderRadius: [30, 30, 0, 0]
}
// normal: {
borderRadius: [30, 30, 0, 0]
// }
}
};
});
@@ -285,7 +285,7 @@ function getWeekData() {
});
});
}
function getCharts3(time, data) {
function getCharts3(time: any, data: any) {
const chartstation3 = echarts.init(chart3.value);
const option = {
tooltip: {


+ 1
- 1
SafeCampus.WEB/src/views/userManage/clothing/index.vue Ver fichero

@@ -10,7 +10,7 @@
label="clothSetName"
id="clothSetId"
width="300px"
:show-all="true"
:show-all="false"
:request-api="userManageClothApi.getList"
@change="changeTreeFilter"
>


+ 35
- 3
SafeCampus.WEB/src/views/userManage/dormitory/components/formDormitory/index.vue Ver fichero

@@ -27,6 +27,28 @@
<s-radio-group v-model="sysDormitoryProps.record.gender" :options="genderOptions" />
</s-form-item>
</el-col>
<el-col :span="22">
<s-form-item label="进楼摄像头" prop="insCameraId">
<s-select
v-model="sysDormitoryProps.record.insCameraId"
:filterable="true"
:options="creamaData"
label="sensorName"
value="sensorId"
></s-select>
</s-form-item>
</el-col>
<el-col :span="22">
<s-form-item label="出楼摄像头" prop="outCameraId">
<s-select
v-model="sysDormitoryProps.record.outCameraId"
:filterable="true"
:options="creamaData"
label="sensorName"
value="sensorId"
></s-select>
</s-form-item>
</el-col>
</el-row>
</div>
</el-form>
@@ -40,12 +62,13 @@

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

const visibleDormitory = ref(false); //是否显示表单
const creamaData = ref<any>([]);
const genderOptions = [
{
label: "男",
@@ -65,7 +88,9 @@ const sysDormitoryProps = reactive<FormProps.Base<SysDormitory.DormitoryInfo>>({
// 表单验证规则
const rules = reactive({
name: [required("请输入宿舍楼名称")],
gender: [required("请选择性别")]
gender: [required("请选择性别")],
insCameraId: [required("请选择进楼摄像头")],
outCameraId: [required("请选择出楼摄像头")]
});

/**
@@ -113,7 +138,14 @@ async function handleSubmit() {
function onClose() {
visibleDormitory.value = false;
}

onMounted(() => {
getCreamaList();
});
const getCreamaList = () => {
monitorLIVEApi.list({ pageNum: 1, pageSize: 1000 }).then(res => {
creamaData.value = res.data.list;
});
};
// 暴露给父组件的方法
defineExpose({
onOpen


+ 0
- 144
SafeCampus.WEB/src/views/userManage/dormitory/components/formUser/index.vue Ver fichero

@@ -1,144 +0,0 @@
<!--
* @Description: 表单
* @Author: huguodong
* @Date: 2023-12-15 15:45:28
!-->
<template>
<div>
<form-container v-model="visible" title="人员选择" form-size="600px">
<el-form
ref="userFormRef"
:rules="rules"
:disabled="liveUserProps.disabled"
:model="liveUserProps.record"
:hide-required-asterisk="liveUserProps.disabled"
label-width="auto"
label-suffix=" :"
>
<s-form-item label="分配人员" prop="userId">
<el-button link type="primary" @click="showSelector">选择</el-button>
<el-tag v-if="liveUserProps.record.userId" class="ml-3px" type="warning" closable @close="removeDirector">{{
liveUserProps.record.userInfo?.name
}}</el-tag>
</s-form-item>
</el-form>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button v-show="!liveUserProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
</template>
</form-container>
<user-selector
multiple
ref="userSelectorRef"
:org-tree-api="sysOrgApi.tree"
:user-selector-api="sysUserApi.selector"
@successful="handleChooseUser"
/>
</div>
</template>

<script setup lang="ts">
import { SysOrg, SysUser, sysOrgApi, sysPositionApi, sysRoleApi, sysUserApi, monitorLIVEApi } from "@/api";
import { FormOptEnum, SysDictEnum } from "@/enums";
import { required } from "@/utils/formRules";
import { FormInstance } from "element-plus";
import { useDictStore } from "@/stores/modules";
import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface";

const visible = ref(false); //是否显示表单
const dictStore = useDictStore(); //字典仓库

// 表单参数
const liveUserProps = reactive<FormProps.Base<any>>({
opt: FormOptEnum.ADD,
record: {},
disabled: false
});

// 表单验证规则
const rules = reactive({
userId: [required("请选择人员")]
});

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

// 提交数据(新增/编辑)
const userFormRef = ref<FormInstance>();
/** 提交表单 */
async function handleSubmit() {
userFormRef.value?.validate(async valid => {
if (!valid) return; //表单验证失败
let params: any = {
warnCode: "",
userId: ""
};
if (liveUserProps.opt == "预警推送人") {
params.warnCode = liveUserProps.record.warnCode;
params.userId = liveUserProps.record.userId;
//提交表单
await monitorLIVEApi
.setWarningPushPerson(params)
.then(() => {
liveUserProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
}
});
}

/** 关闭表单*/
function onClose() {
visible.value = false;
liveUserProps.record.userId = null;
liveUserProps.record.userInfo = null;
}

const userSelectorRef = ref<UserSelectorInstance>(); //用户选择器引用
/** 显示用户选择器 */
function showSelector() {
//将liveUserProps.record.userInfo转为 SysUser.SysUserInfo[]类型
const userInfo = liveUserProps.record.userInfo ? [liveUserProps.record.userInfo] : [];
userSelectorRef.value?.showSelector(userInfo);
}

/** 选择用户 */
function handleChooseUser(data: SysUser.SysUserInfo[]) {
// 选择用户后,将用户id赋值给liveUserProps.record.userId
if (data.length > 0) {
liveUserProps.record.userId = data[0].id;
liveUserProps.record.userInfo = data[0];
}
}

/** 移除主管 */
function removeDirector() {
liveUserProps.record.userId = null;
liveUserProps.record.userInfo = null;
}
// 暴露给父组件的方法
defineExpose({
onOpen
});
</script>

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

+ 128
- 44
SafeCampus.WEB/src/views/userManage/dormitory/index.vue Ver fichero

@@ -1,7 +1,7 @@
<!--
* @Description: 寝室管理
* @Author: syy
* @Date: 2024-7-15
* @Author: wwp
* @Date: 2024-7-25
-->
<template>
<div class="main-box">
@@ -17,6 +17,7 @@
>
<template v-slot:header>
<s-button suffix="宿舍楼" @click="addDormitory(FormOptEnum.ADD)" style="margin-bottom: 15px" />
<el-button @click="settingTime" style="margin-bottom: 15px">归寝时间设置</el-button>
</template>
<template v-slot:label="{ row }">
<span class="custom-tree-node">
@@ -65,38 +66,68 @@
</el-space>
</template>
</ProTable>
<ClassUserselector
ref="userSelectorRef"
:org-tree-api="userManageClassManageApi.page"
:user-selector-api="userManagePersonnelApi.page"
multiple
@successful="handleChooseUser"
>
</ClassUserselector>
</div>
<!-- 寝室新增/编辑表单 -->
<Form ref="formRef"></Form>
<!-- 宿舍楼新增/编辑表单 -->
<FormDormitory ref="formRefD" />
<!-- 班主任绑定/修改 -->
<!-- :user-selector-params="{ orgId: orgId }" -->
<ClassUserselector
ref="userSelectorRef"
:org-tree-api="userManageClassManageApi.page"
:org-tree-props="{ label: 'name', children: 'children' }"
:user-selector-api="userManagePersonnelApi.page"
multiple
@successful="handleChooseUser"
>
</ClassUserselector>
<!-- <formUser ref="formRefU" /> -->
<!-- 预览头像 -->
<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 v-model="timeVisible" title="归寝时间设置" :before-close="closeTime">
<el-form :model="timeForm" :rules="timeRules" ref="timeFormRef" label-width="100px">
<el-row>
<el-col :span="16">
<el-form-item label="功能有效期:" prop="dateArr">
<el-date-picker
v-model="timeForm.dateArr"
type="daterange"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
:size="size"
/>
</el-form-item>
</el-col>
<el-col :span="16">
<el-form-item label="布防时间:" prop="timeArr">
<el-time-picker
v-model="timeForm.timeArr"
format="HH:mm:ss"
value-format="HH:mm:ss"
is-range
range-separator="-"
start-placeholder="开始时间"
end-placeholder="结束时间"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>

<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onTimeSubmit">提交</el-button>
<el-button @click="closeTime">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="tsx" name="SysDormitory">
import { userManageDormitoryApi,dormitoryButtonCode,SysDormitory,sysOrgApi,sysPositionApi,sysUserApi,sysRoleApi,userManagePersonnelApi,userManageClassManageApi } from "@/api";
import { userManageDormitoryApi,dormitoryButtonCode,SysDormitory,userManagePersonnelApi,userManageClassManageApi,SysUser } from "@/api";
import { useHandleData } from "@/hooks/useHandleData";
import { FormOptEnum } from "@/enums";
import Form from "./components/form/index.vue";
import FormDormitory from "./components/formDormitory/index.vue";
import formUser from "./components/formUser/index.vue";
import { ArrowDown,More } from "@element-plus/icons-vue";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import TreeFilter from "@/components/TreeFilter/index.vue";
@@ -105,8 +136,7 @@ import { TokenEnum } from "@/enums";
import type { UploadProps } from "element-plus";
import { UserSelectorInstance } from "@/components/Selectors/UserSelector/interface";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const faceUrl = ref('');
const visible = ref(false); //是否显示寝室表单

const proTable = ref<ProTableInstance>();
const treeFilter = ref<InstanceType<typeof TreeFilter> | null>(null);
const userStore = useUserStore();
@@ -128,32 +158,84 @@ const columns: ColumnProps<SysDormitory.ChamberInfo>[] = [
},
{ 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 size = ref<'default' | 'large' | 'small'>('default')
const timeVisible = ref(false); //是否显示时间设置
const timeForm = reactive<any>({
dateArr: [],
timeArr: [],
});

const timeRules = ref({
dateArr: [{ required: true, message: "请选择功能有效期", trigger: "change" }],
timeArr: [{ required: true, message: "请选择布防时间", trigger: "change" }],
});
const timeFormRef = ref<any>(null);
const settingTime = () => {
timeVisible.value = true;
getTimeDetail()
};
const getTimeDetail = () => {
userManageDormitoryApi.getReturnTime().then((res:any) => {
let {data} = res
timeForm.dateArr = [data.funcStart,data.funcEnd] as never[];
timeForm.timeArr = [data.timeBegin,data.timeEnd] as never[];
});
}
const closeTime = () => {
timeForm.dateArr = [];
timeForm.timeArr = [];
timeVisible.value = false;
};
const handleClose = () => {
visible.value = false;
// 提交分组
const onTimeSubmit = () => {
timeFormRef.value.validate((valid: any) => {
if (valid) {
let params: any = reactive({
funcStart: timeForm.dateArr[0],
funcEnd: timeForm.dateArr[1],
timeBegin: timeForm.timeArr[0],
timeEnd: timeForm.timeArr[1]
});
userManageDormitoryApi.setReturnTime(params).then((res:any) => {
if (res.code == 200) {
// getGroupList();
ElMessage({
message: res.msg,
type: 'success'
});
closeTime();
}
});
} else {
return false;
}
});
};
// 确定人员
function handleChooseUser(data: SysUser.SysUserInfo[]) {
console.log(data)
//组装参数
const grantUser: SysRole.GrantUserReq = {
const grantUser: SysDormitory.ChamberPersonnel = {
// id: roleId.value,
// grantInfoList: data.map(item => item.id) as number[] | string[],
dormitoryId: chamberId.value,
personIds: data.map(item => item.personId) as number[] | string[],
personIds: data.map((item:any) => item.personId) as number[] | string[],
};
userManageDormitoryApi.setAssignPerson(grantUser);
userManageDormitoryApi.setAssignPerson(grantUser).then(res => {
ElMessage({
message: res.msg,
type: 'success'
});
RefreshTable();
})
}
// 寝室表单引用
const formRef = ref<InstanceType<typeof Form> | null>(null);
// 宿舍楼表单引用
const formRefD = ref<InstanceType<typeof FormDormitory> | null>(null);
// 人员引用
const formRefU = ref<InstanceType<typeof formUser> | null>(null);


/**
* 打开表单
@@ -161,13 +243,14 @@ const formRefU = ref<InstanceType<typeof formUser> | null>(null);
* @param record 记录
*/
function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) {
if(buildId.value) {
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
} else {
if(!buildId.value && opt == '新增') {
ElMessage({
message: '请选择宿舍楼',
type: 'warning'
});
} else {
formRef.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
}
}
@@ -204,7 +287,7 @@ function onOpen(opt: FormOptEnum, record: {} | SysDormitory.ChamberInfo = {}) {
return
}
// 二次确认 => 请求api => 刷新表格
await useHandleData(userManageDormitoryApi.delete, {id: ids.join(",") }, msg);
await useHandleData(userManageDormitoryApi.delete, {ids: ids }, msg);
RefreshTable(); //刷新表格
}

@@ -248,16 +331,17 @@ const chamberId = ref<number | string>(); //寝室id
function handleCommand(command: Command) {
switch (command.command) {
case cmdEnum.AddPerson:
console.log(111)
// addPerson(FormOptEnum.add, command.row)
userSelectorRef.value?.showSelector(); //显示用户选择器
userManageDormitoryApi.detail({ id: command.row.id }).then((res:any) => {
userSelectorRef.value?.showSelector(res.data.personInfos); //显示用户选择器
});
chamberId.value = command.row.id; //获取寝室id
break;
}
}
function addPerson(opt: FormOptEnum, record: {} | SysDormitory.DormitoryInfo = {}) {
formRefU.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
}
// function addPerson(opt: FormOptEnum, record: {} | SysDormitory.DormitoryInfo = {}) {
// formRefU.value?.onOpen({ opt: opt, record: record, successful: RefreshTable });
// }
/** 宿舍楼切换 */
const buildId = ref<number | string>()
const buildGender = ref<boolean>()


+ 143
- 0
SafeCampus.WEB/src/views/violation/analysis/index.vue Ver fichero

@@ -0,0 +1,143 @@
<!--
* @Description: 学生画像
* @Author: syy
* @Date: 2024-7-24
-->
<template>
<div class="main-box">
<div class="table-box">
<ProTable ref="proTable" title="预警分析" :columns="columns" rowKey="id" :pagination="false" :request-api="abilityApi.warnGroup">
<!-- 表格 header 按钮 -->
<template #operation="scope">
<s-button icon="Download" link :opt="FormOptEnums.EXPORT" @click="exportFn(scope.row)" />
</template>
</ProTable>
</div>
<el-dialog v-model="timeForm.visible" title="选择导出时间范围" :before-close="closeTime" width="600px">
<el-form :model="timeForm" :rules="timeRules" ref="timeFormRef" label-width="100px">
<el-row>
<el-col :span="21">
<el-form-item label="时间:" prop="dateArr">
<el-date-picker
v-model="timeForm.dateArr"
type="daterange"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>

<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="onTimeSubmit">提交</el-button>
<el-button @click="closeTime">取消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup lang="tsx" name="SysUserPersonnel">
import { abilityApi} from "@/api";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTable = ref<ProTableInstance>();
const timeForm:any= reactive({
dateArr:[],
rowItem:{},
visible:false
});
const timeFormRef = ref();
const timeRules = ref({
dateArr: [
{ required: true, message: "请选择导出时间范围", trigger: "change" }
]
});
/** 表单操作类型枚举 */
enum FormOptEnums {
/** 导出 */
EXPORT = "导出",
}
// 表格配置项
const columns: ColumnProps[] = [{ type: "index", label: "序号", width: 60, fixed: "left" },
{
prop: "cameraName",
label: "摄像头",
render: (scope: any) => {
return scope.row.cameraName.join(", ");
}
},
{
prop: "name",
label: "场景"
},
{
prop: "state",
label: "状态",
render: (scope: any) => {
return scope.row.state ? <el-tag type="success">启用</el-tag> : <el-tag type="danger">禁用</el-tag>;
}
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];
/* 导出 */
const onTimeSubmit = ()=>{
timeFormRef.value.validate((valid: any) => {
if (valid) {
abilityApi.reportExport({
groupCode:timeForm.rowItem.code,
startTime: timeForm.dateArr[0],
endTime: timeForm.dateArr[1],
}).then((res:any) => {
console.log(res,"....UTF-8''");
const filename:any = ref()
filename.value = window.decodeURI(res.headers["content-disposition"].split("=")[2]);
filename.value = filename.value.slice(7,-1)
let blobUrl = window.URL.createObjectURL(res.data);
const a = document.createElement('a');
a.style.display = 'none';
a.setAttribute("target", "_blank");
a.download = filename.value
a.href = blobUrl;
a.click();
a.remove();
ElMessage({
message: res.msg,
type: 'success'
});
closeTime();
});
} else {
return false;
}
});
};
const closeTime = () =>{
timeForm.visible = false
}
const exportFn = (row: any) => {
timeForm.rowItem = JSON.parse(JSON.stringify(row));
timeForm.visible = true
};

</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>

+ 254
- 0
SafeCampus.WEB/src/views/violation/portrait/detail.vue Ver fichero

@@ -0,0 +1,254 @@
<template>
<div class="roolcallDetail">
<div class="header">
<div class="left">
<el-image
style="width: 100px; height: 100px"
src="https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"
:zoom-rate="1.2"
:max-scale="7"
:min-scale="0.2"
:preview-src-list="['https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg']"
:initial-index="4"
fit="cover"
/>
</div>
<div class="right">
<el-row>
<el-col :span="6">
<span>人员编号:{{ formData.personId }}</span></el-col
>
<el-col :span="6"
><span>姓名:{{ formData.name }}</span></el-col
>
<el-col :span="6"
><span>性别:{{ genderOptions[formData.gender] }}</span></el-col
>
<el-col :span="6"
><span>年龄:{{ formData.age }}</span></el-col
>
<el-col :span="6"
><span>联系方式:{{ formData.phone }}</span>
</el-col>
<el-col :span="6"><span>班级:演示一班</span> </el-col>
</el-row>
</div>
</div>
<div class="content">
<div ref="chartEl" style="width: 100%; height: 100%"></div>
</div>
</div>
</template>
<script setup lang="ts" name="ViolationPortraitDetail">
import { userManagePersonnelApi, portraitSummaryApi } from "@/api";
const route = useRoute();
const formData = ref<any>({}); //班级人员列表
import * as echarts from "echarts";
const chartEl = ref(null);
const genderOptions = ref<any>({
GENDER_UNKNOWN: "未知",
GENDER_MALE: "男",
GENDER_FEMALE: "女"
});
const getDetail = () => {
userManagePersonnelApi.detail({ id: route.query.personId }).then((res: any) => {
formData.value = res.data;
});
portraitSummaryApi.getStudentDetail({ id: route.query.personId }).then((res: any) => {
getCharts(res.data.label, res.data.value);
});
};
const getCharts = (nameArr: any, valueArr: any) => {
const chart = echarts.init(chartEl.value);
const option = {
title: {
text: "人员属性标签",
left: "center",
top: "5%",
textStyle: {
color: "#000",
fontSize: 25
}
},
grid: {
top: "18%",
left: "5%",
right: "5%",
bottom: "12%"
},
tooltip: {
trigger: "axis",
backgroundColor: "#3A4667",
borderColor: "#3A4667",
textStyle: {
color: "#fff"
},
formatter: "{b} : {c}",
axisPointer: {
type: "cross",
crossStyle: {
color: "#999"
}
}
},
legend: {
icon: "rect",
top: 10,
right: 5,
itemWidth: 10,
itemHeight: 10,
textStyle: {
fontSize: 12, // 字体大小
// color: '#B3CFFF', // 字体颜色
color: "#FFEB3B"
}
},
xAxis: {
type: "category",
axisPointer: {
type: "shadow"
},
axisLine: {
lineStyle: {
color: "rgba(112, 138, 198, 1)"
}
},
axisLabel: {
textStyle: {
color: "#333", // x轴文本颜色
fontSize: 12
}
// rotate:30,
},
axisTick: {
show: false
},
data: nameArr
},
yAxis: {
name: "次",
type: "value",
splitLine: {
show: true,
lineStyle: {
color: "#333",
type: "dashed"
}
},
axisLabel: {
formatter: "{value}",
textStyle: {
color: "#333", // x轴文本颜色
fontSize: 12
}
},
nameTextStyle: {
color: "#333",
fontSize: 12
}
},
series: [
{
type: "bar",
name: "",
barWidth: 27,
emphasis: {
itemStyle: {
color: "#7fb7e9"
},
label: {
textStyle: {
color: "#7fb7e9"
}
}
},
label: {
show: true,
position: "top",
textStyle: {
color: "rgba(12, 245, 229, 1)",
padding: [0, 10]
}
},
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: "rgba(12, 245, 229, 1)"
// opacity: 0.6
},
{
offset: 0,
color: "rgba(12, 245, 229, 0)"
// opacity: 1
}
])
}
},
data: valueArr
},
{
name: "",
type: "pictorialBar",
itemStyle: {
normal: {
color: "rgba(12, 245, 229, 1)"
}
},
symbol: "rect", // 图形类型,这里是矩形
symbolRotate: 0,
symbolSize: ["27", "3"],
symbolPosition: "end",
data: valueArr,
z: 3
}
]
};

chart.setOption(option);
window.addEventListener("resize", function () {
chart.resize();
});
};
onMounted(() => {
getDetail();
});
</script>
<style lang="scss" scoped>
.roolcallDetail {
.header {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 180px;
padding: 10px 20px;
background: #ffffff;
.left {
display: flex;
align-items: center;
justify-content: flex-end;
width: 200px;
height: 100%;
}
.right {
width: calc(100% - 200px);
.el-row {
height: 100%;
.el-col {
height: 50px;
line-height: 50px;
text-align: center;
}
}
}
}
.content {
height: 550px;
margin-top: 20px;
background: #ffffff;
}
}
</style>

+ 123
- 0
SafeCampus.WEB/src/views/violation/portrait/index.vue Ver fichero

@@ -0,0 +1,123 @@
<!--
* @Description: 学生画像
* @Author: syy
* @Date: 2024-7-24
-->
<template>
<div class="main-box">
<TreeFilter
ref="treeFilter"
label="personSetName"
id="personSetId"
width="300px"
title="班级管理"
:show-all="true"
:request-api="userManageClassManageApi.page"
@change="changeTreeFilter"
>
<template v-slot:label="{ row }">
<span class="custom-tree-node">
<span>{{ row.node.label }} {{ row.node.userName ? `(${row.node.userName})` : "" }}</span>
</span>
</template>
</TreeFilter>
<div class="table-box">
<ProTable ref="proTable" title="人员列表" :columns="columns" rowKey="id" :request-api="userManagePersonnelApi.page">
<!-- 表格操作栏 -->
<template #operation="scope">
<el-space>
<s-button link :opt="FormOptEnum.VIEW" @click="onView(scope.row)" />
</el-space>
</template>
</ProTable>
</div>
<!-- 预览头像 -->
<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="ViolationPortrait">
import { userManagePersonnelApi,userManageClassManageApi} from "@/api";
import { FormOptEnum } from "@/enums";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import TreeFilter from "@/components/TreeFilter/index.vue";
import { useRouter } from "vue-router";
const visible = ref(false); //是否显示人员表单
const faceUrl = ref('');
const router = useRouter();
// 获取 ProTable 元素,调用其获取刷新数据方法(还能获取到当前查询参数,方便导出携带参数)
const proTable = ref<ProTableInstance>();
const treeFilter = ref<any>();
// 表格配置项
const columns: ColumnProps[] = [
{
prop: "faceUrl",
label: "人脸",
render: scope => {
return (
<img src={scope.row.faces.length > 0 ? scope.row.faces[0].faceUrl : ''} onClick={() => viewHeadImage(scope)} style='width:50px;height:50px;' alt=''/>
);
}
},
{
prop: "name",
label: "姓名"
},
{
prop: "personId",
label: "人员ID"
},
{
prop: "phone",
label: "手机号"
},
{
prop: "personSetName",
label: "所属班级",
},
{ prop: "operation", label: "操作", width: 250, fixed: "right" }
];
const viewHeadImage = (scope: any) => {
faceUrl.value = scope.row.faces[0].faceUrl;
visible.value = true
};
const handleClose = () => {
visible.value = false;
};

const onView = (row: any) => {
router.push({
path:'/violation/portrait/detail',
query: {
personId: row.personId
}
});
};

/** 部门切换 */
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>

+ 539
- 0
SafeCampus.WEB/src/views/violation/portraitSummary/index.vue Ver fichero

@@ -0,0 +1,539 @@
<template>
<div class="home">
<el-row :gutter="20">
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="home-bg card">
<div class="home-bg-title">
<div></div>
<div>学生性别</div>
</div>
<div class="home-bg-content">
<div ref="chart1" style="width: 100%; height: 100%"></div>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="home-bg card">
<div class="home-bg-title">
<div></div>
<div>学生年龄</div>
</div>
<div class="home-bg-content">
<div ref="chart2" style="width: 100%; height: 100%"></div>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="home-bg card">
<div class="home-bg-title">
<div></div>
<div>地理位置</div>
</div>
<div class="home-bg-content">
<div ref="chart5" style="width: 100%; height: 100%"></div>
</div>
</div>
</el-col>
<el-col :xs="24" :sm="24" :md="12" :lg="12" :xl="12">
<div class="home-bg card">
<div class="home-bg-title">
<div></div>
<div>标签属性</div>
</div>
<div class="home-bg-content handleBox">
<div ref="chart4" style="width: 100%; height: 100%"></div>
</div>
</div>
</el-col>
</el-row>
</div>
</template>

<script setup lang="ts" name="home">
import * as echarts from "echarts";
import { portraitSummaryApi } from "@/api";
const chart1 = ref(null);
const chart2 = ref(null);
const chart4 = ref(null);
const chart5 = ref(null);
onMounted(() => {
getDataChart();
});
const getDataChart = async () => {
/* 获取学生性别 */
let sex: any = await portraitSummaryApi.getStudentSex();
getCharts1(sex.data.label, sex.data.value);
/* 获取学生年龄 */
let age: any = await portraitSummaryApi.getStudentAge();
getCharts2(age.data.label, age.data.value);
/* 获取属性标签 */
let attr: any = await portraitSummaryApi.getStudentAttr();
getCharts4(attr.data.label, attr.data.value);
/* 获取地理位置 */
let address: any = await portraitSummaryApi.getAddress();
getCharts5(address.data.label, address.data.value);
};

const handleDate = (label: any, value: any, key: any = "") => {
let data: any = [];
label.forEach((item: any, index: number) => {
data.push({
value: value[index],
name: item + key
});
});
return data;
};
/* 性別 */
function getCharts1(label: any, value: any) {
const chart = echarts.init(chart1.value);
const data = handleDate(label, value);
const option = {
tooltip: {
confine: true
},
legend: {
show: true,
right: "0%",
top: "center",
orient: "vertical",
data: label
},
series: [
{
type: "pie",
radius: "80%",
center: ["50%", "50%"],
roseType: "area",
label: {
normal: {
show: true
},
emphasis: {
show: true
}
},
itemStyle: {
normal: {
label: {
show: true,
// position:'inside',
formatter: "{b} : {c}人"
}
},
labelLine: {
show: true
}
},
data: data
}
]
};

chart.setOption(option);
window.addEventListener("resize", function () {
chart.resize();
});
}
/* 年齡 */
function getCharts2(label: any, value: any) {
const chartstation = echarts.init(chart2.value);
const data = handleDate(label, value, "岁");
const labelArr: any = [];
label.map((item: any) => labelArr.push(item + "岁"));
const option = {
legend: {
show: true,
right: "0%",
top: "center",
orient: "vertical",
data: labelArr
},
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)"
},
calculable: true,
series: [
{
name: "年龄分布",
type: "pie",
radius: [50, 140],

roseType: "area",
data: data,
itemStyle: {
normal: {
label: {
show: true,
// position:'inside',
formatter: "{b} : {c}人"
}
},
labelLine: {
show: true
}
}
}
]
};

chartstation.setOption(option);
window.addEventListener("resize", function () {
chartstation.resize();
});
}
/* 兴趣爱好 */
function getCharts4(categoryData: any, dataArr: any) {
const chartstation = echarts.init(chart4.value);
var spaceLength = 5,
fixedData = [],
end = 0,
max = 300;
// var categoryData = ys.超市品牌;
let xhao: any = [];
for (var i = 0; i < dataArr.length; i++) {
xhao.push(i + 1);
}

var data1 = dataArr.map((item: any) => {
fixedData.push(spaceLength);
return item - spaceLength;
});
if (categoryData.length < 5) {
end = categoryData.length - 1;
} else {
end = 5;
}
const option = {
xAxis: [{ show: false }],

yAxis: [
{
splitLine: {
show: false
},
axisLine: {
//y轴
show: false
},
type: "category",
inverse: true,
axisTick: {
show: false
},

data: categoryData,
axisLabel: {
align: "left",
margin: 170,
formatter: function (value: any, index: any) {
const num = ref<any>("");
var str = "";
num.value = xhao[categoryData.indexOf(value)];
if (index === 0) {
str = "{no1|" + "} {num1|" + num.value + "} {title| " + value + "}";
} else if (index === 1) {
str = "{no2|" + "} {num2|" + num.value + "} {title| " + value + "}";
} else if (index === 2) {
str = "{no3|" + "} {num3|" + num.value + "} {title| " + value + "}";
} else {
str = " {num|" + num.value + "} {title| " + value + "}";
}

return str;
},
rich: {
num: {
color: "#387ec1",
backgroundColor: "#112b67",
width: 10,
height: 10,
fontSize: 14,
padding: [6, 5, 3, 5],
align: "center",
shadowColor: "#3374ba",
borderColor: "#3374ba",
borderWidth: 1
},
num1: {
color: "#51aff8",
backgroundColor: "#112b67",
width: 10,
height: 10,
fontSize: 14,
padding: [7, 5, 3, 5],
align: "center",
shadowColor: "#4db2ff",
borderColor: "#4db2ff",
borderWidth: 1
},
num2: {
color: "#51aff8",
backgroundColor: "#112b67",
width: 10,
height: 10,
fontSize: 14,
padding: [7, 5, 3, 5],
align: "center",
shadowColor: "#4db2ff",
borderColor: "#4db2ff",
borderWidth: 1
},
num3: {
color: "#51aff8",
backgroundColor: "#112b67",
width: 10,
height: 10,
fontSize: 14,
padding: [7, 5, 3, 5],
align: "center",
shadowColor: "#4db2ff",
borderColor: "#4db2ff",
borderWidth: 1
},
title: {
color: "#000"
}
}
}
}
],
dataZoom: [
{
show: false,
type: "slider",
yAxisIndex: 0,
zoomLock: false,
width: 8,
showDetail: false,
startValue: 0, // 从头开始。
endValue: end, // 一次性展示五个。
borderWidth: 0,
borderColor: "transparent",
backgroundColor: "#343F4B",
fillerColor: "#4291CE",
showDataShadow: false,
brushSelect: false,
height: "88%",
handleStyle: {
color: "#4291CE"
},
handleIcon: "path://M512 512m-320 0a320 320 0 1 0 640 0 320 320 0 1 0-640 0Z"
}
],
grid: {
right: "14%",
left: "35%",
top: "4%",
bottom: "1%"
},
series: [
{
name: "",
type: "bar",
barWidth: 12, // 柱子宽度
itemStyle: {
normal: {
color: function (params: any) {
// var colorList = [
// '#7711AF', '#CF77FF', '#AE004F', '#F35872', '#FA7729',
// '#FFC526', '#F8E71C', '#34ADAE', '#3DDFD2', '#A0FFFF'
// ];
var colorListr = [
"#8A64B8",
"#7575D3",
"#5F85DD",
"#6FABE8",
"#7ED3F4",
"#8CD8C0",
"#9CDF8D",
"#BFED6B",
"#EAFE4F",
"#FFFD47",
"#FFEA55",
"#FFCF63",
"#FFA069",
"#fce38a",
"#eaffd0",
"#95e1d3",
"#e3fdfd",
"#749f83",
"#ca8622"
];
return colorListr[params.dataIndex];
},

shadowBlur: 20,
shadowColor: "rgba(40, 40, 40, 0.5)"
}
},
label: {
formatter: function (parms: any) {
return parms.value + spaceLength;
},
show: true,
position: "right", // 位置
color: "#1CD8A8",
fontSize: 14,
fontWeight: "bold", // 加粗
distance: 10 // 距离
},

data: data1
}
]
};

chartstation.setOption(option);
window.addEventListener("resize", function () {
chartstation.resize();
});
}

/* 标签、地理位置 */
function getCharts5(nameArr: any, valueArr: any) {
const chartstation5 = echarts.init(chart5.value);
const option = {
grid: {
top: "10%",
left: "8%",
right: "5%",
bottom: "20%"
},
tooltip: {
trigger: "axis",
backgroundColor: "#3A4667",
borderColor: "#3A4667",
textStyle: {
color: "#fff"
},
formatter: "{b} : {c}",
axisPointer: {
type: "cross",
crossStyle: {
color: "#999"
}
}
},
legend: {
icon: "rect",
top: 10,
right: 5,
itemWidth: 10,
itemHeight: 10,
textStyle: {
fontSize: 12, // 字体大小
color: "#B3CFFF" // 字体颜色
}
},
xAxis: {
type: "category",
axisPointer: {
type: "shadow"
},
axisLine: {
lineStyle: {
color: "rgba(112, 138, 198, 1)"
}
},
axisLabel: {
textStyle: {
color: "#333", // x轴文本颜色
fontSize: 12
}
// rotate:30,
},
axisTick: {
show: false
},
data: nameArr
},
yAxis: {
type: "value",
splitLine: {
show: true,
lineStyle: {
color: "#162647",
type: "solid"
}
},
axisLabel: {
formatter: "{value}",
textStyle: {
color: "#333", // x轴文本颜色
fontSize: 12
}
},
name: "",
nameTextStyle: {
color: "#B3CFFF",
fontSize: 12
}
},
series: [
{
type: "bar",
name: "",
barWidth: 16,
emphasis: {
itemStyle: {
color: "#7fb7e9"
},
label: {
textStyle: {
color: "#7fb7e9"
}
}
},
label: {
show: true,
position: "top",
textStyle: {
color: "rgba(147, 157, 223, 1)",
padding: [0, 10]
}
},
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: "rgba(147, 157, 223, 1)"
},
{
offset: 0,
color: "rgba(147, 157, 223, 0)"
}
])
}
},
data: valueArr
},
{
name: "",
type: "pictorialBar",
itemStyle: {
normal: {
color: "rgba(147, 157, 223, 1)"
}
},
symbolRotate: 0,
symbolSize: ["16", "3"],
symbolPosition: "end",
data: valueArr,
z: 3
}
]
};
chartstation5.setOption(option);
window.addEventListener("resize", function () {
chartstation5.resize();
});
}
</script>


<style scoped lang="scss">
@import "../../home/index.scss";
</style>

+ 21
- 35
SafeCampus.WEB/src/views/warn/statistion/index.vue Ver fichero

@@ -36,17 +36,17 @@ onMounted(() => {
});
function getDataChart() {
setTimeout(async () => {
await statistionApi.warnstatistion({}).then(res => {
await statistionApi.warnstatistion({}).then((res: any) => {
let { code, data } = res;

if (code == 200) {
let chartData1 = data.alarm.map(item => {
let chartData1 = data.alarm.map((item: any) => {
return {
value: item.count,
name: item.name
};
});
let chartData2 = data.hand.map(item => {
let chartData2 = data.hand.map((item: any) => {
return {
value: item.count,
name: item.name
@@ -68,7 +68,7 @@ function getDataChart() {
});
});
}
function getCharts1(data) {
function getCharts1(data: any) {
const chart = echarts.init(chart1.value);
const option = {
title: {
@@ -105,7 +105,7 @@ function getCharts1(data) {
chart.resize();
});
}
function getCharts2(data) {
function getCharts2(data: any) {
const chartstation = echarts.init(chart2.value);
const option = {
title: {
@@ -142,39 +142,23 @@ function getCharts2(data) {
chartstation.resize();
});
}
function flattenArray(arr) {
const result = [];
arr.forEach(item => {
if (Array.isArray(item)) {
result.push(...flattenArray(item));
} else {
result.push(item);
}
});
return result;
}

function unique(arr) {
return arr.filter((item, index, arr) => arr.indexOf(item, 0) === index);
}
function getWeekData() {
setTimeout(async () => {
await statistionApi.weekstatistion({}).then(res => {
await statistionApi.weekstatistion({}).then((res: any) => {
let { code, data } = res;

if (code == 200) {
// let chartData = data;
let time = data.dataX;
let chartData = data.dataY.map(item => {
let chartData = data.dataY.map((item: any) => {
return {
data: item.data,
name: item.name,
type: "bar",
barWidth: "12px", // 设置柱子粗细
itemStyle: {
normal: {
barBorderRadius: [30, 30, 0, 0]
}
borderRadius: [30, 30, 0, 0]
}
};
});
@@ -183,7 +167,7 @@ function getWeekData() {
});
});
}
function getCharts3(time, data) {
function getCharts3(time: any, data: any) {
const chartstation3 = echarts.init(chart3.value);
const option = {
title: {
@@ -228,21 +212,20 @@ function getCharts3(time, data) {
height: 50px;
line-height: 50px;
}

.collapse-title {
flex: 1 0 90%;
order: 1;
display: flex;
flex: 1 0 90%;
align-items: center;
justify-content: space-between;
// padding: 30px 0;
order: 1;

// padding: 30px 0;
.titlemodel {
margin-right: 40px;

// display: inline-block;
font-size: 18px;
margin-right: 40px;
}

.btns {
margin-left: 40px;
}
@@ -250,19 +233,22 @@ function getCharts3(time, data) {
.collapse-content {
padding: 20px;
.contentinfo {
margin-top: 20px;
box-sizing: border-box;

// display: flex;
// justify-content: space-between;
// align-items: center;
padding: 20px 20px;
box-sizing: border-box;
padding: 20px;
margin-top: 20px;

// border-bottom: 1px solid #dcdfe6;
// background: red;
border-radius: 10px;

// box-shadow: 3px 3px 3px #00000014, 3px -3px 3px #00000014, -3px 3px 3px #00000014, -3px -3px 3px #00000014;
// box-shadow: 0 1px 1px hsl(0deg 0% 0% / 0.075), 0 2px 2px hsl(0deg 0% 0% / 0.075), 0 4px 4px hsl(0deg 0% 0% / 0.075),
// 0 8px 8px hsl(0deg 0% 0% / 0.075), 0 16px 16px hsl(0deg 0% 0% / 0.075);
box-shadow: 0px 2px 1px rgba(0, 0, 0, 0.1), 0 0px 8px rgba(0, 0, 0, 0.1), 0 -1px 1px #fff, 0px 0 0px #fff, 0 0 16px #fff;
box-shadow: 0 2px 1px rgb(0 0 0 / 10%), 0 0 8px rgb(0 0 0 / 10%), 0 -1px 1px #ffffff, 0 0 0 #ffffff, 0 0 16px #ffffff;
.modellabel {
font-size: 16px;
}


+ 101
- 0
SafeCampus.WEB/src/views/warn/zjrq/components/handleForm.vue Ver fichero

@@ -0,0 +1,101 @@
<!--
* @Description: 表单
* @Author: syy
* @Date: 2023-12-15 15:45:59
-->
<template>
<div>
<form-container v-model="visibleChamber" title="处理" form-size="600px" @close="onClose">
<el-form
ref="SysDormitoryFormRef"
:rules="rules"
:disabled="warnHandleProps.disabled"
:model="warnHandleProps.record"
:hide-required-asterisk="warnHandleProps.disabled"
label-width="auto"
label-suffix=" :"
>
<div>
<el-row :gutter="16">
<el-col :span="22">
<s-form-item label="处理意见" prop="remark">
<el-input v-model="warnHandleProps.record.remark" :autosize="{ minRows: 4 }" type="textarea" placeholder="请输入处理意见" />
</s-form-item>
</el-col>
</el-row>
</div>
</el-form>
<template #footer>
<el-button @click="onClose"> 取消 </el-button>
<el-button v-show="!warnHandleProps.disabled" type="primary" @click="handleSubmit"> 确定 </el-button>
</template>
</form-container>
</div>
</template>

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

const visibleChamber = ref(false); //是否显示表单
// 表单参数
const warnHandleProps = reactive<FormProps.Base<ZJRQ.WarnInfo>>({
opt: FormOptEnum.ADD,
record: {},
disabled: false
});
// 表单验证规则
const rules = reactive({
remark: [required("请输入处理意见")]
});

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

// 提交数据(新增/编辑)
const SysDormitoryFormRef = ref<FormInstance>();
/** 提交表单 */
async function handleSubmit() {
SysDormitoryFormRef.value?.validate(async valid => {
if (!valid) return; //表单验证失败
let params: any = {
id: warnHandleProps.record.id,
remark: warnHandleProps.record.remark
};
await warnZJRQApi
.handWarn(params)
.then((res: any) => {
ElMessage({
message: res.msg,
type: "success"
});
warnHandleProps.successful!(); //调用父组件的successful方法
})
.finally(() => {
onClose();
});
});
}

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

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

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

+ 28
- 11
SafeCampus.WEB/src/views/warn/zjrq/index.vue Ver fichero

@@ -34,7 +34,7 @@
<!-- 操作 -->
<template #operation="scope">
<s-button link :opt="FormOptEnum.VIEW" @click="onDetail(scope.row)"> 详情 </s-button>
<s-button link :opt="FormOptEnum.EDIT" @click="onOpen(FormOptEnum.EDIT, scope.row)">处理</s-button>
<s-button v-if="scope.row.warnHand == 0" link :opt="FormOptEnum.EDIT" @click="toHandle(FormOptEnum.EDIT, scope.row)">处理</s-button>
<s-button link :opt="FormOptEnum.DELETE" @click="onDelete([scope.row.id], `确定删除该预警吗?`)" />
</template>
</ProTable>
@@ -77,6 +77,16 @@
<!-- {{ detailData.videoUrl }} -->
</div>
</el-col>
<el-col :span="24">
<div class="linebox">
处理意见:
<span style="cursor: pointer" v-if="detailData.remark">
{{ detailData.remark }}
</span>
<span v-else>暂无数据</span>
<!-- {{ detailData.videoUrl }} -->
</div>
</el-col>
</el-row>
</div>
<template #footer>
@@ -111,6 +121,8 @@
<img class="detailpic" :src="faceUrl" alt="" />
</div>
</el-dialog>
<!-- 处理告警 -->
<handleForm ref="formRefH" />
</div>
</template>

@@ -120,6 +132,7 @@ import { warnZJRQApi } from "@/api";
import { ZJRQ } from "@/api/interface";
import { useHandleData } from "@/hooks/useHandleData";
import { ColumnProps, ProTableInstance } from "@/components/ProTable/interface";
import handleForm from "./components/handleForm.vue";
import { useDictStore } from "@/stores/modules";
import { FormOptEnum, SysDictEnum, MenuTypeDictEnum } from "@/enums";
const faceUrl = ref('');
@@ -136,14 +149,18 @@ const visible = ref(false); //是否显示表单
onMounted(() => {
getWarnTypeList();
});
const formRefH = ref<InstanceType<typeof handleForm> | null>(null);
function toHandle(opt: FormOptEnum, record: {} | ZJRQ.WarnInfo= {}) {
formRefH.value?.onOpen({ opt: opt, record: JSON.parse(JSON.stringify(record)), successful: RefreshTable });
}
let warnOptions = ref([]);
function getWarnTypeList() {
setTimeout(async ()=> {
await warnZJRQApi.warnType({}).then(res => {
await warnZJRQApi.warnType({}).then((res:any) => {
let { code, data } = res;
if (code == 200) {
warnOptions.value = data.map(item => {
warnOptions.value = data.map((item:any) => {
return {
label: item.name,
value: item.code
@@ -299,14 +316,14 @@ let detailData = ref({});
function onDetail(row: any) {
visible.value = true;
setTimeout(async ()=> {
await warnZJRQApi.detail({ id: row.id }).then(res => {
let { code, data } = res;
if (code == 200) {
detailData.value = data
}
});
await warnZJRQApi.detail({ id: row.id }).then((res:any) => {
let { code, data } = res;
if (code == 200) {
detailData.value = data
}
});
})
}


Cargando…
Cancelar
Guardar