Merge branch 'lx' of http://xny.yj-3d.com:3000/taoge_xiaodi/maintenance_system into tcy
This commit is contained in:
26
src/api/renyuan/paiban/index.ts
Normal file
26
src/api/renyuan/paiban/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询排班人员列表
|
||||||
|
* @param deptId
|
||||||
|
*/
|
||||||
|
export function getPaibanRenYuanList(deptId:string | number): AxiosPromise<any> {
|
||||||
|
return request({
|
||||||
|
url: `/system/user/list/dept/`+deptId,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询运维-人员排班列表
|
||||||
|
* @param deptId
|
||||||
|
*/
|
||||||
|
export function getPaibanRiLiList(deptId:string | number): AxiosPromise<any> {
|
||||||
|
return request({
|
||||||
|
url: `/ops/personnel/scheduling/getRiLiList/`+deptId,
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
||||||
0
src/api/renyuan/paiban/types.ts
Normal file
0
src/api/renyuan/paiban/types.ts
Normal file
63
src/api/renyuan/schedulingDate/index.ts
Normal file
63
src/api/renyuan/schedulingDate/index.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
import { AxiosPromise } from 'axios';
|
||||||
|
import { SchedulingDateVO, SchedulingDateForm, SchedulingDateQuery } from '@/api/renyuan/schedulingDate/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询运维-排班时间类型列表
|
||||||
|
* @param query
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const listSchedulingDate = (query?: SchedulingDateQuery): AxiosPromise<SchedulingDateVO[]> => {
|
||||||
|
return request({
|
||||||
|
url: '/ops/personnel/schedulingDate/list',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询运维-排班时间类型详细
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getSchedulingDate = (id: string | number): AxiosPromise<SchedulingDateVO> => {
|
||||||
|
return request({
|
||||||
|
url: '/ops/personnel/schedulingDate/' + id,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增运维-排班时间类型
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const addSchedulingDate = (data: SchedulingDateForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/ops/personnel/schedulingDate',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改运维-排班时间类型
|
||||||
|
* @param data
|
||||||
|
*/
|
||||||
|
export const updateSchedulingDate = (data: SchedulingDateForm) => {
|
||||||
|
return request({
|
||||||
|
url: '/ops/personnel/schedulingDate',
|
||||||
|
method: 'put',
|
||||||
|
data: data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除运维-排班时间类型
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const delSchedulingDate = (id: string | number | Array<string | number>) => {
|
||||||
|
return request({
|
||||||
|
url: '/ops/personnel/schedulingDate/' + id,
|
||||||
|
method: 'delete'
|
||||||
|
});
|
||||||
|
};
|
||||||
86
src/api/renyuan/schedulingDate/types.ts
Normal file
86
src/api/renyuan/schedulingDate/types.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
export interface SchedulingDateVO {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
id: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排班名称
|
||||||
|
*/
|
||||||
|
schedulingName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
startTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
endTime: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门ID
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SchedulingDateForm extends BaseEntity {
|
||||||
|
/**
|
||||||
|
* id
|
||||||
|
*/
|
||||||
|
id?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排班名称
|
||||||
|
*/
|
||||||
|
schedulingName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
startTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
endTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门ID
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SchedulingDateQuery extends PageQuery {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排班名称
|
||||||
|
*/
|
||||||
|
schedulingName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
startTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
endTime?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 部门ID
|
||||||
|
*/
|
||||||
|
projectId?: string | number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 日期范围参数
|
||||||
|
*/
|
||||||
|
params?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -20,10 +20,11 @@ export const getMenu = (menuId: string | number): AxiosPromise<MenuVO> => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 查询菜单下拉树结构
|
// 查询菜单下拉树结构
|
||||||
export const treeselect = (): AxiosPromise<MenuTreeOption[]> => {
|
export const treeselect = (params?: any): AxiosPromise<MenuTreeOption[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/menu/treeselect',
|
url: '/system/menu/treeselect',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -147,10 +147,11 @@ export const authUserSelectAll = (data: any) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 根据角色ID查询部门树结构
|
// 根据角色ID查询部门树结构
|
||||||
export const deptTreeSelect = (roleId: string | number): AxiosPromise<RoleDeptTree> => {
|
export const deptTreeSelect = (roleId: string | number, params?) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/role/deptTree/' + roleId,
|
url: '/system/role/deptTree/' + roleId,
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export interface RoleQuery extends PageQuery {
|
|||||||
|
|
||||||
export interface RoleForm {
|
export interface RoleForm {
|
||||||
roleName: string;
|
roleName: string;
|
||||||
|
deptId: string | undefined;
|
||||||
roleKey: string;
|
roleKey: string;
|
||||||
roleSort: number;
|
roleSort: number;
|
||||||
status: string;
|
status: string;
|
||||||
|
|||||||
@ -202,10 +202,11 @@ export const listUserByDeptId = (deptId: string | number): AxiosPromise<UserVO[]
|
|||||||
/**
|
/**
|
||||||
* 查询部门下拉树结构
|
* 查询部门下拉树结构
|
||||||
*/
|
*/
|
||||||
export const deptTreeSelect = (): AxiosPromise<DeptTreeVO[]> => {
|
export const deptTreeSelect = (data?: { isShow: string }): AxiosPromise<DeptTreeVO[]> => {
|
||||||
return request({
|
return request({
|
||||||
url: '/system/user/deptTree',
|
url: '/system/user/deptTree',
|
||||||
method: 'get'
|
method: 'get',
|
||||||
|
params: data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,8 @@ export default {
|
|||||||
responseType: 'blob',
|
responseType: 'blob',
|
||||||
headers: globalHeaders()
|
headers: globalHeaders()
|
||||||
});
|
});
|
||||||
|
console.log('🚀 ~ zip ~ res:', res);
|
||||||
|
|
||||||
const isBlob = blobValidate(res.data);
|
const isBlob = blobValidate(res.data);
|
||||||
if (isBlob) {
|
if (isBlob) {
|
||||||
const blob = new Blob([res.data], { type: 'application/zip' });
|
const blob = new Blob([res.data], { type: 'application/zip' });
|
||||||
|
|||||||
@ -242,7 +242,7 @@ onMounted(() => {
|
|||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 500px;
|
height: 435px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
@ -288,7 +288,7 @@ onMounted(() => {
|
|||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.chart-container {
|
.chart-container {
|
||||||
height: 450px;
|
height: 435px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,269 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 人员排班弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
:model-value="manageAttendDialogVisible"
|
||||||
|
@update:model-value="handleDialogVisibleChange"
|
||||||
|
title="管理考勤"
|
||||||
|
width="500"
|
||||||
|
>
|
||||||
|
<el-form :model="attendForm" label-width="100px">
|
||||||
|
<el-form-item label="选择日期">
|
||||||
|
<el-date-picker
|
||||||
|
v-model="attendForm.date"
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
style="width: 100%;"
|
||||||
|
:disabled-date="(time) => time.getTime() < Date.now() - 8.64e7"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<!-- 动态排班表单 -->
|
||||||
|
<div v-for="(item, index) in attendForm.shifts" :key="index" class="dynamic-shift-item">
|
||||||
|
<el-form-item :label="index === 0 ? '排班设置' : ''" :required="index === 0">
|
||||||
|
<div class="shift-form-row">
|
||||||
|
<!-- 排班类型选择 -->
|
||||||
|
<el-select
|
||||||
|
v-model="item.type"
|
||||||
|
placeholder="请选择排班类型"
|
||||||
|
style="width: 40%; margin-right: 10px;"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="option in availableShiftOptions"
|
||||||
|
:key="option.value"
|
||||||
|
:label="option.label"
|
||||||
|
:value="option.value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 人员选择 -->
|
||||||
|
<el-select
|
||||||
|
v-model="item.personnel"
|
||||||
|
placeholder="请选择人员"
|
||||||
|
style="width: 50%; margin-right: 10px;"
|
||||||
|
multiple
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="person in props.personnelList"
|
||||||
|
:key="person.value"
|
||||||
|
:label="person.label"
|
||||||
|
:value="person.value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
|
||||||
|
<!-- 删除按钮 (仅在不是第一个项目时显示) -->
|
||||||
|
<el-button
|
||||||
|
v-if="index > 0"
|
||||||
|
type="danger"
|
||||||
|
icon="CircleCloseFilled"
|
||||||
|
circle
|
||||||
|
@click="removeShiftItem(index)"
|
||||||
|
></el-button>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 添加排班类型按钮 -->
|
||||||
|
<el-form-item>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
icon="CirclePlusFilled"
|
||||||
|
@click="addShiftItem"
|
||||||
|
:disabled="attendForm.shifts.length >= shiftTypes.length"
|
||||||
|
>
|
||||||
|
添加排班类型
|
||||||
|
</el-button>
|
||||||
|
<div v-if="attendForm.shifts.length > 0" class="form-tip">
|
||||||
|
提示:已添加 {{ attendForm.shifts.length }}/{{ shiftTypes.length }} 种排班类型
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="handleCancel">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleConfirm">
|
||||||
|
确认
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
|
||||||
|
// 定义组件的props
|
||||||
|
const props = defineProps({
|
||||||
|
manageAttendDialogVisible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 排班人员列表数据
|
||||||
|
personnelList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [
|
||||||
|
{ label: '张三', value: '1' },
|
||||||
|
{ label: '李四', value: '2' },
|
||||||
|
{ label: '王五', value: '3' },
|
||||||
|
{ label: '赵六', value: '4' },
|
||||||
|
{ label: '钱七', value: '5' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义组件的emits
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'update:manageAttendDialogVisible': [value: boolean];
|
||||||
|
'confirm': [formData: any];
|
||||||
|
}>();
|
||||||
|
|
||||||
|
// 排班类型列表
|
||||||
|
const shiftTypes = [
|
||||||
|
{ label: '早班', value: '早班' },
|
||||||
|
{ label: '中班', value: '中班' },
|
||||||
|
{ label: '晚班', value: '晚班' },
|
||||||
|
{ label: '休息', value: '休息' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 考勤表单数据
|
||||||
|
const attendForm = ref({
|
||||||
|
date: '',
|
||||||
|
shifts: [
|
||||||
|
{ type: '', personnel: [] }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取可用的排班类型选项(排除已添加的类型)
|
||||||
|
const availableShiftOptions = ref(shiftTypes);
|
||||||
|
|
||||||
|
// 监听排班类型变化,更新可用选项
|
||||||
|
const setupWatchers = () => {
|
||||||
|
attendForm.value.shifts.forEach((item) => {
|
||||||
|
watch(() => item.type, (newType) => {
|
||||||
|
updateAvailableShiftOptions();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化时设置监听器
|
||||||
|
setupWatchers();
|
||||||
|
|
||||||
|
// 更新可用的排班类型选项
|
||||||
|
const updateAvailableShiftOptions = () => {
|
||||||
|
const usedTypes = attendForm.value.shifts
|
||||||
|
.map(item => item.type)
|
||||||
|
.filter(type => type !== '');
|
||||||
|
|
||||||
|
availableShiftOptions.value = shiftTypes.filter(type =>
|
||||||
|
!usedTypes.includes(type.value)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 添加新的排班类型项
|
||||||
|
const addShiftItem = () => {
|
||||||
|
// 检查是否还有可用的排班类型
|
||||||
|
if (attendForm.value.shifts.length < shiftTypes.length) {
|
||||||
|
attendForm.value.shifts.push({ type: '', personnel: [] });
|
||||||
|
|
||||||
|
// 为新添加的项添加监听器
|
||||||
|
const newItem = attendForm.value.shifts[attendForm.value.shifts.length - 1];
|
||||||
|
watch(() => newItem.type, (newType) => {
|
||||||
|
updateAvailableShiftOptions();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 删除排班类型项
|
||||||
|
const removeShiftItem = (index: number) => {
|
||||||
|
if (attendForm.value.shifts.length > 1) {
|
||||||
|
attendForm.value.shifts.splice(index, 1);
|
||||||
|
updateAvailableShiftOptions();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理取消
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('update:manageAttendDialogVisible', false);
|
||||||
|
resetForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理弹窗可见性变化
|
||||||
|
const handleDialogVisibleChange = (newVisible: boolean) => {
|
||||||
|
emit('update:manageAttendDialogVisible', newVisible);
|
||||||
|
if (!newVisible) {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理确认
|
||||||
|
const handleConfirm = () => {
|
||||||
|
// 提交表单数据给父组件
|
||||||
|
emit('confirm', attendForm.value);
|
||||||
|
emit('update:manageAttendDialogVisible', false);
|
||||||
|
resetForm();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const resetForm = () => {
|
||||||
|
attendForm.value = {
|
||||||
|
date: '',
|
||||||
|
shifts: [
|
||||||
|
{ type: '', personnel: [] }
|
||||||
|
]
|
||||||
|
};
|
||||||
|
updateAvailableShiftOptions();
|
||||||
|
// 重新设置监听器
|
||||||
|
setupWatchers();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听弹窗显示状态变化,在显示时重置表单
|
||||||
|
watch(() => props.manageAttendDialogVisible, (newVisible) => {
|
||||||
|
if (newVisible) {
|
||||||
|
resetForm();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
/* 动态排班表单样式 */
|
||||||
|
.dynamic-shift-item {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shift-form-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-tip {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 8px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式调整 */
|
||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.shift-form-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shift-form-row .el-select {
|
||||||
|
width: 100% !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shift-form-row .el-button {
|
||||||
|
align-self: flex-start;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -26,14 +26,40 @@
|
|||||||
<div class="week-day">{{ dateInfo.weekDay }}</div>
|
<div class="week-day">{{ dateInfo.weekDay }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template #default="scope">
|
||||||
|
<div
|
||||||
|
class="schedule-cell"
|
||||||
|
:style="{ color: getShiftColor(scope.row[`day${index + 1}`]) }"
|
||||||
|
@click="handleCellClick(scope.row, {...dateInfo, index}, scope)"
|
||||||
|
>
|
||||||
|
{{ scope.row[`day${index + 1}`] }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
<!-- 分页组件 -->
|
||||||
|
<div class="pagination-container">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:page-sizes="[10, 20, 50, 100]"
|
||||||
|
layout="total, sizes, prev, pager, next, jumper"
|
||||||
|
:total="total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed, onMounted } from 'vue';
|
import { ref, computed, onMounted } from 'vue';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
'edit-schedule': [rowData: any, columnData: any, cellEvent: any]
|
||||||
|
}>();
|
||||||
|
|
||||||
// 员工列表
|
// 员工列表
|
||||||
const employees = [
|
const employees = [
|
||||||
{ name: '张三', position: '水泥工', weeklyHours: 142 },
|
{ name: '张三', position: '水泥工', weeklyHours: 142 },
|
||||||
@ -51,6 +77,19 @@ const employees = [
|
|||||||
// 排班类型
|
// 排班类型
|
||||||
const shifts = ['早班', '中班', '晚班', '休息'];
|
const shifts = ['早班', '中班', '晚班', '休息'];
|
||||||
|
|
||||||
|
// 排班类型与颜色的映射关系
|
||||||
|
const shiftColorMap = {
|
||||||
|
'早班': '#67c23a', // 绿色
|
||||||
|
'中班': '#e6a23c', // 橙色
|
||||||
|
'晚班': '#409eff', // 蓝色
|
||||||
|
'休息': '#909399' // 灰色
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据排班类型获取对应的颜色
|
||||||
|
const getShiftColor = (shiftType: string) => {
|
||||||
|
return shiftColorMap[shiftType as keyof typeof shiftColorMap] || '#333';
|
||||||
|
};
|
||||||
|
|
||||||
// 获取当前月的日期信息
|
// 获取当前月的日期信息
|
||||||
const currentMonthDates = ref<any[]>([]);
|
const currentMonthDates = ref<any[]>([]);
|
||||||
|
|
||||||
@ -84,9 +123,17 @@ const getCurrentMonthDates = () => {
|
|||||||
return dates;
|
return dates;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 分页相关状态
|
||||||
|
const currentPage = ref(1);
|
||||||
|
const pageSize = ref(10);
|
||||||
|
const total = ref(50); // 总数据条数,模拟数据
|
||||||
|
|
||||||
// 生成排班数据
|
// 生成排班数据
|
||||||
const scheduleData = computed(() => {
|
const scheduleData = computed(() => {
|
||||||
return Array.from({ length: 20 }, (_, index) => {
|
const startIndex = (currentPage.value - 1) * pageSize.value;
|
||||||
|
const endIndex = startIndex + pageSize.value;
|
||||||
|
|
||||||
|
return Array.from({ length: total.value }, (_, index) => {
|
||||||
// 循环使用员工数据
|
// 循环使用员工数据
|
||||||
const employee = employees[index % employees.length];
|
const employee = employees[index % employees.length];
|
||||||
|
|
||||||
@ -105,13 +152,29 @@ const scheduleData = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return rowData;
|
return rowData;
|
||||||
});
|
}).slice(startIndex, endIndex);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 分页大小变化处理
|
||||||
|
const handleSizeChange = (size: number) => {
|
||||||
|
pageSize.value = size;
|
||||||
|
currentPage.value = 1; // 重置为第一页
|
||||||
|
};
|
||||||
|
|
||||||
|
// 当前页码变化处理
|
||||||
|
const handleCurrentChange = (current: number) => {
|
||||||
|
currentPage.value = current;
|
||||||
|
};
|
||||||
|
|
||||||
// 组件挂载时获取当前月数据
|
// 组件挂载时获取当前月数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
currentMonthDates.value = getCurrentMonthDates();
|
currentMonthDates.value = getCurrentMonthDates();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 处理单元格点击事件
|
||||||
|
const handleCellClick = (rowData: any, columnData: any, cellEvent: any) => {
|
||||||
|
emit('edit-schedule', rowData, columnData, cellEvent);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -165,6 +228,18 @@ onMounted(() => {
|
|||||||
padding: 8px 0;
|
padding: 8px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 排班单元格样式 */
|
||||||
|
.schedule-cell {
|
||||||
|
padding: 8px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schedule-cell:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
transform: scale(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
.date-number {
|
.date-number {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
@ -173,7 +248,20 @@ onMounted(() => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.week-day {
|
.week-day {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 分页容器样式 */
|
||||||
|
.pagination-container {
|
||||||
|
margin-top: 16px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 分页组件样式优化 */
|
||||||
|
:deep(.el-pagination) {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- 考勤管理 -->
|
||||||
<div class="model">
|
<div class="model">
|
||||||
<!-- 标题栏 -->
|
<!-- 标题栏 -->
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
@ -38,19 +39,24 @@
|
|||||||
<infoBox></infoBox>
|
<infoBox></infoBox>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 第二行:人员排班和出勤趋势分析 -->
|
<!-- 第二行:人员排班和出勤趋势分析 -->
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="17">
|
<el-col :span="17">
|
||||||
<div class="analysis-content">
|
<div class="analysis-content">
|
||||||
<attendTrend :attendData="attendData"></attendTrend>
|
<attendTrend :attendData="attendData"></attendTrend>
|
||||||
<el-card>
|
<el-card>
|
||||||
<TitleComponent title="人员排班" :fontLevel="2" />
|
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||||
<renyuanpaiban></renyuanpaiban>
|
<TitleComponent title="人员排班" :fontLevel="2" />
|
||||||
|
<el-button type="primary" @click="manageAttendDialogVisible = true">
|
||||||
|
管理考勤
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<renyuanpaiban @edit-schedule="handleEditSchedule"></renyuanpaiban>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<!-- 右侧日历卡片 -->
|
<!-- 右侧日历卡片 -->
|
||||||
<el-col :span="7">
|
<el-col :span="7">
|
||||||
<div class="calendar-content">
|
<div class="calendar-content">
|
||||||
@ -62,17 +68,149 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<!-- 人员排班弹窗组件 -->
|
||||||
|
<renyuanguanliDialog
|
||||||
|
v-model:manageAttendDialogVisible="manageAttendDialogVisible"
|
||||||
|
@confirm="handleAttendConfirm"
|
||||||
|
:personnel-list="paibanRenYuanList"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- 编辑排班弹窗 -->
|
||||||
|
<el-dialog v-model="editScheduleDialogVisible" title="修改排班" width="400">
|
||||||
|
<el-form :model="editScheduleForm" label-width="100px">
|
||||||
|
<el-form-item label="员工姓名">
|
||||||
|
<el-input v-model="editScheduleForm.name" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="排班日期">
|
||||||
|
<el-input v-model="editScheduleForm.date" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="当前排班">
|
||||||
|
<el-input v-model="editScheduleForm.currentShift" disabled />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="修改为">
|
||||||
|
<el-select v-model="editScheduleForm.newShift" placeholder="请选择排班类型" style="width: 100%;">
|
||||||
|
<el-option v-for="option in shiftOptions" :key="option.value" :label="option.label" :value="option.value"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="editScheduleDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="handleConfirmEditSchedule">
|
||||||
|
确认修改
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import infoBox from '@/views/integratedManage/attendManage/components/infoBox.vue'
|
import infoBox from '@/views/integratedManage/attendManage/components/infoBox.vue'
|
||||||
import attendTrend from '@/views/integratedManage/attendManage/components/attendTrend.vue'
|
import attendTrend from '@/views/integratedManage/attendManage/components/attendTrend.vue'
|
||||||
import todayAttend from '@/views/integratedManage/attendManage/components/leftBox/todayAttend.vue'
|
import todayAttend from '@/views/integratedManage/attendManage/components/rightBox/todayAttend.vue'
|
||||||
import approval from '@/views/integratedManage/attendManage/components/leftBox/approval.vue'
|
import approval from '@/views/integratedManage/attendManage/components/rightBox/approval.vue'
|
||||||
import calendar from '@/views/integratedManage/attendManage/components/leftBox/calendar.vue'
|
import calendar from '@/views/integratedManage/attendManage/components/rightBox/calendar.vue'
|
||||||
import totalView from '@/views/integratedManage/attendManage/components/totalView.vue'
|
import totalView from '@/views/integratedManage/attendManage/components/totalView.vue'
|
||||||
import renyuanpaiban from '@/views/integratedManage/attendManage/components/renyuanpaiban.vue'
|
import renyuanpaiban from '@/views/integratedManage/attendManage/components/renyuanpaiban.vue'
|
||||||
import { ref } from 'vue';
|
import renyuanguanliDialog from '@/views/integratedManage/attendManage/components/renyuanguanliDialog.vue'
|
||||||
|
import { getPaibanRenYuanList } from '@/api/renyuan/paiban';
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
// 导入用户store
|
||||||
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
|
||||||
|
// 排班人员列表
|
||||||
|
const paibanRenYuanList = ref([]);
|
||||||
|
|
||||||
|
// 获取排班人员列表
|
||||||
|
const fetchPaibanRenYuanList = async (deptId?: string) => {
|
||||||
|
try {
|
||||||
|
// 如果没有提供deptId,默认使用当前登录用户的部门ID
|
||||||
|
const targetDeptId = deptId || userStore.deptId;
|
||||||
|
if (!targetDeptId) {
|
||||||
|
console.warn('未提供部门ID,无法获取排班人员列表');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const response = await getPaibanRenYuanList(targetDeptId);
|
||||||
|
// 格式化人员列表数据,确保每个人员对象包含label和value属性
|
||||||
|
paibanRenYuanList.value = response.data?.map((user: any) => ({
|
||||||
|
label: user.nickName || user.userName || '未知用户',
|
||||||
|
value: user.userId || user.id || ''
|
||||||
|
})) || [];
|
||||||
|
|
||||||
|
console.log('获取排班人员列表成功:', paibanRenYuanList.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取排班人员列表失败:', error);
|
||||||
|
// 错误情况下提供模拟数据,确保功能可用
|
||||||
|
paibanRenYuanList.value = [
|
||||||
|
{ label: '张三', value: '1' },
|
||||||
|
{ label: '李四', value: '2' },
|
||||||
|
{ label: '王五', value: '3' },
|
||||||
|
{ label: '赵六', value: '4' },
|
||||||
|
{ label: '钱七', value: '5' }
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 人员排班弹窗
|
||||||
|
const manageAttendDialogVisible = ref(false);
|
||||||
|
|
||||||
|
// 处理考勤管理确认
|
||||||
|
const handleAttendConfirm = (formData: any) => {
|
||||||
|
console.log('考勤表单数据:', formData);
|
||||||
|
// 这里可以添加表单提交逻辑
|
||||||
|
};
|
||||||
|
|
||||||
|
// 编辑排班弹窗
|
||||||
|
const editScheduleDialogVisible = ref(false);
|
||||||
|
|
||||||
|
// 编辑排班表单数据
|
||||||
|
const editScheduleForm = ref({
|
||||||
|
name: '',
|
||||||
|
date: '',
|
||||||
|
currentShift: '',
|
||||||
|
newShift: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// 排班类型选项
|
||||||
|
const shiftOptions = [
|
||||||
|
{ label: '早班', value: '早班' },
|
||||||
|
{ label: '中班', value: '中班' },
|
||||||
|
{ label: '晚班', value: '晚班' },
|
||||||
|
{ label: '休息', value: '休息' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// 处理编辑排班
|
||||||
|
const handleEditSchedule = (rowData: any, columnData: any) => {
|
||||||
|
// 设置表单数据
|
||||||
|
editScheduleForm.value = {
|
||||||
|
name: rowData.name,
|
||||||
|
date: `${columnData.fullDate}`,
|
||||||
|
currentShift: '',
|
||||||
|
newShift: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
// 查找当前排班
|
||||||
|
Object.keys(rowData).forEach(key => {
|
||||||
|
if (key.startsWith('day')) {
|
||||||
|
const dayIndex = parseInt(key.replace('day', '')) - 1;
|
||||||
|
if (dayIndex === columnData.index) {
|
||||||
|
editScheduleForm.value.currentShift = rowData[key];
|
||||||
|
editScheduleForm.value.newShift = rowData[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 显示弹窗
|
||||||
|
editScheduleDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认修改排班
|
||||||
|
const handleConfirmEditSchedule = () => {
|
||||||
|
console.log('修改排班数据:', editScheduleForm.value);
|
||||||
|
// 这里可以添加修改排班的逻辑
|
||||||
|
editScheduleDialogVisible.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
// 出勤数据 - 用于attendTrend组件
|
// 出勤数据 - 用于attendTrend组件
|
||||||
const attendData = ref(
|
const attendData = ref(
|
||||||
@ -92,46 +230,46 @@ const attendData = ref(
|
|||||||
|
|
||||||
// Mock数据 - 更新为循环生成所需的数据结构
|
// Mock数据 - 更新为循环生成所需的数据结构
|
||||||
const totalData = ref({
|
const totalData = ref({
|
||||||
attendance: {
|
attendance: {
|
||||||
value: 248,
|
value: 248,
|
||||||
change: '+8.2%',
|
change: '+8.2%',
|
||||||
isPositive: true,
|
isPositive: true,
|
||||||
chartData: [150, 230, 224, 218, 135, 300, 220],
|
chartData: [150, 230, 224, 218, 135, 300, 220],
|
||||||
color: '#FF7D00',
|
color: '#FF7D00',
|
||||||
title: '总出勤人数',
|
title: '总出勤人数',
|
||||||
compareText: '较昨日同期',
|
compareText: '较昨日同期',
|
||||||
chartType: 'bar'
|
chartType: 'bar'
|
||||||
},
|
},
|
||||||
rest: {
|
rest: {
|
||||||
value: 8,
|
value: 8,
|
||||||
change: '+8.2%',
|
change: '+8.2%',
|
||||||
isPositive: true,
|
isPositive: true,
|
||||||
chartData: [10, 12, 15, 8, 7, 9, 10],
|
chartData: [10, 12, 15, 8, 7, 9, 10],
|
||||||
color: '#00C48C',
|
color: '#00C48C',
|
||||||
title: '调休',
|
title: '调休',
|
||||||
compareText: '较上月同期',
|
compareText: '较上月同期',
|
||||||
chartType: 'line'
|
chartType: 'line'
|
||||||
},
|
},
|
||||||
leave: {
|
leave: {
|
||||||
value: 24,
|
value: 24,
|
||||||
change: '-10%',
|
change: '-10%',
|
||||||
isPositive: false,
|
isPositive: false,
|
||||||
chartData: [30, 25, 28, 22, 20, 26, 24],
|
chartData: [30, 25, 28, 22, 20, 26, 24],
|
||||||
color: '#FF5252',
|
color: '#FF5252',
|
||||||
title: '本月请假',
|
title: '本月请假',
|
||||||
compareText: '较昨日同期',
|
compareText: '较昨日同期',
|
||||||
chartType: 'line'
|
chartType: 'line'
|
||||||
},
|
},
|
||||||
rate: {
|
rate: {
|
||||||
value: '96.8%',
|
value: '96.8%',
|
||||||
change: '+10%',
|
change: '+10%',
|
||||||
isPositive: true,
|
isPositive: true,
|
||||||
chartData: [90, 92, 94, 95, 97, 98, 96.8],
|
chartData: [90, 92, 94, 95, 97, 98, 96.8],
|
||||||
color: '#029CD4',
|
color: '#029CD4',
|
||||||
title: '平均出勤率',
|
title: '平均出勤率',
|
||||||
compareText: '较昨日同期',
|
compareText: '较昨日同期',
|
||||||
chartType: 'line'
|
chartType: 'line'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 审批数据 - 用于approval组件
|
// 审批数据 - 用于approval组件
|
||||||
@ -185,47 +323,56 @@ const approvalData = ref([
|
|||||||
|
|
||||||
// 今日出勤数据 - 用于todayAttend组件
|
// 今日出勤数据 - 用于todayAttend组件
|
||||||
const todayAttendData = ref({
|
const todayAttendData = ref({
|
||||||
attendance: {
|
attendance: {
|
||||||
count: 150,
|
count: 150,
|
||||||
icon: '/src/assets/demo/qin.png'
|
icon: '/src/assets/demo/qin.png'
|
||||||
},
|
},
|
||||||
late: {
|
late: {
|
||||||
count: 5,
|
count: 5,
|
||||||
icon: '/src/assets/demo/chi.png'
|
icon: '/src/assets/demo/chi.png'
|
||||||
},
|
},
|
||||||
earlyLeave: {
|
earlyLeave: {
|
||||||
count: 2,
|
count: 2,
|
||||||
icon: '/src/assets/demo/tui.png'
|
icon: '/src/assets/demo/tui.png'
|
||||||
},
|
},
|
||||||
absent: {
|
absent: {
|
||||||
count: 8,
|
count: 8,
|
||||||
icon: '/src/assets/demo/que.png'
|
icon: '/src/assets/demo/que.png'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 日历数据 - 用于calendar组件
|
// 日历数据 - 用于calendar组件
|
||||||
const calendarData = ref({
|
const calendarData = ref({
|
||||||
// 初始化当前日期
|
// 初始化当前日期
|
||||||
today: new Date(),
|
today: new Date(),
|
||||||
currentDate: new Date(2025, 8, 27), // 2025年9月27日,截图中显示的日期
|
currentDate: new Date(2025, 8, 27), // 2025年9月27日,截图中显示的日期
|
||||||
selectedDate: new Date(2025, 8, 27),
|
selectedDate: new Date(2025, 8, 27),
|
||||||
|
|
||||||
// 模拟考勤数据
|
// 模拟考勤数据
|
||||||
attendanceData: {
|
attendanceData: {
|
||||||
2025: {
|
2025: {
|
||||||
9: {
|
9: {
|
||||||
1: 'normal',
|
1: 'normal',
|
||||||
4: 'late',
|
4: 'late',
|
||||||
8: 'absent',
|
8: 'absent',
|
||||||
10: 'leave',
|
10: 'leave',
|
||||||
15: 'normal',
|
15: 'normal',
|
||||||
20: 'normal',
|
20: 'normal',
|
||||||
25: 'late',
|
25: 'late',
|
||||||
27: 'normal'
|
27: 'normal'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// 初始化用户store
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchPaibanRenYuanList(String(userStore.deptId));
|
||||||
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -260,11 +407,11 @@ const calendarData = ref({
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-content .el-card > * {
|
.calendar-content .el-card>* {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.calendar-content .el-card > *:last-child {
|
.calendar-content .el-card>*:last-child {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
@ -300,9 +447,9 @@ const calendarData = ref({
|
|||||||
.analysis-content {
|
.analysis-content {
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 日历卡片内组件间距 */
|
/* 日历卡片内组件间距 */
|
||||||
.calendar-content .el-card > * {
|
.calendar-content .el-card>* {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
274
src/views/integratedManage/paibanTimeType.vue
Normal file
274
src/views/integratedManage/paibanTimeType.vue
Normal file
@ -0,0 +1,274 @@
|
|||||||
|
<template>
|
||||||
|
<div class="p-2">
|
||||||
|
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
|
||||||
|
<div v-show="showSearch" class="mb-[10px]">
|
||||||
|
<el-card shadow="hover">
|
||||||
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
||||||
|
<el-form-item label="排班名称" prop="schedulingName">
|
||||||
|
<el-input v-model="queryParams.schedulingName" placeholder="请输入排班名称" clearable @keyup.enter="handleQuery" />
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
||||||
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<el-card shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<el-row :gutter="10" class="mb8">
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['personnel:schedulingDate:add']">新增</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['personnel:schedulingDate:edit']">修改</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['personnel:schedulingDate:remove']">删除</el-button>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-table v-loading="loading" border :data="schedulingDateList" @selection-change="handleSelectionChange">
|
||||||
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
|
<el-table-column label="排班名称" align="center" prop="schedulingName" />
|
||||||
|
<el-table-column label="开始时间" align="center" prop="startTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{scope.row.startTime}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="结束时间" align="center" prop="endTime" width="180">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ scope.row.endTime}}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tooltip content="修改" placement="top">
|
||||||
|
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['personnel:schedulingDate:edit']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
<el-tooltip content="删除" placement="top">
|
||||||
|
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['personnel:schedulingDate:remove']"></el-button>
|
||||||
|
</el-tooltip>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
|
||||||
|
</el-card>
|
||||||
|
<!-- 添加或修改运维-排班时间类型对话框 -->
|
||||||
|
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
|
||||||
|
<el-form ref="schedulingDateFormRef" :model="form" :rules="rules" label-width="80px">
|
||||||
|
<el-form-item label="排班名称" prop="schedulingName">
|
||||||
|
<el-input v-model="form.schedulingName" placeholder="请输入排班名称" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="开始时间" prop="startTime">
|
||||||
|
<el-time-select clearable
|
||||||
|
v-model="form.startTime"
|
||||||
|
value-format="HH:mm:ss"
|
||||||
|
step="00:10:00"
|
||||||
|
start="00:00"
|
||||||
|
end="23:59"
|
||||||
|
placeholder="请选择开始时间">
|
||||||
|
</el-time-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="结束时间" prop="endTime">
|
||||||
|
<el-time-select clearable
|
||||||
|
v-model="form.endTime"
|
||||||
|
value-format="HH:mm:ss"
|
||||||
|
step="00:10:00"
|
||||||
|
start="00:00"
|
||||||
|
end="23:59"
|
||||||
|
placeholder="请选择结束时间">
|
||||||
|
</el-time-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button :loading="buttonLoading" type="primary" @click="submitForm">确 定</el-button>
|
||||||
|
<el-button @click="cancel">取 消</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup name="SchedulingDate" lang="ts">
|
||||||
|
import { ref, reactive, toRefs, onMounted, onUnmounted, watch, getCurrentInstance } from 'vue';
|
||||||
|
import { listSchedulingDate, getSchedulingDate, delSchedulingDate, addSchedulingDate, updateSchedulingDate } from '@/api/renyuan/schedulingDate';
|
||||||
|
import { SchedulingDateVO, SchedulingDateQuery, SchedulingDateForm } from '@/api/renyuan/schedulingDate/types';
|
||||||
|
// 导入用户store
|
||||||
|
import { useUserStore } from '@/store/modules/user';
|
||||||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
|
// 获取用户store
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
|
const schedulingDateList = ref<SchedulingDateVO[]>([]);
|
||||||
|
const buttonLoading = ref(false);
|
||||||
|
const loading = ref(true);
|
||||||
|
const showSearch = ref(true);
|
||||||
|
const ids = ref<Array<string | number>>([]);
|
||||||
|
const single = ref(true);
|
||||||
|
const multiple = ref(true);
|
||||||
|
const total = ref(0);
|
||||||
|
|
||||||
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
|
const schedulingDateFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const dialog = reactive<DialogOption>({
|
||||||
|
visible: false,
|
||||||
|
title: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
const initFormData: SchedulingDateForm = {
|
||||||
|
id: undefined,
|
||||||
|
schedulingName: undefined,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined,
|
||||||
|
projectId: undefined,
|
||||||
|
}
|
||||||
|
const data = reactive<PageData<SchedulingDateForm, SchedulingDateQuery>>({
|
||||||
|
form: {...initFormData},
|
||||||
|
queryParams: {
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
schedulingName: undefined,
|
||||||
|
startTime: undefined,
|
||||||
|
endTime: undefined,
|
||||||
|
projectId: undefined,
|
||||||
|
params: {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
schedulingName: [
|
||||||
|
{ required: true, message: "排班名称不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
startTime: [
|
||||||
|
{ required: true, message: "开始时间不能为空", trigger: "blur" }
|
||||||
|
],
|
||||||
|
endTime: [
|
||||||
|
{ required: true, message: "结束时间不能为空", trigger: "blur" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { queryParams, form, rules } = toRefs(data);
|
||||||
|
|
||||||
|
/** 查询运维-排班时间类型列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await listSchedulingDate(queryParams.value);
|
||||||
|
schedulingDateList.value = res.rows;
|
||||||
|
total.value = res.total;
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 取消按钮 */
|
||||||
|
const cancel = () => {
|
||||||
|
reset();
|
||||||
|
dialog.visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 表单重置 */
|
||||||
|
const reset = () => {
|
||||||
|
form.value = {...initFormData};
|
||||||
|
schedulingDateFormRef.value?.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 搜索按钮操作 */
|
||||||
|
const handleQuery = () => {
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 重置按钮操作 */
|
||||||
|
const resetQuery = () => {
|
||||||
|
queryFormRef.value?.resetFields();
|
||||||
|
handleQuery();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 多选框选中数据 */
|
||||||
|
const handleSelectionChange = (selection: SchedulingDateVO[]) => {
|
||||||
|
ids.value = selection.map(item => item.id);
|
||||||
|
single.value = selection.length != 1;
|
||||||
|
multiple.value = !selection.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 新增按钮操作 */
|
||||||
|
const handleAdd = () => {
|
||||||
|
reset();
|
||||||
|
// 显式设置projectId为当前选中的项目ID
|
||||||
|
if (userStore.selectedProject && userStore.selectedProject.id) {
|
||||||
|
form.value.projectId = userStore.selectedProject.id;
|
||||||
|
}
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = "添加运维-排班时间类型";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 修改按钮操作 */
|
||||||
|
const handleUpdate = async (row?: SchedulingDateVO) => {
|
||||||
|
reset();
|
||||||
|
const _id = row?.id || ids.value[0]
|
||||||
|
const res = await getSchedulingDate(_id);
|
||||||
|
Object.assign(form.value, res.data);
|
||||||
|
dialog.visible = true;
|
||||||
|
dialog.title = "修改运维-排班时间类型";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 提交按钮 */
|
||||||
|
const submitForm = () => {
|
||||||
|
schedulingDateFormRef.value?.validate(async (valid: boolean) => {
|
||||||
|
if (valid) {
|
||||||
|
buttonLoading.value = true;
|
||||||
|
if (form.value.id) {
|
||||||
|
await updateSchedulingDate(form.value).finally(() => buttonLoading.value = false);
|
||||||
|
} else {
|
||||||
|
await addSchedulingDate(form.value).finally(() => buttonLoading.value = false);
|
||||||
|
}
|
||||||
|
proxy?.$modal.msgSuccess("操作成功");
|
||||||
|
dialog.visible = false;
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 删除按钮操作 */
|
||||||
|
const handleDelete = async (row?: SchedulingDateVO) => {
|
||||||
|
const _ids = row?.id || ids.value;
|
||||||
|
await proxy?.$modal.confirm('是否确认删除运维-排班时间类型编号为"' + _ids + '"的数据项?').finally(() => loading.value = false);
|
||||||
|
await delSchedulingDate(_ids);
|
||||||
|
proxy?.$modal.msgSuccess("删除成功");
|
||||||
|
await getList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 监听用户选择的项目变化
|
||||||
|
watch(() => userStore.selectedProject, (newProject) => {
|
||||||
|
if (newProject && newProject.id) {
|
||||||
|
queryParams.value.projectId = newProject.id;
|
||||||
|
// 只在新增表单时设置projectId,编辑表单保留原有值
|
||||||
|
if (!form.value.id) {
|
||||||
|
form.value.projectId = newProject.id;
|
||||||
|
}
|
||||||
|
// 调用getList刷新数据
|
||||||
|
getList();
|
||||||
|
}
|
||||||
|
}, { immediate: true, deep: true });
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getList();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 组件卸载时清空projectId
|
||||||
|
onUnmounted(() => {
|
||||||
|
queryParams.value.projectId = undefined;
|
||||||
|
form.value.projectId = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
||||||
@ -1,7 +1,6 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<!--组件温度(℃) 图表内容区域 -->
|
|
||||||
<div ref="chartRef" class="chart-content"></div>
|
<div ref="chartRef" class="chart-content"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -9,64 +9,17 @@
|
|||||||
<span class="update-time">截止至2025/06/30 12:00</span>
|
<span class="update-time">截止至2025/06/30 12:00</span>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
|
||||||
<!-- 关键指标卡片区域 -->
|
<!-- 关键指标卡片区域 -->
|
||||||
<el-row class="metrics-container" :gutter="0">
|
<el-row class="metrics-container" :gutter="0">
|
||||||
<el-col :span="6">
|
<el-col v-for="card in cardData" :key="card.key" :span="6">
|
||||||
<div class="metric-card">
|
<div class="metric-card">
|
||||||
<div class="metric-value">{{ props.dashboardData.todayAlarmTotal }}</div>
|
<div class="metric-value">{{ props.dashboardData[card.key] }}</div>
|
||||||
<div class="metric-label">今日报警总数</div>
|
<div class="metric-label">{{ card.label }}</div>
|
||||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.todayAlarmTotal.type">
|
<div class="metric-change">较上周 <span :class="props.dashboardData.updates[card.updateKey].type">
|
||||||
<img v-if="props.dashboardData.updates.todayAlarmTotal.type === 'up'" src="/src/assets/demo/up.png"
|
<img v-if="props.dashboardData.updates[card.updateKey].type === 'up'" src="/src/assets/demo/up.png"
|
||||||
class="trend-icon" alt="上升">
|
class="trend-icon" alt="上升">
|
||||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
||||||
props.dashboardData.updates.todayAlarmTotal.value }}
|
props.dashboardData.updates[card.updateKey].value }}
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
|
|
||||||
<el-col :span="6">
|
|
||||||
<div class="metric-card">
|
|
||||||
<div class="metric-value">{{ props.dashboardData.unhandledAlarms }}</div>
|
|
||||||
<div class="metric-label">未处理报警</div>
|
|
||||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.unhandledAlarms.type">
|
|
||||||
<img v-if="props.dashboardData.updates.unhandledAlarms.type === 'up'" src="/src/assets/demo/up.png"
|
|
||||||
class="trend-icon" alt="上升">
|
|
||||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
|
||||||
props.dashboardData.updates.unhandledAlarms.value }}
|
|
||||||
</span></div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
|
|
||||||
<el-col :span="6">
|
|
||||||
<div class="metric-card">
|
|
||||||
<div class="metric-value">{{ props.dashboardData.handledAlarms }}</div>
|
|
||||||
<div class="metric-label">已处理报警</div>
|
|
||||||
<div class="metric-change">较上周 <span :class="props.dashboardData.updates.handledAlarms.type">
|
|
||||||
<img v-if="props.dashboardData.updates.handledAlarms.type === 'up'" src="/src/assets/demo/up.png"
|
|
||||||
class="trend-icon" alt="上升">
|
|
||||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
|
||||||
props.dashboardData.updates.handledAlarms.value }}
|
|
||||||
</span></div>
|
|
||||||
</div>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
|
|
||||||
<el-col :span="6">
|
|
||||||
<div class="metric-card">
|
|
||||||
<div class="metric-value">{{ props.dashboardData.avgProcessTime }}</div>
|
|
||||||
<div class="metric-label">平均处理时长</div>
|
|
||||||
<div class="metric-change">
|
|
||||||
较上周
|
|
||||||
<span :class="props.dashboardData.updates.avgProcessTime.type">
|
|
||||||
<img v-if="props.dashboardData.updates.avgProcessTime.type === 'up'" src="/src/assets/demo/up.png"
|
|
||||||
class="trend-icon" alt="上升">
|
|
||||||
<img v-else src="/src/assets/demo/down.png" class="trend-icon" alt="下降">{{
|
|
||||||
props.dashboardData.updates.avgProcessTime.value }}
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -176,6 +129,30 @@ const props = defineProps({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 卡片数据配置
|
||||||
|
const cardData = [
|
||||||
|
{
|
||||||
|
key: 'todayAlarmTotal',
|
||||||
|
label: '今日报警总数',
|
||||||
|
updateKey: 'todayAlarmTotal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unhandledAlarms',
|
||||||
|
label: '未处理报警',
|
||||||
|
updateKey: 'unhandledAlarms'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'handledAlarms',
|
||||||
|
label: '已处理报警',
|
||||||
|
updateKey: 'handledAlarms'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'avgProcessTime',
|
||||||
|
label: '平均处理时长',
|
||||||
|
updateKey: 'avgProcessTime'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
const timeRange = ref('7days');
|
const timeRange = ref('7days');
|
||||||
const alarmCountRef = ref(null);
|
const alarmCountRef = ref(null);
|
||||||
const processEfficiencyRef = ref(null);
|
const processEfficiencyRef = ref(null);
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pie-chart-container">
|
<div class="pie-chart-container">
|
||||||
|
<!-- 标题栏 -->
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<TitleComponent title="报警类型分布" :fontLevel="2" />
|
<TitleComponent title="报警类型分布" :fontLevel="2" />
|
||||||
<el-select v-model="selectedTimeRange" placeholder="选择时间范围" size="small">
|
<el-select v-model="selectedTimeRange" placeholder="选择时间范围" size="small">
|
||||||
<el-option label="今日" value="today" />
|
<el-option label="今日" value="today" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- 图表 -->
|
||||||
<div ref="pieChartRef" class="chart-content"></div>
|
<div ref="pieChartRef" class="chart-content"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -27,6 +29,7 @@ const selectedTimeRange = ref('today');
|
|||||||
const pieChartRef = ref(null);
|
const pieChartRef = ref(null);
|
||||||
let chartInstance = null;
|
let chartInstance = null;
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initChart();
|
initChart();
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
|
|||||||
@ -1,5 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="detaildata-container">
|
<div class="detaildata-container">
|
||||||
|
<div class="title-container">
|
||||||
|
<div class="title-left">
|
||||||
|
<TitleComponent title="发电量同比分析" :font-level="2" />
|
||||||
|
</div>
|
||||||
|
<div class="title-right">
|
||||||
|
<el-input
|
||||||
|
placeholder="请输入搜索内容"
|
||||||
|
style="width: 200px;"
|
||||||
|
prefix-icon="Search"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<el-table
|
<el-table
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
@ -177,8 +189,24 @@ onMounted(() => {
|
|||||||
.detaildata-container {
|
.detaildata-container {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
}
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
|
.title-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-container {
|
.pagination-container {
|
||||||
|
|||||||
@ -1,6 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="duibifenxi-bar-container">
|
<div class="duibifenxi-bar-container">
|
||||||
<div ref="chartRef" class="chart" style="width: 100%; height: 300px;"></div>
|
<div class="title">
|
||||||
|
<TitleComponent title="发电量同比分析" :font-level="2" />
|
||||||
|
<el-select placeholder="请选择线路" style="width: 150px;">
|
||||||
|
<el-option label="A线路" value="all"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div ref="chartRef" class="chart-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -32,17 +38,17 @@ const defaultCompareData: CompareData = {
|
|||||||
// 初始化图表
|
// 初始化图表
|
||||||
const initChart = () => {
|
const initChart = () => {
|
||||||
if (!chartRef.value) return
|
if (!chartRef.value) return
|
||||||
|
|
||||||
chartInstance = echarts.init(chartRef.value)
|
chartInstance = echarts.init(chartRef.value)
|
||||||
const data = props.compareData || defaultCompareData
|
const data = props.compareData || defaultCompareData
|
||||||
|
|
||||||
const option = {
|
const option = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
type: 'shadow'
|
type: 'shadow'
|
||||||
},
|
},
|
||||||
formatter: function(params: any) {
|
formatter: function (params: any) {
|
||||||
const current = params[0]
|
const current = params[0]
|
||||||
const lastYear = params[1]
|
const lastYear = params[1]
|
||||||
let result = `${current.name}<br/>`
|
let result = `${current.name}<br/>`
|
||||||
@ -78,16 +84,12 @@ const initChart = () => {
|
|||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: 'kwh',
|
|
||||||
nameTextStyle: {
|
|
||||||
color: '#666',
|
|
||||||
padding: [0, 0, 0, 40]
|
|
||||||
},
|
|
||||||
axisLine: {
|
axisLine: {
|
||||||
show: false
|
show: false
|
||||||
},
|
},
|
||||||
axisLabel: {
|
axisLabel: {
|
||||||
color: '#666'
|
color: '#666',
|
||||||
|
formatter: '{value} Kwh',
|
||||||
},
|
},
|
||||||
splitLine: {
|
splitLine: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
@ -123,7 +125,7 @@ const initChart = () => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
chartInstance.setOption(option)
|
chartInstance.setOption(option)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,28 +149,35 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.duibifenxi-bar-container {
|
.duibifenxi-bar-container {
|
||||||
padding: 16px;
|
padding: 10px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
min-height: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
.title {
|
||||||
flex: 1;
|
display: flex;
|
||||||
min-height: 0;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.chart-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 响应式调整
|
// 响应式调整
|
||||||
@media screen and (max-width: 768px) {
|
@media screen and (max-width: 768px) {
|
||||||
.duibifenxi-bar-container {
|
.duibifenxi-bar-container {
|
||||||
padding: 12px;
|
padding: 5px;
|
||||||
|
min-height: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
.chart-container {
|
||||||
height: 250px;
|
min-height: 230px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -1,43 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="tongbifenxi-line-container">
|
<div class="tongbifenxi-line-container">
|
||||||
<div id="tongbifenxiLineChart" class="chart-container"></div>
|
<div class="title">
|
||||||
|
<TitleComponent title="发电量同比分析" :font-level="2" />
|
||||||
|
<el-select placeholder="请选择线路" style="width: 150px;">
|
||||||
|
<el-option label="A线路" value="all"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div ref="chartDomRef" class="chart-container"></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, onBeforeUnmount, ref } from 'vue';
|
import { onMounted, onBeforeUnmount, ref } from 'vue';
|
||||||
import * as echarts from 'echarts';
|
import * as echarts from 'echarts';
|
||||||
|
import TitleComponent from '@/components/TitleComponent/index.vue';
|
||||||
|
|
||||||
|
const chartDomRef = ref<HTMLElement | null>(null);
|
||||||
const chartInstance = ref<echarts.ECharts | null>(null);
|
const chartInstance = ref<echarts.ECharts | null>(null);
|
||||||
|
|
||||||
const initChart = () => {
|
const initChart = () => {
|
||||||
const chartDom = document.getElementById('tongbifenxiLineChart');
|
if (!chartDomRef.value) return;
|
||||||
if (!chartDom) return;
|
|
||||||
|
|
||||||
chartInstance.value = echarts.init(chartDom);
|
chartInstance.value = echarts.init(chartDomRef.value);
|
||||||
|
|
||||||
// 写死的数据
|
// 写死的数据
|
||||||
const dates = ['1号', '2号', '3号', '4号', '5号', '6号', '7号'];
|
const dates = ['1号', '2号', '3号', '4号', '5号', '6号', '7号'];
|
||||||
const growthRates = ['1.50', '1.20', '0.50', '0.80', '0.90', '0.30', '-2.00'];
|
const growthRates = [1.50, 1.20, 0.50, 0.80, 0.90, 0.30, -2.00];
|
||||||
|
|
||||||
const option: echarts.EChartsOption = {
|
const option: echarts.EChartsOption = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'item',
|
||||||
backgroundColor: 'rgba(0, 0, 0, 0.7)',
|
backgroundColor: '#67c23a',
|
||||||
borderColor: '#409eff',
|
borderWidth: 0,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#fff'
|
color: '#fff',
|
||||||
|
fontSize: 14
|
||||||
},
|
},
|
||||||
formatter: (params: any) => {
|
formatter: (params: any) => {
|
||||||
const data = params[0];
|
return `${params.name}:\n环比增长率:${params.value}%`;
|
||||||
return `${data.name}:\n环比增长率: ${data.value}%`;
|
|
||||||
},
|
},
|
||||||
axisPointer: {
|
padding: [10, 15]
|
||||||
type: 'cross',
|
|
||||||
label: {
|
|
||||||
backgroundColor: '#6a7985'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
left: '3%',
|
||||||
@ -51,7 +53,7 @@ const initChart = () => {
|
|||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: dates,
|
data: dates,
|
||||||
axisTick: {
|
axisTick: {
|
||||||
alignWithLabel: true
|
show: false
|
||||||
},
|
},
|
||||||
axisLine: {
|
axisLine: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
@ -90,7 +92,6 @@ const initChart = () => {
|
|||||||
{
|
{
|
||||||
name: '环比增长率',
|
name: '环比增长率',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
stack: 'Total',
|
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
{
|
{
|
||||||
@ -103,9 +104,6 @@ const initChart = () => {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
emphasis: {
|
|
||||||
focus: 'series'
|
|
||||||
},
|
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#67c23a',
|
color: '#67c23a',
|
||||||
width: 3
|
width: 3
|
||||||
@ -117,6 +115,17 @@ const initChart = () => {
|
|||||||
borderColor: '#fff',
|
borderColor: '#fff',
|
||||||
borderWidth: 2
|
borderWidth: 2
|
||||||
},
|
},
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
itemStyle: {
|
||||||
|
color: '#67c23a',
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 3,
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowColor: 'rgba(103, 194, 58, 0.5)'
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
data: growthRates,
|
data: growthRates,
|
||||||
smooth: true
|
smooth: true
|
||||||
}
|
}
|
||||||
@ -149,8 +158,14 @@ onBeforeUnmount(() => {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 4px;
|
}
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
||||||
|
.title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-container {
|
.chart-container {
|
||||||
|
|||||||
200
src/views/shengchanManage/powerfenxi/components/zonglan.vue
Normal file
200
src/views/shengchanManage/powerfenxi/components/zonglan.vue
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
<template>
|
||||||
|
<div class="zonglan-container">
|
||||||
|
<!-- 循环生成统计卡片 -->
|
||||||
|
<div v-for="card in statCards" :key="card.id" class="stat-card">
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">{{ card.title }}</span>
|
||||||
|
<el-tooltip content="查看详情" placement="top">
|
||||||
|
<el-icon>
|
||||||
|
<Warning />
|
||||||
|
</el-icon>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<div class="stat-value">{{ card.value }}</div>
|
||||||
|
<div class="stat-footer">
|
||||||
|
<span class="trend-indicator up">
|
||||||
|
<img src="/src/assets/demo/up.png" alt="up" class="trend-icon"> {{ card.trendChange }}
|
||||||
|
</span>
|
||||||
|
<el-select v-model="card.selectedTimeRange" placeholder="选择时间范围" style="width: 120px; font-size: 12px;">
|
||||||
|
<el-option label="Today" value="today"></el-option>
|
||||||
|
<el-option label="This Week" value="week"></el-option>
|
||||||
|
<el-option label="This Month" value="month"></el-option>
|
||||||
|
<el-option label="This Year" value="year"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
// 统计卡片数据
|
||||||
|
interface StatCard {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
value: string;
|
||||||
|
trendChange: string;
|
||||||
|
selectedTimeRange: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const statCards = ref<StatCard[]>([
|
||||||
|
{
|
||||||
|
id: 'power-total',
|
||||||
|
title: '总发电量',
|
||||||
|
value: '2,456.8',
|
||||||
|
trendChange: '4.2%',
|
||||||
|
selectedTimeRange: 'today'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'year-on-year',
|
||||||
|
title: '同比增长率',
|
||||||
|
value: '3.8%',
|
||||||
|
trendChange: '0.5%',
|
||||||
|
selectedTimeRange: 'today'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'month-on-month',
|
||||||
|
title: '环比增长率',
|
||||||
|
value: '2.1%',
|
||||||
|
trendChange: '0.3%',
|
||||||
|
selectedTimeRange: 'today'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'efficiency',
|
||||||
|
title: '运行效率',
|
||||||
|
value: '98.6%',
|
||||||
|
trendChange: '1.2%',
|
||||||
|
selectedTimeRange: 'today'
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.zonglan-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
flex: 1;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-icon {
|
||||||
|
color: #c0c4cc;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
transition: color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-icon:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-content {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
line-height: 1.2;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-indicator.up {
|
||||||
|
color: #67c23a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-indicator.down {
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-indicator i {
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trend-icon {
|
||||||
|
margin-right: 4px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-range {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.zonglan-container {
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.zonglan-container {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 22px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,12 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="power-fenxi-container">
|
||||||
<DuibifenxiBar></DuibifenxiBar>
|
<!-- 标题栏 -->
|
||||||
<tongbifenxiLine></tongbifenxiLine>
|
<el-row :gutter="24">
|
||||||
<detaildata></detaildata>
|
<el-col :span="12">
|
||||||
|
<TitleComponent title="电量分析" subtitle="测量在电解过程中消耗的电荷量" />
|
||||||
|
</el-col>
|
||||||
|
<!-- 外层col:控制整体宽度并右对齐,同时作为flex容器 -->
|
||||||
|
<el-col :span="12" style="display: flex; justify-content: flex-end; align-items: center;">
|
||||||
|
<el-col :span="4">
|
||||||
|
<el-button type="primary">
|
||||||
|
导出数据
|
||||||
|
<el-icon class="el-icon--right">
|
||||||
|
<UploadFilled />
|
||||||
|
</el-icon>
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<!-- 第一排:总览组件 -->
|
||||||
|
<el-row :gutter="20" class="mb-4">
|
||||||
|
<el-col :span="24">
|
||||||
|
<zonglan></zonglan>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="18">
|
||||||
|
<TitleComponent title="发电量对比分析" :font-level="2" />
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="3">
|
||||||
|
<el-select placeholder="请选择时间" style="width: 100%;">
|
||||||
|
<el-option label="今天" value="all"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="3">
|
||||||
|
<el-date-picker v-model="value1" type="daterange" range-separator="至" start-placeholder="开始"
|
||||||
|
end-placeholder="结束" style="width: 100%;" />
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<el-row :gutter="20" class="mb-4">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card>
|
||||||
|
<DuibifenxiBar></DuibifenxiBar>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card>
|
||||||
|
<tongbifenxiLine></tongbifenxiLine>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 第三排:详细数据组件 -->
|
||||||
|
<el-row :gutter="20">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-card>
|
||||||
|
<detaildata></detaildata>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import TitleComponent from '@/components/TitleComponent/index.vue';
|
||||||
import detaildata from '@/views/shengchanManage/powerfenxi/components/detaildata.vue'
|
import detaildata from '@/views/shengchanManage/powerfenxi/components/detaildata.vue'
|
||||||
import tongbifenxiLine from './components/tongbifenxiLine.vue';
|
import tongbifenxiLine from '@/views/shengchanManage/powerfenxi/components/tongbifenxiLine.vue';
|
||||||
import DuibifenxiBar from './components/duibifenxiBar.vue';
|
import DuibifenxiBar from '@/views/shengchanManage/powerfenxi/components/duibifenxiBar.vue';
|
||||||
|
import zonglan from '@/views/shengchanManage/powerfenxi/components/zonglan.vue';
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.power-fenxi-container {
|
||||||
|
padding: 20px;
|
||||||
|
background-color: rgba(242, 248, 252, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb-4 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -15,92 +15,113 @@
|
|||||||
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="创建时间" style="width: 308px">
|
|
||||||
<el-date-picker
|
|
||||||
v-model="dateRange"
|
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
type="daterange"
|
|
||||||
range-separator="-"
|
|
||||||
start-placeholder="开始日期"
|
|
||||||
end-placeholder="结束日期"
|
|
||||||
:default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
|
<el-button type="primary" icon="Search" @click="handleQuery" v-hasPermi="['system:role:query']">搜索</el-button>
|
||||||
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
</transition>
|
||||||
|
<el-row :gutter="20">
|
||||||
<el-card shadow="hover">
|
<!-- 部门树 -->
|
||||||
<template #header>
|
<el-col :lg="4" :xs="24" style="">
|
||||||
<el-row :gutter="10">
|
<el-card shadow="hover">
|
||||||
<el-col :span="1.5">
|
<el-input v-model="deptName" placeholder="请输入部门名称" prefix-icon="Search" clearable />
|
||||||
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
<el-tree
|
||||||
</el-col>
|
ref="deptTreeRef"
|
||||||
<el-col :span="1.5">
|
class="mt-2"
|
||||||
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()">修改</el-button>
|
node-key="id"
|
||||||
</el-col>
|
:data="deptOptions"
|
||||||
<el-col :span="1.5">
|
:props="{ label: 'label', children: 'children' }"
|
||||||
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()">删除</el-button>
|
:expand-on-click-node="false"
|
||||||
</el-col>
|
:filter-node-method="filterNode"
|
||||||
<el-col :span="1.5">
|
highlight-current
|
||||||
<el-button v-hasPermi="['system:role:export']" type="warning" plain icon="Download" @click="handleExport">导出</el-button>
|
default-expand-all
|
||||||
</el-col>
|
@node-click="handleNodeClick"
|
||||||
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
/>
|
||||||
</el-row>
|
</el-card>
|
||||||
</template>
|
</el-col>
|
||||||
|
<el-col :lg="20" :xs="24">
|
||||||
<el-table ref="roleTableRef" border v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
<el-card shadow="hover">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<template #header>
|
||||||
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
<el-row :gutter="10">
|
||||||
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
<el-col :span="1.5">
|
||||||
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
<el-button v-hasPermi="['system:role:add']" type="primary" plain icon="Plus" @click="handleAdd()">新增</el-button>
|
||||||
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
</el-col>
|
||||||
<el-table-column label="状态" align="center" width="100">
|
<el-col :span="1.5">
|
||||||
<template #default="scope">
|
<el-button v-hasPermi="['system:role:edit']" type="success" plain :disabled="single" icon="Edit" @click="handleUpdate()"
|
||||||
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
>修改</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="1.5">
|
||||||
|
<el-button v-hasPermi="['system:role:delete']" type="danger" plain :disabled="ids.length === 0" @click="handleDelete()"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
|
</el-col>
|
||||||
|
<right-toolbar v-model:show-search="showSearch" @query-table="getList"></right-toolbar>
|
||||||
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
<el-table ref="roleTableRef" v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column label="创建时间" align="center" prop="createTime">
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<template #default="scope">
|
<el-table-column v-if="false" label="角色编号" prop="roleId" width="120" />
|
||||||
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
<el-table-column label="角色名称" prop="roleName" :show-overflow-tooltip="true" width="150" />
|
||||||
</template>
|
<el-table-column label="权限字符" prop="roleKey" :show-overflow-tooltip="true" width="200" />
|
||||||
</el-table-column>
|
<el-table-column label="显示顺序" prop="roleSort" width="100" />
|
||||||
|
<el-table-column label="状态" align="center" width="100">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="创建时间" align="center" prop="createTime">
|
||||||
|
<template #default="scope">
|
||||||
|
<span>{{ proxy.parseTime(scope.row.createTime) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<el-table-column fixed="right" label="操作" width="180">
|
<el-table-column fixed="right" label="操作" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="修改" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="Edit" @click="handleUpdate(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="删除" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
<el-button v-hasPermi="['system:role:remove']" link type="primary" icon="Delete" @click="handleDelete(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="数据权限" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="CircleCheck" @click="handleDataScope(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
<el-tooltip v-if="scope.row.roleId !== 1" content="分配用户" placement="top">
|
||||||
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
<el-button v-hasPermi="['system:role:edit']" link type="primary" icon="User" @click="handleAuthUser(scope.row)"></el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<pagination
|
<pagination
|
||||||
v-if="total > 0"
|
v-if="total > 0"
|
||||||
v-model:total="total"
|
v-model:total="total"
|
||||||
v-model:page="queryParams.pageNum"
|
v-model:page="queryParams.pageNum"
|
||||||
v-model:limit="queryParams.pageSize"
|
v-model:limit="queryParams.pageSize"
|
||||||
@pagination="getList"
|
@pagination="getList"
|
||||||
/>
|
/>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
<el-dialog v-model="dialog.visible" :title="dialog.title" width="500px" append-to-body>
|
||||||
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="100px">
|
<el-form ref="roleFormRef" :model="form" :rules="rules" label-width="110px">
|
||||||
|
<el-form-item label="所属部门" prop="deptId">
|
||||||
|
<el-cascader
|
||||||
|
:options="deptOptions"
|
||||||
|
v-model="form.deptId"
|
||||||
|
placeholder="请选择所属部门"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
:show-all-levels="false"
|
||||||
|
:props="{ value: 'id', emitPath: false, checkStrictly: true }"
|
||||||
|
>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="角色名称" prop="roleName">
|
<el-form-item label="角色名称" prop="roleName">
|
||||||
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
<el-input v-model="form.roleName" placeholder="请输入角色名称" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -124,7 +145,7 @@
|
|||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单权限">
|
<el-form-item label="菜单权限">
|
||||||
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">展开/折叠</el-checkbox>
|
<el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand(Boolean($event), 'menu')">展开/折叠</el-checkbox>
|
||||||
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
@ -135,9 +156,12 @@
|
|||||||
node-key="id"
|
node-key="id"
|
||||||
:check-strictly="!form.menuCheckStrictly"
|
:check-strictly="!form.menuCheckStrictly"
|
||||||
empty-text="加载中,请稍候"
|
empty-text="加载中,请稍候"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
></el-tree>
|
></el-tree>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="是否为特殊角色">
|
||||||
|
<el-switch v-model="form.isSpecial" active-value="1" inactive-value="0" active-text="是" inactive-text="否"> </el-switch>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -165,7 +189,7 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
<el-form-item v-show="form.dataScope === '2'" label="数据权限">
|
||||||
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">展开/折叠</el-checkbox>
|
<el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand(Boolean($event), 'dept')">展开/折叠</el-checkbox>
|
||||||
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
<el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">全选/全不选</el-checkbox>
|
||||||
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
<el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">父子联动</el-checkbox>
|
||||||
<el-tree
|
<el-tree
|
||||||
@ -177,7 +201,7 @@
|
|||||||
node-key="id"
|
node-key="id"
|
||||||
:check-strictly="!form.deptCheckStrictly"
|
:check-strictly="!form.deptCheckStrictly"
|
||||||
empty-text="加载中,请稍候"
|
empty-text="加载中,请稍候"
|
||||||
:props="{ label: 'label', children: 'children' } as any"
|
:props="{ label: 'label', children: 'children' }"
|
||||||
></el-tree>
|
></el-tree>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
@ -196,6 +220,8 @@ import { addRole, changeRoleStatus, dataScope, delRole, getRole, listRole, updat
|
|||||||
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
import { roleMenuTreeselect, treeselect as menuTreeselect } from '@/api/system/menu/index';
|
||||||
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
import { RoleVO, RoleForm, RoleQuery, DeptTreeOption } from '@/api/system/role/types';
|
||||||
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
import { MenuTreeOption, RoleMenuTree } from '@/api/system/menu/types';
|
||||||
|
import api from '@/api/system/user';
|
||||||
|
import { DeptTreeVO, DeptVO } from '@/api/system/dept/types';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
@ -214,8 +240,11 @@ const menuExpand = ref(false);
|
|||||||
const menuNodeAll = ref(false);
|
const menuNodeAll = ref(false);
|
||||||
const deptExpand = ref(true);
|
const deptExpand = ref(true);
|
||||||
const deptNodeAll = ref(false);
|
const deptNodeAll = ref(false);
|
||||||
const deptOptions = ref<DeptTreeOption[]>([]);
|
const deptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
const enabledDeptOptions = ref<DeptTreeVO[]>([]);
|
||||||
|
|
||||||
const openDataScope = ref(false);
|
const openDataScope = ref(false);
|
||||||
|
const deptName = ref('');
|
||||||
|
|
||||||
/** 数据范围选项*/
|
/** 数据范围选项*/
|
||||||
const dataScopeOptions = ref([
|
const dataScopeOptions = ref([
|
||||||
@ -232,8 +261,9 @@ const roleFormRef = ref<ElFormInstance>();
|
|||||||
const dataScopeRef = ref<ElFormInstance>();
|
const dataScopeRef = ref<ElFormInstance>();
|
||||||
const menuRef = ref<ElTreeInstance>();
|
const menuRef = ref<ElTreeInstance>();
|
||||||
const deptRef = ref<ElTreeInstance>();
|
const deptRef = ref<ElTreeInstance>();
|
||||||
|
const deptTreeRef = ref<ElTreeInstance>();
|
||||||
|
|
||||||
const initForm: RoleForm = {
|
const initForm = {
|
||||||
roleId: undefined,
|
roleId: undefined,
|
||||||
roleSort: 1,
|
roleSort: 1,
|
||||||
status: '0',
|
status: '0',
|
||||||
@ -244,17 +274,22 @@ const initForm: RoleForm = {
|
|||||||
remark: '',
|
remark: '',
|
||||||
dataScope: '1',
|
dataScope: '1',
|
||||||
menuIds: [],
|
menuIds: [],
|
||||||
deptIds: []
|
deptId: '',
|
||||||
|
isSpecial: null,
|
||||||
|
deptIds: [],
|
||||||
|
roleSource: '1'
|
||||||
};
|
};
|
||||||
|
|
||||||
const data = reactive<PageData<RoleForm, RoleQuery>>({
|
const data = reactive({
|
||||||
form: { ...initForm },
|
form: { ...initForm },
|
||||||
queryParams: {
|
queryParams: {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
roleName: '',
|
roleName: '',
|
||||||
roleKey: '',
|
roleKey: '',
|
||||||
status: ''
|
deptId: '',
|
||||||
|
status: '',
|
||||||
|
roleSource: '1'
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
roleName: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
|
||||||
@ -269,6 +304,18 @@ const dialog = reactive<DialogOption>({
|
|||||||
title: ''
|
title: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 通过条件过滤节点 */
|
||||||
|
const filterNode = (value: string, data: any) => {
|
||||||
|
if (!value) return true;
|
||||||
|
return data.label.indexOf(value) !== -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 节点单击事件 */
|
||||||
|
const handleNodeClick = (data: DeptVO) => {
|
||||||
|
queryParams.value.deptId = data.id as string;
|
||||||
|
handleQuery();
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询角色列表
|
* 查询角色列表
|
||||||
*/
|
*/
|
||||||
@ -293,6 +340,9 @@ const handleQuery = () => {
|
|||||||
const resetQuery = () => {
|
const resetQuery = () => {
|
||||||
dateRange.value = ['', ''];
|
dateRange.value = ['', ''];
|
||||||
queryFormRef.value?.resetFields();
|
queryFormRef.value?.resetFields();
|
||||||
|
queryParams.value.pageNum = 1;
|
||||||
|
queryParams.value.deptId = undefined;
|
||||||
|
deptTreeRef.value?.setCurrentKey(undefined);
|
||||||
handleQuery();
|
handleQuery();
|
||||||
};
|
};
|
||||||
/**删除按钮操作 */
|
/**删除按钮操作 */
|
||||||
@ -323,7 +373,7 @@ const handleSelectionChange = (selection: RoleVO[]) => {
|
|||||||
|
|
||||||
/** 角色状态修改 */
|
/** 角色状态修改 */
|
||||||
const handleStatusChange = async (row: RoleVO) => {
|
const handleStatusChange = async (row: RoleVO) => {
|
||||||
const text = row.status === '0' ? '启用' : '停用';
|
let text = row.status === '0' ? '启用' : '停用';
|
||||||
try {
|
try {
|
||||||
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
|
await proxy?.$modal.confirm('确认要"' + text + '""' + row.roleName + '"角色吗?');
|
||||||
await changeRoleStatus(row.roleId, row.status);
|
await changeRoleStatus(row.roleId, row.status);
|
||||||
@ -340,17 +390,17 @@ const handleAuthUser = (row: RoleVO) => {
|
|||||||
|
|
||||||
/** 查询菜单树结构 */
|
/** 查询菜单树结构 */
|
||||||
const getMenuTreeselect = async () => {
|
const getMenuTreeselect = async () => {
|
||||||
const res = await menuTreeselect();
|
const res = await menuTreeselect({ menuSource: '1' });
|
||||||
menuOptions.value = res.data;
|
menuOptions.value = res.data;
|
||||||
};
|
};
|
||||||
/** 所有部门节点数据 */
|
/** 所有部门节点数据 */
|
||||||
const getDeptAllCheckedKeys = (): any => {
|
const getDeptAllCheckedKeys = (): any => {
|
||||||
// 目前被选中的部门节点
|
// 目前被选中的部门节点
|
||||||
const checkedKeys = deptRef.value?.getCheckedKeys();
|
let checkedKeys = deptRef.value?.getCheckedKeys();
|
||||||
// 半选中的部门节点
|
// 半选中的部门节点
|
||||||
const halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
|
let halfCheckedKeys = deptRef.value?.getHalfCheckedKeys();
|
||||||
if (halfCheckedKeys) {
|
if (halfCheckedKeys) {
|
||||||
checkedKeys?.unshift(...halfCheckedKeys);
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
}
|
}
|
||||||
return checkedKeys;
|
return checkedKeys;
|
||||||
};
|
};
|
||||||
@ -390,28 +440,28 @@ const handleUpdate = async (row?: RoleVO) => {
|
|||||||
};
|
};
|
||||||
/** 根据角色ID查询菜单树结构 */
|
/** 根据角色ID查询菜单树结构 */
|
||||||
const getRoleMenuTreeselect = (roleId: string | number) => {
|
const getRoleMenuTreeselect = (roleId: string | number) => {
|
||||||
return roleMenuTreeselect(roleId).then((res): RoleMenuTree => {
|
return roleMenuTreeselect(roleId, { menuSource: '1' }).then((res): RoleMenuTree => {
|
||||||
menuOptions.value = res.data.menus;
|
menuOptions.value = res.data.menus;
|
||||||
return res.data;
|
return res.data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
/** 根据角色ID查询部门树结构 */
|
/** 根据角色ID查询部门树结构 */
|
||||||
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
const getRoleDeptTreeSelect = async (roleId: string | number) => {
|
||||||
const res = await deptTreeSelect(roleId);
|
const res = await deptTreeSelect(roleId, { roleSource: '1' });
|
||||||
deptOptions.value = res.data.depts;
|
deptOptions.value = res.data.depts;
|
||||||
return res.data;
|
return res.data;
|
||||||
};
|
};
|
||||||
/** 树权限(展开/折叠)*/
|
/** 树权限(展开/折叠)*/
|
||||||
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
const handleCheckedTreeExpand = (value: boolean, type: string) => {
|
||||||
if (type == 'menu') {
|
if (type == 'menu') {
|
||||||
const treeList = menuOptions.value;
|
let treeList = menuOptions.value;
|
||||||
for (let i = 0; i < treeList.length; i++) {
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
if (menuRef.value) {
|
if (menuRef.value) {
|
||||||
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
menuRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (type == 'dept') {
|
} else if (type == 'dept') {
|
||||||
const treeList = deptOptions.value;
|
let treeList = deptOptions.value;
|
||||||
for (let i = 0; i < treeList.length; i++) {
|
for (let i = 0; i < treeList.length; i++) {
|
||||||
if (deptRef.value) {
|
if (deptRef.value) {
|
||||||
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
deptRef.value.store.nodesMap[treeList[i].id].expanded = value;
|
||||||
@ -438,11 +488,11 @@ const handleCheckedTreeConnect = (value: any, type: string) => {
|
|||||||
/** 所有菜单节点数据 */
|
/** 所有菜单节点数据 */
|
||||||
const getMenuAllCheckedKeys = (): any => {
|
const getMenuAllCheckedKeys = (): any => {
|
||||||
// 目前被选中的菜单节点
|
// 目前被选中的菜单节点
|
||||||
const checkedKeys = menuRef.value?.getCheckedKeys();
|
let checkedKeys = menuRef.value?.getCheckedKeys();
|
||||||
// 半选中的菜单节点
|
// 半选中的菜单节点
|
||||||
const halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
|
let halfCheckedKeys = menuRef.value?.getHalfCheckedKeys();
|
||||||
if (halfCheckedKeys) {
|
if (halfCheckedKeys) {
|
||||||
checkedKeys?.unshift(...halfCheckedKeys);
|
checkedKeys?.unshift.apply(checkedKeys, halfCheckedKeys);
|
||||||
}
|
}
|
||||||
return checkedKeys;
|
return checkedKeys;
|
||||||
};
|
};
|
||||||
@ -496,8 +546,28 @@ const cancelDataScope = () => {
|
|||||||
form.value = { ...initForm };
|
form.value = { ...initForm };
|
||||||
openDataScope.value = false;
|
openDataScope.value = false;
|
||||||
};
|
};
|
||||||
|
/** 查询部门下拉树结构 */
|
||||||
|
const getDeptTree = async () => {
|
||||||
|
const res = await api.deptTreeSelect({ isShow: '1' });
|
||||||
|
deptOptions.value = res.data;
|
||||||
|
enabledDeptOptions.value = filterDisabledDept(res.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 过滤禁用的部门 */
|
||||||
|
const filterDisabledDept = (deptList: DeptTreeVO[]) => {
|
||||||
|
return deptList.filter((dept) => {
|
||||||
|
if (dept.disabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (dept.children && dept.children.length) {
|
||||||
|
dept.children = filterDisabledDept(dept.children);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
getDeptTree(); // 初始化部门数据
|
||||||
getList();
|
getList();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user