feat:第二版
This commit is contained in:
1 parent
53bdab7f0c
commit
bf4f9348df
21 files changed
+775
-221
No files matched your search
@@ -1,8 +1,8 @@
|
||||
# 网站主标题
|
||||
VITE_GLOBAL_TITLE= 'PIGX ADMIN'
|
||||
VITE_GLOBAL_TITLE= '智慧安防平台'
|
||||
|
||||
# footer
|
||||
VITE_FOOTER_TITLE= '©2025 pig4cloud.com'
|
||||
VITE_FOOTER_TITLE= ''
|
||||
|
||||
# 是否是微服务架构(重要)
|
||||
VITE_IS_MICRO= true
|
||||
@@ -38,13 +38,13 @@ VITE_VERIFY_IMAGE_ENABLE = false
|
||||
VITE_WEBSOCKET_ENABLE = false
|
||||
|
||||
# 是否开启注册
|
||||
VITE_REGISTER_ENABLE = true
|
||||
VITE_REGISTER_ENABLE = false
|
||||
|
||||
# 是否开启租户自动选择 (根据租户域名)
|
||||
VITE_AUTO_TENANT = false
|
||||
|
||||
# 是否开启多语言切换
|
||||
VITE_I18N_ENABLE = true
|
||||
VITE_I18N_ENABLE = false
|
||||
|
||||
# 是否开启暗黑模式切换
|
||||
VITE_DARK_MODE_ENABLE = true
|
||||
|
||||
@@ -8,10 +8,10 @@ VITE_OPEN = true
|
||||
ENV = 'prod'
|
||||
|
||||
# ADMIN 服务地址
|
||||
# VITE_ADMIN_PROXY_PATH = http://127.0.0.1:36588
|
||||
VITE_ADMIN_PROXY_PATH = http://127.0.0.1:36588
|
||||
|
||||
# 本地
|
||||
VITE_ADMIN_PROXY_PATH = http://172.20.10.2:36588
|
||||
# VITE_ADMIN_PROXY_PATH = http://172.20.10.2:36588
|
||||
|
||||
# 图片访问基础地址
|
||||
VITE_IMAGE_BASE_PATH = http://123.157.250.162:36588/api
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.9 KiB |
@@ -1,5 +1,27 @@
|
||||
import request from "/@/utils/request"
|
||||
|
||||
/**
|
||||
* 加入考勤的人员在位数量分页
|
||||
*/
|
||||
export function reignCount(data: any) {
|
||||
return request({
|
||||
url: '/admin/door/total/reignCount',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 迟到、早退数量统计
|
||||
*/
|
||||
export function beLateCount(data: any) {
|
||||
return request({
|
||||
url: '/admin/door/total/beLateCount',
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchList(query?: Object) {
|
||||
return request({
|
||||
url: '/admin/door/doorRecord/page',
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
<template>
|
||||
<div class="layout-logo" v-if="setShowLogo" @click="onThemeConfigChange">
|
||||
<span :style="{color:setFontColor}">{{ themeConfig.globalTitle }}</span>
|
||||
<span :style="{ color: setFontColor }">{{ themeConfig.globalTitle }}</span>
|
||||
</div>
|
||||
<div class="layout-logo-size" v-else @click="onThemeConfigChange">
|
||||
<img :src="logoMini" class="layout-logo-size-img"/>
|
||||
<!-- <img :src="logoMini" class="layout-logo-size-img" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="layoutLogo">
|
||||
import {useThemeConfig} from '/@/stores/themeConfig';
|
||||
import { useThemeConfig } from '/@/stores/themeConfig';
|
||||
import logoMini from '/@/assets/logo-mini.svg';
|
||||
|
||||
// 定义变量内容
|
||||
const storesThemeConfig = useThemeConfig();
|
||||
const {themeConfig} = storeToRefs(storesThemeConfig);
|
||||
const { themeConfig } = storeToRefs(storesThemeConfig);
|
||||
|
||||
// 设置 logo 的显示。classic 经典布局默认显示 logo
|
||||
const setShowLogo = computed(() => {
|
||||
let {isCollapse, layout} = themeConfig.value;
|
||||
let { isCollapse, layout } = themeConfig.value;
|
||||
return !isCollapse || layout === 'classic' || document.body.clientWidth < 1000;
|
||||
});
|
||||
|
||||
// 设置 title 的显示颜色。根据布局模式自动显示
|
||||
const setFontColor = computed(() => {
|
||||
let {layout} = themeConfig.value;
|
||||
let { layout } = themeConfig.value;
|
||||
return layout === 'classic' || layout === 'transverse' ? `var(--next-bg-topBarColor)` : 'var(--el-color-primary)';
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="180px"
|
||||
v-loading="state.loading">
|
||||
<el-divider class="mb-12">人员高频次出入</el-divider>
|
||||
<el-form-item label="车闸报警频次" prop="carRepeatCount">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>车闸报警频次</span>
|
||||
<el-tooltip class="box-item" :content="`每天进出${form.carRepeatCount}次就会报警`" placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="form.carRepeatCount" placeholder="请输入道闸报警频次">
|
||||
<template #append>次</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">车辆工作时间</el-divider>
|
||||
<el-form-item prop="carPersonWorkForenoonTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>车辆工作时间(上午)</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.carPersonWorkForenoonTime" is-range
|
||||
placeholder="请选择车辆工作时间(上午)" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="carPersonWorkAfternoonTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>车辆工作时间(下午)</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.carPersonWorkAfternoonTime" is-range
|
||||
placeholder="请选择车辆工作时间(下午)" />
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">夜晚报警</el-divider>
|
||||
<el-form-item prop="carNightAlarmTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>车辆夜晚报警时间</span>
|
||||
<el-tooltip class="box-item" :content="`每天${form.carNightAlarmTime}以后出入人闸报警`" placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.carNightAlarmTime" is-range
|
||||
placeholder="请选择车辆夜晚报警时间" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="carSetting">
|
||||
import { useMessage } from "/@/hooks/message"
|
||||
import * as ComDhSettingApi from "/@/api/com/comDhSetting";
|
||||
|
||||
const dataFormRef = ref();
|
||||
|
||||
const state = reactive<any>({
|
||||
loading: false,
|
||||
})
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive<any>({
|
||||
// 道闸报警频次
|
||||
carRepeatCount: 0,
|
||||
// 工作时间上午
|
||||
carPersonWorkForenoonTime: null,
|
||||
// 工作时间下午
|
||||
carPersonWorkAfternoonTime: null,
|
||||
// 夜晚报警时间
|
||||
carNightAlarmTime: [],
|
||||
})
|
||||
|
||||
const dataRules = ref({
|
||||
carRepeatCount: [{ required: true, message: '车辆报警频次不能为空', trigger: 'blur' }],
|
||||
carPersonWorkForenoonTime: [{ required: true, message: '车辆工作时间(上午)不能为空', trigger: 'change' }],
|
||||
carPersonWorkAfternoonTime: [{ required: true, message: '车辆工作时间(下午)不能为空', trigger: 'change' }],
|
||||
carNightAlarmTime: [{ required: true, message: '车辆报警时间不能为空', trigger: 'change' }],
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getSetting()
|
||||
})
|
||||
|
||||
async function getSetting() {
|
||||
state.loading = true
|
||||
try {
|
||||
const { data } = await ComDhSettingApi.getObj()
|
||||
if (data) {
|
||||
if (data.carPersonWorkForenoonTime) {
|
||||
data.carPersonWorkForenoonTime = data.carPersonWorkForenoonTime.split(',')
|
||||
}
|
||||
if (data.carPersonWorkAfternoonTime) {
|
||||
data.carPersonWorkAfternoonTime = data.carPersonWorkAfternoonTime.split(',')
|
||||
}
|
||||
if (data.carNightAlarmTime) {
|
||||
data.carNightAlarmTime = data.carNightAlarmTime.split(',')
|
||||
}
|
||||
Object.assign(form, data)
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
const valid = await dataFormRef.value.validate().catch(() => { });
|
||||
if (!valid) return false;
|
||||
state.loading = true
|
||||
try {
|
||||
const _form = {
|
||||
...form,
|
||||
}
|
||||
if (_form.carPersonWorkForenoonTime && Array.isArray(_form.carPersonWorkForenoonTime)) {
|
||||
_form.carPersonWorkForenoonTime = _form.carPersonWorkForenoonTime.join(',')
|
||||
}
|
||||
if (_form.carPersonWorkAfternoonTime && Array.isArray(_form.carPersonWorkAfternoonTime)) {
|
||||
_form.carPersonWorkAfternoonTime = _form.carPersonWorkAfternoonTime.join(',')
|
||||
}
|
||||
if (_form.carNightAlarmTime && Array.isArray(_form.carNightAlarmTime)) {
|
||||
_form.carNightAlarmTime = _form.carNightAlarmTime.join(',')
|
||||
}
|
||||
await ComDhSettingApi.putObj(_form)
|
||||
useMessage().success('修改成功');
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getSetting,
|
||||
onSubmit
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="180px"
|
||||
v-loading="state.loading">
|
||||
<el-divider class="mb-12">人员高频次出入</el-divider>
|
||||
<el-form-item prop="doorRepeatCount">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>道闸报警频次</span>
|
||||
<el-tooltip class="box-item" :content="`每天进出${form.doorRepeatCount}次就会报警`" placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="form.doorRepeatCount" placeholder="请输入道闸报警频次">
|
||||
<template #append>次</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">人员工作时间</el-divider>
|
||||
<el-form-item prop="doorPersonWorkForenoonTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>人员工作时间(上午)</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.doorPersonWorkForenoonTime" is-range
|
||||
placeholder="请选择人员工作时间(上午)" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="doorPersonWorkAfternoonTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>人员工作时间(下午)</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.doorPersonWorkAfternoonTime" is-range
|
||||
placeholder="请选择人员工作时间(下午)" />
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">夜晚报警</el-divider>
|
||||
<el-form-item prop="doorNightAlarmTime">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>人员夜晚报警时间</span>
|
||||
</div>
|
||||
</template>
|
||||
<el-time-picker format="HH:mm" value-format="HH:mm" v-model="form.doorNightAlarmTime" is-range
|
||||
placeholder="请选择夜晚报警时间" />
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">主楼配置</el-divider>
|
||||
<el-form-item prop="doorMainFloorChannels">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>主楼入口摄像头</span>
|
||||
</div>
|
||||
</template>
|
||||
<select-tree-channel v-model="form.doorMainFloorChannels" placeholder="请选择主楼入口摄像头" />
|
||||
</el-form-item>
|
||||
<el-divider class="my-12">考勤配置</el-divider>
|
||||
<el-form-item prop="doorCheckingChannels">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>考勤摄像头</span>
|
||||
</div>
|
||||
</template>
|
||||
<select-tree-channel v-model="form.doorCheckingChannels" placeholder="请选择考勤摄像头" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="doorSetting">
|
||||
import { useMessage } from "/@/hooks/message"
|
||||
import * as ComDhSettingApi from "/@/api/com/comDhSetting";
|
||||
|
||||
const dataFormRef = ref();
|
||||
|
||||
const state = reactive<any>({
|
||||
loading: false,
|
||||
})
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive<any>({
|
||||
// 道闸报警频次
|
||||
doorRepeatCount: 0,
|
||||
// 工作时间上午
|
||||
doorPersonWorkForenoonTime: null,
|
||||
// 工作时间下午
|
||||
doorPersonWorkAfternoonTime: null,
|
||||
// 夜晚报警时间
|
||||
doorNightAlarmTime: [],
|
||||
// 通道编号
|
||||
doorMainFloorChannels: [],
|
||||
// 考勤摄像头通道
|
||||
doorCheckingChannels: [],
|
||||
})
|
||||
|
||||
const dataRules = ref({
|
||||
doorRepeatCount: [{ required: true, message: '道闸报警频次不能为空', trigger: 'blur' }],
|
||||
doorPersonWorkForenoonTime: [{ required: true, message: '人员工作时间(上午)不能为空', trigger: 'change' }],
|
||||
doorPersonWorkAfternoonTime: [{ required: true, message: '人员工作时间(下午)不能为空', trigger: 'change' }],
|
||||
doorNightAlarmTime: [{ required: true, message: '夜晚报警时间不能为空', trigger: 'change' }],
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getSetting()
|
||||
})
|
||||
|
||||
async function getSetting() {
|
||||
state.loading = true
|
||||
try {
|
||||
const { data } = await ComDhSettingApi.getObj()
|
||||
if (data) {
|
||||
if (data.doorPersonWorkForenoonTime) {
|
||||
data.doorPersonWorkForenoonTime = data.doorPersonWorkForenoonTime.split(',')
|
||||
}
|
||||
if (data.doorPersonWorkAfternoonTime) {
|
||||
data.doorPersonWorkAfternoonTime = data.doorPersonWorkAfternoonTime.split(',')
|
||||
}
|
||||
if (data.doorMainFloorChannels) {
|
||||
data.doorMainFloorChannels = data.doorMainFloorChannels.split(',')
|
||||
}
|
||||
if (data.doorCheckingChannels) {
|
||||
data.doorCheckingChannels = data.doorCheckingChannels.split(',')
|
||||
}
|
||||
if (data.doorNightAlarmTime) {
|
||||
data.doorNightAlarmTime = data.doorNightAlarmTime.split(',')
|
||||
}
|
||||
Object.assign(form, data)
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
const valid = await dataFormRef.value.validate().catch(() => { });
|
||||
if (!valid) return false;
|
||||
state.loading = true
|
||||
try {
|
||||
const _form = {
|
||||
...form,
|
||||
}
|
||||
if (_form.doorPersonWorkForenoonTime && Array.isArray(_form.doorPersonWorkForenoonTime)) {
|
||||
_form.doorPersonWorkForenoonTime = _form.doorPersonWorkForenoonTime.join(',')
|
||||
}
|
||||
if (_form.doorPersonWorkAfternoonTime && Array.isArray(_form.doorPersonWorkAfternoonTime)) {
|
||||
_form.doorPersonWorkAfternoonTime = _form.doorPersonWorkAfternoonTime.join(',')
|
||||
}
|
||||
if (_form.doorMainFloorChannels && Array.isArray(_form.doorMainFloorChannels)) {
|
||||
_form.doorMainFloorChannels = _form.doorMainFloorChannels.join(',')
|
||||
}
|
||||
if (_form.doorCheckingChannels && Array.isArray(_form.doorCheckingChannels)) {
|
||||
_form.doorCheckingChannels = _form.doorCheckingChannels.join(',')
|
||||
}
|
||||
if (_form.doorNightAlarmTime && Array.isArray(_form.doorNightAlarmTime)) {
|
||||
_form.doorNightAlarmTime = _form.doorNightAlarmTime.join(',')
|
||||
}
|
||||
await ComDhSettingApi.putObj(_form)
|
||||
useMessage().success('修改成功');
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
getSetting,
|
||||
onSubmit
|
||||
});
|
||||
</script>
|
||||
@@ -4,61 +4,14 @@
|
||||
<el-tabs v-model="state.currentTab" class="demo-tabs" @tab-click="tabClick">
|
||||
<el-tab-pane v-for="(v, i) in data.tabs" :key="v.name" :label="v.label" :name="v.name" />
|
||||
</el-tabs>
|
||||
<div class="flex-1 overflow-hidden mt-4">
|
||||
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="150px"
|
||||
v-loading="state.loading">
|
||||
<el-row :gutter="24">
|
||||
<div class="w-full" v-if="state.currentTab === 'PERSON'">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="人闸报警频次" prop="doorRepeatCount">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>人闸报警频次</span>
|
||||
<el-tooltip class="box-item" :content="`每天进出${form.doorRepeatCount}次就会报警`"
|
||||
placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="form.doorRepeatCount" placeholder="请输入人闸报警频次">
|
||||
<div class="flex items-center gap-1">
|
||||
<span>请输入人闸报警频次</span>
|
||||
<el-tooltip class="box-item" :content="`每天进出${form.doorRepeatCount}次就会报警`"
|
||||
placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<template #append>次</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</div>
|
||||
<div class="w-full" v-if="state.currentTab === 'DOOR'">
|
||||
<el-col :span="24" class="mb20">
|
||||
<el-form-item label="道闸报警频次" prop="carRepeatCount">
|
||||
<template #label>
|
||||
<div class="flex items-center gap-1">
|
||||
<span>道闸报警频次</span>
|
||||
<el-tooltip class="box-item" :content="`每天进出${form.carRepeatCount}次就会报警`"
|
||||
placement="top">
|
||||
<el-icon :size="16">
|
||||
<InfoFilled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
<el-input v-model="form.carRepeatCount" placeholder="请输入道闸报警频次">
|
||||
<template #append>次</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</div>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<div class="flex-1 overflow-y-scroll px-8">
|
||||
<div class="w-full" v-if="state.currentTab === 'PERSON'">
|
||||
<DoorSetting ref="doorSetting" />
|
||||
</div>
|
||||
<div class="w-full" v-if="state.currentTab === 'DOOR'">
|
||||
<CarSetting ref="carSetting" />
|
||||
</div>
|
||||
<div class="h-20" />
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<el-button type="primary" @click="onSubmit">保存配置</el-button>
|
||||
@@ -68,16 +21,11 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="deviceLog">
|
||||
import { useMessage } from "/@/hooks/message";
|
||||
|
||||
import * as ComDhSettingApi from "/@/api/com/comDhSetting";
|
||||
const CarSetting = defineAsyncComponent(() => import('./car/car-setting.vue'));
|
||||
const DoorSetting = defineAsyncComponent(() => import('./door/door-setting.vue'));
|
||||
|
||||
const data = {
|
||||
tabs: [
|
||||
{
|
||||
label: "车速预警配置",
|
||||
name: "CAR_SPEED",
|
||||
},
|
||||
{
|
||||
label: "人员预警配置",
|
||||
name: "PERSON",
|
||||
@@ -89,64 +37,25 @@ const data = {
|
||||
]
|
||||
}
|
||||
|
||||
const doorSetting = ref()
|
||||
const carSetting = ref()
|
||||
|
||||
const state = reactive<any>({
|
||||
currentTab: data.tabs[0].name,
|
||||
loading: false,
|
||||
})
|
||||
|
||||
const dataFormRef = ref();
|
||||
|
||||
// 提交表单数据
|
||||
const form = reactive({
|
||||
// 人闸报警频次
|
||||
doorRepeatCount: null,
|
||||
// 道闸报警频次
|
||||
carRepeatCount: null,
|
||||
})
|
||||
|
||||
// 定义校验规则
|
||||
const dataRules = ref({
|
||||
doorRepeatCount: [{ required: true, message: '人闸报警频次不能为空', trigger: 'blur' }],
|
||||
carRepeatCount: [{ required: true, message: '道闸报警频次不能为空', trigger: 'blur' }],
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getSetting()
|
||||
})
|
||||
|
||||
function tabClick(e: any) {
|
||||
getSetting()
|
||||
console.log("tabClick", e);
|
||||
}
|
||||
|
||||
async function getSetting() {
|
||||
state.loading = true
|
||||
try {
|
||||
const { data } = await ComDhSettingApi.getObj()
|
||||
if (data) {
|
||||
Object.assign(form, data)
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
state.loading = false
|
||||
function onSubmit() {
|
||||
if (state.currentTab == "PERSON") {
|
||||
doorSetting.value.onSubmit()
|
||||
return
|
||||
}
|
||||
if (state.currentTab == "DOOR") {
|
||||
carSetting.value.onSubmit()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
async function onSubmit() {
|
||||
const valid = await dataFormRef.value.validate().catch(() => { });
|
||||
if (!valid) return false;
|
||||
state.loading = true
|
||||
try {
|
||||
const { data } = await ComDhSettingApi.putObj(form)
|
||||
if (data) {
|
||||
Object.assign(form, data)
|
||||
}
|
||||
useMessage().success('修改成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
@@ -35,7 +35,7 @@
|
||||
<el-table-column prop="carOwnerId" min-width="100" label="车主id" />
|
||||
<el-table-column prop="ownerType" min-width="100" label="车辆类型" />
|
||||
</el-table-column>
|
||||
<el-table-column min-width="200" label="报警类型">
|
||||
<el-table-column min-width="210" label="报警类型">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<el-tag v-for="(v, i) in row.alarmList" key="v" type="danger">
|
||||
@@ -84,7 +84,7 @@
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="人员信息">
|
||||
<el-table-column prop="ownerId" width="120" label="人员ID" />
|
||||
<el-table-column prop="ownerName" width="120" label="人员" />
|
||||
<el-table-column prop="ownerCardId" width="120" label="证件号码" />
|
||||
</el-table-column>
|
||||
|
||||
@@ -112,8 +112,8 @@
|
||||
|
||||
<el-table-column label="操作" width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.alarmList && row.alarmList.includes('2')" icon="VideoCamera" text
|
||||
type="primary" @click="replayVideoDialogRef.openDialog('channel', row.devChnId)">
|
||||
<el-button v-if="row.devChnId" icon="VideoCamera" text type="primary"
|
||||
@click="openReplayDialog(row)">
|
||||
回放
|
||||
</el-button>
|
||||
</template>
|
||||
@@ -195,6 +195,19 @@ function getDictByValue(value: any, tag: any) {
|
||||
}
|
||||
}
|
||||
|
||||
function openReplayDialog(row: any) {
|
||||
const dateTime = row.capTime
|
||||
if (!dateTime) return
|
||||
// 获取dateTime前后30秒的时间
|
||||
const baseTime = new Date(dateTime)
|
||||
const startDateTime = new Date(baseTime.getTime() - 30 * 1000)
|
||||
const endDateTime = new Date(baseTime.getTime() + 30 * 1000)
|
||||
|
||||
const startTime = parseTime(startDateTime, '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
const endTime = parseTime(endDateTime, '{y}-{m}-{d} {h}:{i}:{s}')
|
||||
|
||||
replayVideoDialogRef.value.openDialog('channel', row.devChnId, { startTime, endTime })
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -68,7 +68,7 @@
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="人员信息">
|
||||
<el-table-column prop="ownerId" width="120" label="人员ID" />
|
||||
<el-table-column prop="ownerName" width="120" label="人员" />
|
||||
<el-table-column prop="ownerCardId" width="120" label="证件号码" />
|
||||
</el-table-column>
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column label="人员信息">
|
||||
<el-table-column prop="ownerId" width="120" label="人员ID" />
|
||||
<el-table-column prop="ownerName" width="120" label="人员" />
|
||||
<el-table-column prop="ownerCardId" width="120" label="证件号码" />
|
||||
</el-table-column>
|
||||
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<!-- 人员出入次数统计详情 -->
|
||||
<template>
|
||||
<el-dialog title="车辆进去详情" v-model="visible" width="70%" :close-on-click-modal="false" draggable>
|
||||
<el-dialog title="人员进出详情" v-model="visible" width="80%" :close-on-click-modal="false" draggable>
|
||||
<el-row shadow="hover" class="ml10">
|
||||
<el-form-item style="width: 250px;" label="进出门类型" prop="enterOrExit">
|
||||
<dict-select v-model="state.queryForm.enterOrExit" :options="dh_enter_or_exit" placeholder="请选择进出门类型" />
|
||||
@@ -147,8 +147,8 @@ const resetQuery = () => {
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
function openDialog(row: any) {
|
||||
state.queryForm.personCode = row.personCode
|
||||
function openDialog(query: any) {
|
||||
state.queryForm = query
|
||||
visible.value = true
|
||||
getDataList();
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
<dict-select v-model="state.queryForm.enterOrExit" :options="dh_enter_or_exit"
|
||||
placeholder="请选择进出门类型" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="开门类型" prop="openType">
|
||||
<dict-select v-model="state.queryForm.openType" :options="dh_door_open_type"
|
||||
<el-form-item style="width: 250px;" label="报警类型" prop="door_alarm_type">
|
||||
<dict-select v-model="state.queryForm.alarmType" :options="door_alarm_type"
|
||||
placeholder="请选择进开门类型" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 350px;" label="抓拍时间" prop="swingTimeList">
|
||||
@@ -30,7 +30,6 @@
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
|
||||
<el-table-column min-width="200" label="报警类型">
|
||||
<template #default="{ row }">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
@@ -48,7 +47,7 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<el-table-column prop="swingTime" label="触发时间" min-width="180" />
|
||||
<el-table-column min-width="100" label="人员">
|
||||
<el-table-column prop="personCode" min-width="100" label="人员编号">
|
||||
<template #default="{ row }">
|
||||
@@ -112,11 +111,10 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="remark" label="开门失败原因" min-width="200" show-overflow-tooltip />
|
||||
<el-table-column prop="swingTime" label="触发时间" min-width="180" />
|
||||
<el-table-column label="操作" min-width="100" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.alarmList && (row.alarmList.includes('1') || row.alarmList.includes('2'))"
|
||||
icon="VideoCamera" text type="primary" @click="openReplayDialog(row)">
|
||||
<el-button v-if="row.channelCode" icon="VideoCamera" text type="primary"
|
||||
@click="openReplayDialog(row)">
|
||||
回放
|
||||
</el-button>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row shadow="hover" v-show="showSearch" class="ml10">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item style="width: 250px;" label="统计时间" prop="type">
|
||||
<dict-select v-model="state.queryForm.type" :options="tool_time_type" placeholder="请选择统计时间" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="false" @exportExcel="exportExcel"
|
||||
class="ml10 mr20" style="float: right;" @queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border :cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle" @selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle" show-summary :summary-method="getSummaries">
|
||||
<el-table-column type="selection" width="80" align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
<el-table-column min-width="100" label="日期">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.time }}</span>
|
||||
<span> - </span>
|
||||
<span class="color-primary">{{ row.weekStr }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" prop="morningPreCount" align="center" label="上午迟到、早退次数">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success">
|
||||
<span> {{ row.morningPreCount }}</span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" prop="afternoonPreCount" align="center" label="下午迟到、早退次数">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success">
|
||||
<span> {{ row.afternoonPreCount }}</span>
|
||||
<span>人</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" prop="timeCount" align="center" label="迟到、早退次数">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success">
|
||||
<span> {{ row.timeCount }}</span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" prop="preCount" align="center" label="迟到、早退人数">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success">
|
||||
<span> {{ row.preCount }}</span>
|
||||
<span>人</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button icon="InfoFilled" text type="primary" @click="openDoorTableDialogRef(row)">
|
||||
详情
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<door-table-dialog ref="doorTableDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDoorRecord">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import * as doorRecordApi from "/@/api/door/doorRecord";
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// 引入组件
|
||||
const DoorTableDialog = defineAsyncComponent(() => import("../components/doorTableDialog.vue"));
|
||||
|
||||
// 定义查询字典
|
||||
const { tool_time_type } = useDict("tool_time_type")
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const doorTableDialogRef = ref<any>(null)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
isPage: false,
|
||||
queryForm: { type: '3' },
|
||||
pageList: doorRecordApi.beLateCount
|
||||
})
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/door/doorRecord/export', Object.assign(state.queryForm, { ids: selectObjs }), 'doorRecord.xlsx')
|
||||
}
|
||||
|
||||
// 多选事件
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
const getSummaries = (param: any) => {
|
||||
const { columns, data } = param
|
||||
const totalColumns = ["morningPreCount", "afternoonPreCount", "timeCount", "preCount"]
|
||||
const totalRow = Array.from({ length: columns.length })
|
||||
totalRow[0] = "合计"
|
||||
columns.forEach((i: any, index: number) => {
|
||||
if (totalColumns.includes(i.property)) {
|
||||
const total = data
|
||||
.filter((v: any) => v[i.property] != null)
|
||||
.map((v: any) => Number(v[i.property]))
|
||||
.reduce((pren: number, next: number) => pren + next, 0)
|
||||
totalRow[index] = `${total}次`
|
||||
}
|
||||
})
|
||||
return totalRow
|
||||
}
|
||||
|
||||
function openDoorTableDialogRef(row: any) {
|
||||
const query = {
|
||||
swingTimeList: [row.time, addDays(row.time, 1)],
|
||||
openTypeList: ['61', '62'],
|
||||
}
|
||||
doorTableDialogRef.value.openDialog(query)
|
||||
}
|
||||
|
||||
function addDays(dateStr: string, days: number) {
|
||||
const date = new Date(dateStr);
|
||||
date.setDate(date.getDate() + days);
|
||||
return date.toISOString().split('T')[0];
|
||||
};
|
||||
</script>
|
||||
@@ -39,25 +39,25 @@
|
||||
<el-table-column prop="personCode" min-width="100" label="人员编号">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.personCode">{{ row.personCode }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="personName" min-width="100" label="姓名">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.personName">{{ row.personName }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paperNumber" min-width="100" label="证件号码" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.paperNumber">{{ row.paperNumber }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deptName" min-width="100" label="部门名称">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.deptName">{{ row.deptName }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table-column>
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<div class="layout-padding">
|
||||
<div class="layout-padding-auto layout-padding-view">
|
||||
<el-row shadow="hover" v-show="showSearch" class="ml10">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item style="width: 250px;" label="统计时间" prop="type">
|
||||
<dict-select v-model="state.queryForm.type" :options="tool_time_type" placeholder="请选择统计时间" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<right-toolbar v-model:showSearch="showSearch" :export="false" @exportExcel="exportExcel"
|
||||
class="ml10 mr20" style="float: right;" @queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border :cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle" @selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle" show-summary :summary-method="getSummaries">
|
||||
<el-table-column type="selection" width="80" align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
<el-table-column min-width="100" label="日期">
|
||||
<template #default="{ row }">
|
||||
<span>{{ row.time }}</span>
|
||||
<span> - </span>
|
||||
<span class="color-primary">{{ row.weekStr }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column min-width="100" prop="preCount" align="center" label="在位人量">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success">
|
||||
<span> {{ row.preCount }}</span>
|
||||
<span>次</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button icon="InfoFilled" text type="primary" @click="openDoorTableDialogRef(row)">
|
||||
详情
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<door-table-dialog ref="doorTableDialogRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDoorRecord">
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import * as doorRecordApi from "/@/api/door/doorRecord";
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
|
||||
// 引入组件
|
||||
const DoorTableDialog = defineAsyncComponent(() => import("../components/doorTableDialog.vue"));
|
||||
|
||||
// 定义查询字典
|
||||
const { tool_time_type } = useDict("tool_time_type")
|
||||
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
|
||||
const doorTableDialogRef = ref<any>(null)
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
isPage: false,
|
||||
queryForm: { type: '3' },
|
||||
pageList: doorRecordApi.reignCount
|
||||
})
|
||||
|
||||
// table hook
|
||||
const {
|
||||
getDataList,
|
||||
currentChangeHandle,
|
||||
sizeChangeHandle,
|
||||
sortChangeHandle,
|
||||
downBlobFile,
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
queryRef.value?.resetFields()
|
||||
// 清空多选
|
||||
selectObjs.value = []
|
||||
getDataList()
|
||||
}
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
downBlobFile('/door/doorRecord/export', Object.assign(state.queryForm, { ids: selectObjs }), 'doorRecord.xlsx')
|
||||
}
|
||||
|
||||
// 多选事件
|
||||
const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
selectObjs.value = objs.map(({ id }) => id);
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
const getSummaries = (param: any) => {
|
||||
const { columns, data } = param
|
||||
const totalColumns = ["preCount"]
|
||||
const totalRow = Array.from({ length: columns.length })
|
||||
totalRow[0] = "合计"
|
||||
columns.forEach((i: any, index: number) => {
|
||||
if (totalColumns.includes(i.property)) {
|
||||
const total = data
|
||||
.filter((v: any) => v[i.property] != null)
|
||||
.map((v: any) => Number(v[i.property]))
|
||||
.reduce((pren: number, next: number) => pren + next, 0)
|
||||
totalRow[index] = `${total}次`
|
||||
}
|
||||
})
|
||||
return totalRow
|
||||
}
|
||||
|
||||
function openDoorTableDialogRef(row: any) {
|
||||
const query = {
|
||||
swingTimeList: [row.time, addDays(row.time, 1)],
|
||||
openTypeList: ['61', '62'],
|
||||
}
|
||||
doorTableDialogRef.value.openDialog(query)
|
||||
}
|
||||
|
||||
function addDays(dateStr: string, days: number) {
|
||||
const date = new Date(dateStr);
|
||||
date.setDate(date.getDate() + days);
|
||||
return date.toISOString().split('T')[0];
|
||||
};
|
||||
</script>
|
||||
@@ -71,7 +71,7 @@
|
||||
<el-table-column label="操作" width="150" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button icon="InfoFilled" text type="primary"
|
||||
@click="doorTimesTableDialogRef.openDialog(row)">详情</el-button>
|
||||
@click="openDoorTableDialogRef(row)">详情</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -79,7 +79,7 @@
|
||||
v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<door-times-table-dialog ref="doorTimesTableDialogRef" />
|
||||
<door-table-dialog ref="doorTableDialogRef" />
|
||||
|
||||
</div>
|
||||
</template>
|
||||
@@ -91,9 +91,9 @@ import { useDict } from '/@/hooks/dict';
|
||||
import * as DoorRecordApi from "/@/api/door/doorRecord";
|
||||
|
||||
// 引入组件
|
||||
const DoorTimesTableDialog = defineAsyncComponent(() => import("./doorTimesTableDialog.vue"));
|
||||
const DoorTableDialog = defineAsyncComponent(() => import("../components/doorTableDialog.vue"));
|
||||
|
||||
const doorTimesTableDialogRef = ref<any>(null)
|
||||
const doorTableDialogRef = ref<any>(null)
|
||||
|
||||
// 搜索变量
|
||||
const queryRef = ref()
|
||||
@@ -152,6 +152,10 @@ const getSummaries = (param: any) => {
|
||||
return totalRow
|
||||
}
|
||||
|
||||
function openDoorTableDialogRef(row: any) {
|
||||
doorTableDialogRef.value.openDialog({ personCode: row.personCode })
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@@ -3,12 +3,9 @@
|
||||
<!-- 语言切换 -->
|
||||
<el-dropdown v-if="isI18nEnabled" trigger="click" @command="onLanguageChange">
|
||||
<div
|
||||
class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm"
|
||||
>
|
||||
<i
|
||||
class="text-lg text-gray-600 dark:text-slate-300 iconfont"
|
||||
:class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"
|
||||
></i>
|
||||
class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm">
|
||||
<i class="text-lg text-gray-600 dark:text-slate-300 iconfont"
|
||||
:class="state.disabledI18n === 'en' ? 'icon-fuhao-yingwen' : 'icon-fuhao-zhongwen'"></i>
|
||||
</div>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
@@ -20,10 +17,8 @@
|
||||
|
||||
<!-- 主题切换 -->
|
||||
<el-tooltip v-if="isDarkModeEnabled" :content="getThemeConfig.isDark ? '切换亮色模式' : '切换暗色模式'" placement="bottom">
|
||||
<div
|
||||
class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm"
|
||||
@click="onThemeClick"
|
||||
>
|
||||
<div class="flex items-center justify-center transition-colors rounded-lg cursor-pointer w-9 h-9 bg-white/80 dark:bg-slate-800/80 hover:bg-gray-100 dark:hover:bg-slate-700 backdrop-blur-sm"
|
||||
@click="onThemeClick">
|
||||
<el-icon :size="18" class="text-gray-600 dark:text-slate-300">
|
||||
<ele-Moon v-if="!getThemeConfig.isDark" />
|
||||
<ele-Sunny v-else />
|
||||
@@ -66,7 +61,7 @@ const onLanguageChange = (lang: string) => {
|
||||
// 主题切换
|
||||
const onThemeClick = () => {
|
||||
if (!isDarkModeEnabled) return; // 如果未启用暗黑模式,直接返回
|
||||
|
||||
|
||||
const body = document.documentElement as HTMLElement;
|
||||
themeConfig.value.isDark = !themeConfig.value.isDark;
|
||||
|
||||
@@ -91,11 +86,11 @@ const getThemeConfig = computed(() => {
|
||||
// 在 script setup 中添加
|
||||
const initLanguage = () => {
|
||||
if (!isI18nEnabled) return; // 如果未启用多语言,直接返回
|
||||
|
||||
|
||||
if (Local.get('themeConfig')) {
|
||||
state.disabledI18n = Local.get('themeConfig').globalI18n;
|
||||
// 确保 i18n locale 与存储的语言保持一致
|
||||
|
||||
|
||||
locale.value = state.disabledI18n;
|
||||
} else {
|
||||
// 如果没有存储的主题配置,设置默认语言
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
<template>
|
||||
<el-form size="large" class="login-content-form" ref="loginFormRef" :rules="loginRules" :model="state.ruleForm" @keyup.enter="handleVerify">
|
||||
<el-form size="large" class="login-content-form" ref="loginFormRef" :rules="loginRules" :model="state.ruleForm"
|
||||
@keyup.enter="handleVerify">
|
||||
<el-form-item class="login-animation1" prop="username">
|
||||
<el-input
|
||||
text
|
||||
:placeholder="$t('password.accountPlaceholder1')"
|
||||
v-model="state.ruleForm.username"
|
||||
clearable
|
||||
autocomplete="off"
|
||||
class="dark:bg-slate-700 dark:text-slate-200"
|
||||
>
|
||||
<el-input text :placeholder="$t('password.accountPlaceholder1')" v-model="state.ruleForm.username" clearable
|
||||
autocomplete="off" class="dark:bg-slate-700 dark:text-slate-200">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon dark:text-slate-400">
|
||||
<ele-User />
|
||||
@@ -17,31 +12,26 @@
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item class="login-animation2" prop="password">
|
||||
<el-input
|
||||
:type="state.isShowPassword ? 'text' : 'password'"
|
||||
:placeholder="$t('password.accountPlaceholder2')"
|
||||
v-model="state.ruleForm.password"
|
||||
class="dark:bg-slate-700 dark:text-slate-200"
|
||||
autocomplete="off"
|
||||
>
|
||||
<el-input :type="state.isShowPassword ? 'text' : 'password'"
|
||||
:placeholder="$t('password.accountPlaceholder2')" v-model="state.ruleForm.password"
|
||||
class="dark:bg-slate-700 dark:text-slate-200" autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon dark:text-slate-400">
|
||||
<ele-Unlock />
|
||||
</el-icon>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<i
|
||||
class="iconfont el-input__icon login-content-password"
|
||||
<i class="iconfont el-input__icon login-content-password"
|
||||
:class="state.isShowPassword ? 'icon-yincangmima' : 'icon-xianshimima'"
|
||||
@click="state.isShowPassword = !state.isShowPassword"
|
||||
>
|
||||
@click="state.isShowPassword = !state.isShowPassword">
|
||||
</i>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item class="login-animation2" prop="code" v-if="verifyImageEnable">
|
||||
<el-col :span="15">
|
||||
<el-input text maxlength="4" :placeholder="$t('mobile.placeholder2')" v-model="state.ruleForm.code" clearable autocomplete="off">
|
||||
<el-input text maxlength="4" :placeholder="$t('mobile.placeholder2')" v-model="state.ruleForm.code"
|
||||
clearable autocomplete="off">
|
||||
<template #prefix>
|
||||
<el-icon class="el-input__icon">
|
||||
<ele-Position />
|
||||
@@ -55,17 +45,19 @@
|
||||
</el-col>
|
||||
</el-form-item>
|
||||
<el-form-item class="mt-4 login-animation4">
|
||||
<el-button type="primary" class="rounded-lg login-content-submit" v-waves @click="handleVerify" :loading="loading">
|
||||
<el-button type="primary" class="rounded-lg login-content-submit" v-waves @click="handleVerify"
|
||||
:loading="loading">
|
||||
<span class="font-semibold tracking-wide">{{ $t('password.accountBtnText') }}</span>
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
|
||||
<div class="flex relative justify-between items-center">
|
||||
<div v-if="false" class="flex relative justify-between items-center">
|
||||
<div class="ml-auto text-sm">
|
||||
<a href="#" class="text-blue-500" @click="emit('change', LoginTypeEnum.MOBILE)">
|
||||
{{ $t('password.mobileLogin') }}
|
||||
</a>
|
||||
<a href="#" v-if="autoRegisterEnable" class="ml-2 text-blue-500" @click="emit('change', LoginTypeEnum.REGISTER)">
|
||||
<a href="#" v-if="autoRegisterEnable" class="ml-2 text-blue-500"
|
||||
@click="emit('change', LoginTypeEnum.REGISTER)">
|
||||
{{ $t('password.createAccount') }}
|
||||
</a>
|
||||
</div>
|
||||
@@ -73,14 +65,8 @@
|
||||
|
||||
<div class="font12 mt30 login-animation4 login-msg text-slate-400">{{ $t('browserMsgText') }}</div>
|
||||
</el-form>
|
||||
<Verify
|
||||
@success="verifySuccess"
|
||||
:mode="'pop'"
|
||||
:captchaType="'blockPuzzle'"
|
||||
v-if="verifyEnable"
|
||||
:imgSize="{ width: '330px', height: '155px' }"
|
||||
ref="verifyref"
|
||||
/>
|
||||
<Verify @success="verifySuccess" :mode="'pop'" :captchaType="'blockPuzzle'" v-if="verifyEnable"
|
||||
:imgSize="{ width: '330px', height: '155px' }" ref="verifyref" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="password">
|
||||
@@ -105,8 +91,8 @@ const state = reactive({
|
||||
isShowPassword: false, // 是否显示密码
|
||||
ruleForm: {
|
||||
// 表单数据
|
||||
username: 'admin', // 用户名
|
||||
password: '123456', // 密码
|
||||
username: '', // 用户名
|
||||
password: '', // 密码
|
||||
code: '', // 验证码
|
||||
randomStr: 'blockPuzzle', // 验证码随机数
|
||||
},
|
||||
@@ -127,14 +113,13 @@ const imgSrc = ref('');
|
||||
// 调用图形证码进行校验
|
||||
const getVerifyImageCode = () => {
|
||||
state.ruleForm.randomStr = generateUUID();
|
||||
imgSrc.value = `${import.meta.env.VITE_API_URL}${import.meta.env.VITE_IS_MICRO == 'false' ? '/admin' : '/auth'}/code/image?randomStr=${
|
||||
state.ruleForm.randomStr
|
||||
}`;
|
||||
imgSrc.value = `${import.meta.env.VITE_API_URL}${import.meta.env.VITE_IS_MICRO == 'false' ? '/admin' : '/auth'}/code/image?randomStr=${state.ruleForm.randomStr
|
||||
}`;
|
||||
};
|
||||
|
||||
// 调用滑块验证码进行校验
|
||||
const handleVerify = async () => {
|
||||
const valid = await loginFormRef.value.validate().catch(() => {}); // 表单校验
|
||||
const valid = await loginFormRef.value.validate().catch(() => { }); // 表单校验
|
||||
|
||||
if (valid && verifyEnable.value) {
|
||||
verifyref.value.show(); // 显示验证组件
|
||||
|
||||
+16
-17
@@ -3,26 +3,22 @@
|
||||
<!-- 右上角控制组件 -->
|
||||
<Control />
|
||||
|
||||
<div
|
||||
class="w-full overflow-hidden bg-white border border-gray-200 shadow-lg dark:bg-slate-800 rounded-3xl dark:border-slate-700"
|
||||
style="max-width: 1000px"
|
||||
>
|
||||
<div class="w-full overflow-hidden bg-white border border-gray-200 shadow-lg dark:bg-slate-800 rounded-3xl dark:border-slate-700"
|
||||
style="max-width: 1000px">
|
||||
<div class="w-full md:flex">
|
||||
<!-- 左侧插图区域 -->
|
||||
<div
|
||||
class="hidden w-[55%] bg-gradient-to-br from-blue-400 via-blue-300 to-blue-200 dark:from-slate-800 dark:via-slate-700 dark:to-slate-900/95 md:flex md:items-center md:justify-center"
|
||||
>
|
||||
<img
|
||||
class="w-[85%] h-auto max-h-[650px] object-contain opacity-100 dark:opacity-75 transition-opacity duration-300 hover:opacity-90"
|
||||
class="hidden w-[55%] bg-gradient-to-br from-blue-400 via-blue-300 to-blue-200 dark:from-slate-800 dark:via-slate-700 dark:to-slate-900/95 md:flex md:items-center md:justify-center">
|
||||
<img class="w-[85%] h-auto max-h-[650px] object-contain opacity-100 dark:opacity-75 transition-opacity duration-300 hover:opacity-90"
|
||||
:src="!themeConfig.background ? illustration : baseURL + themeConfig.background"
|
||||
alt="Login illustration"
|
||||
/>
|
||||
alt="Login illustration" />
|
||||
</div>
|
||||
|
||||
<!-- 右侧登录表单区域 -->
|
||||
<div class="w-full px-5 py-12 md:w-[45%] md:px-12">
|
||||
<div class="mb-12 text-center">
|
||||
<h1 class="text-4xl font-bold text-gray-900 dark:text-white tracking-wide font-['Inter']">{{ getThemeConfig.globalTitle }}</h1>
|
||||
<h1 class="text-4xl font-bold text-gray-900 dark:text-white tracking-wide font-['Inter']">{{
|
||||
getThemeConfig.globalTitle }}</h1>
|
||||
<!-- 租户选择 -->
|
||||
<div class="mt-6">
|
||||
<tenant class="shadow-sm" />
|
||||
@@ -32,26 +28,29 @@
|
||||
<div class="w-full px-5">
|
||||
<!-- 登录表单组件 -->
|
||||
<register v-if="loginType === LoginTypeEnum.REGISTER" @change="changeLoginType" />
|
||||
<password v-if="loginType === LoginTypeEnum.PASSWORD" @signInSuccess="signInSuccess" @change="changeLoginType" />
|
||||
<mobile v-if="loginType === LoginTypeEnum.MOBILE" @signInSuccess="signInSuccess" @change="changeLoginType" />
|
||||
<expire v-if="loginType === LoginTypeEnum.EXPIRE" :username="username" @change="changeLoginType" />
|
||||
<password v-if="loginType === LoginTypeEnum.PASSWORD" @signInSuccess="signInSuccess"
|
||||
@change="changeLoginType" />
|
||||
<mobile v-if="loginType === LoginTypeEnum.MOBILE" @signInSuccess="signInSuccess"
|
||||
@change="changeLoginType" />
|
||||
<expire v-if="loginType === LoginTypeEnum.EXPIRE" :username="username"
|
||||
@change="changeLoginType" />
|
||||
|
||||
<!-- 分割线 -->
|
||||
<div class="flex items-center justify-center my-6 space-x-3">
|
||||
<div v-if="false" class="flex items-center justify-center my-6 space-x-3">
|
||||
<span class="w-20 h-[1.5px] bg-gray-200 dark:bg-slate-600"></span>
|
||||
<span class="text-gray-600 dark:text-slate-400">{{ $t('divider.or') }}</span>
|
||||
<span class="w-20 h-[1.5px] bg-gray-200 dark:bg-slate-600"></span>
|
||||
</div>
|
||||
|
||||
<!-- 社交登录 -->
|
||||
<social @signInSuccess="signInSuccess" />
|
||||
<social v-if="false" @signInSuccess="signInSuccess" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 小程序二维码 -->
|
||||
<Qrcode />
|
||||
<Qrcode v-if="false" />
|
||||
|
||||
<!-- Footer 组件 -->
|
||||
<Footer />
|
||||
|
||||
@@ -46,28 +46,28 @@
|
||||
:label="columnSetting['personCode'].label">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.personCode">{{ row.personCode }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columnSetting['personName'].visible" prop="personName" min-width="100"
|
||||
:label="columnSetting['personName'].label">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.personName">{{ row.personName }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columnSetting['paperNumber'].visible" prop="paperNumber" min-width="100"
|
||||
:label="columnSetting['paperNumber'].label" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.paperNumber">{{ row.paperNumber }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="columnSetting['deptName'].visible" prop="deptName" min-width="100"
|
||||
:label="columnSetting['deptName'].label">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.deptName">{{ row.deptName }}</span>
|
||||
<span v-else class="color-danger">未知</span>
|
||||
<span v-else class="color-danger">访客</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- end 人员 end -->
|
||||
|
||||
Reference in new issue
Block a user