feat: 排班管理

This commit is contained in:
fyy
2025-08-11 11:05:47 +08:00
parent effcb9ef86
commit 0a77934d8b
5 changed files with 71 additions and 37 deletions

View File

@@ -78,3 +78,17 @@ export function arrangmentList(params?: arrangmentListQuery) {
{ params }, { params },
); );
} }
/**
* 查询某天排班人员详情列表(班表视图)
* @param params
* @returns 排班列表
*/
export function queryScheduleView(params?: arrangmentListQuery) {
return requestClient.get<PageResult<AttendanceUserGroup>>(
'/property/AttendanceUserGroup/queryScheduleView',
{ params },
);
}

View File

@@ -40,9 +40,9 @@ export interface ArrangementVO {
* 状态0-未生效1-已生效 * 状态0-未生效1-已生效
*/ */
status?: number; status?: number;
userGroupList?:any[]; userGroupList?: any[];
attendanceGroup?:any; attendanceGroup?: any;
dateType?:number dateType?: number;
} }
export interface ArrangementForm extends BaseEntity { export interface ArrangementForm extends BaseEntity {
@@ -138,5 +138,6 @@ export interface ArrangementQuery extends PageQuery {
month?: string; month?: string;
} }
export interface arrangmentListQuery extends PageQuery { export interface arrangmentListQuery extends PageQuery {
currentDate:string//某天的日期 currentDate: string; //某天的日期
} }
export interface AttendanceUserGroup {}

View File

@@ -15,7 +15,7 @@ import {
import { Modal } from 'ant-design-vue'; import { Modal } from 'ant-design-vue';
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'changeView', value: boolean): void; (e: 'changeView', value: 'calender' | 'schedule'): void;
}>(); }>();
const props = defineProps<{ const props = defineProps<{
viewMode: 'calender' | 'schedule'; viewMode: 'calender' | 'schedule';
@@ -24,20 +24,15 @@ const selectedDate = ref();
const calendarData = reactive<any[]>([]); const calendarData = reactive<any[]>([]);
const loading = ref(false); const loading = ref(false);
// 查询日历数据 // 查询日历数据
const fetchCalendarData = async (month?: string) => { const fetchCalendarData = async () => {
try { try {
loading.value = true; loading.value = true;
const params = { const params = {
month: month: selectedDate.value?.format('YYYY-MM') || dayjs().format('YYYY-MM'),
month ||
selectedDate.value?.format('YYYY-MM') ||
dayjs().format('YYYY-MM'),
}; };
const res = await arrangementCalender(params); const res = await arrangementCalender(params);
const currentMonth = const currentMonth =
month || selectedDate.value?.format('YYYY-MM') || dayjs().format('YYYY-MM'); //当前月份的开始日期
selectedDate.value?.format('YYYY-MM') ||
dayjs().format('YYYY-MM'); //当前月份的开始日期
// 清空之前的数据 // 清空之前的数据
calendarData.length = 0; calendarData.length = 0;
@@ -171,7 +166,6 @@ const scheduleData: {
]; ];
// 切换视图模式 // 切换视图模式
function handleViewModeChange(e: RadioChangeEvent): void { function handleViewModeChange(e: RadioChangeEvent): void {
// 将父组件的isCalenderView变为true
emit('changeView', e.target.value); emit('changeView', e.target.value);
} }

View File

@@ -82,34 +82,51 @@ export const columns: VxeGridProps['columns'] = [
}, },
{ {
title: '人员', title: '人员',
field: 'scheduleName', field: 'employeeName',
width: 120, width: 120,
// width: 'auto', // width: 'auto',
}, },
{ {
title: '单位', title: '单位',
field: 'scheduleName', field: 'deptName',
width: 'auto', width: 'auto',
}, },
{ // {
title: '排班名称', // title: '排班名称',
field: 'scheduleName', // field: 'attendanceArrangement.scheduleName',
minWidth: 120, // minWidth: 120,
}, // },
{ {
title: '考勤组', title: '考勤组',
field: 'groupId', field: 'attendanceGroup.groupName',
minWidth: 120, minWidth: 120,
}, },
{ {
title: '考勤类型', title: '考勤类型',
field: 'scheduleType', field: 'attendanceGroup.attendanceType',
slots: {
default: ({ row }) => {
return renderDict(String(row.attendanceGroup.attendanceType),'wy_kqlx')
},
},
width: 'auto', width: 'auto',
}, },
{ {
title: '考勤时间', title: '考勤时间',
field: 'dateType', field: 'attendanceShift',
minWidth: 200, minWidth: 200,
slots: {
default: ({ row }) => {
if (row.attendanceShift.startTime && row.attendanceShift.endTime) {
if(row.attendanceShift.restEndTime&&row.attendanceShift.restStartTime){
return `${row.attendanceShift.startTime}${row.attendanceShift.endTime} ${row.shift.restStartTime}${row.shift.restEndTime}`;
}else{
return `${row.attendanceShift.startTime}${row.attendanceShift.endTime}`;
}
}
return '/';
},
},
}, },
{ {
field: 'action', field: 'action',
@@ -289,7 +306,7 @@ export const workforceDayDetailColumns:VxeGridProps['columns'] =[
default: ({ row }) => { default: ({ row }) => {
if (row.shift.startTime && row.shift.endTime) { if (row.shift.startTime && row.shift.endTime) {
if(row.shift.restEndTime&&row.shift.restStartTime){ if(row.shift.restEndTime&&row.shift.restStartTime){
return `${row.shift.restStartTime}${row.shift.restEndTime} ${row.shift.startTime}${row.shift.endTime}`; return `${row.shift.startTime}${row.shift.endTime} ${row.shift.restStartTime}${row.shift.restEndTime}`;
}else{ }else{
return `${row.shift.startTime}${row.shift.endTime}`; return `${row.shift.startTime}${row.shift.endTime}`;
} }

View File

@@ -7,24 +7,28 @@ import { columns } from './data';
import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table'; import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
import { getVxePopupContainer } from '@vben/utils'; import { getVxePopupContainer } from '@vben/utils';
import { import {
arrangementList, queryScheduleView,
arrangementRemove, arrangementRemove,
} from '#/api/property/attendanceManagement/arrangement'; } from '#/api/property/attendanceManagement/arrangement';
import arrangementModal from './arrangement-modal.vue'; import arrangementModal from './arrangement-modal.vue';
import type { ArrangementForm } from '#/api/property/attendanceManagement/arrangement/model'; import type { ArrangementForm } from '#/api/property/attendanceManagement/arrangement/model';
import { Page, useVbenModal } from '@vben/common-ui'; import { Page, useVbenModal } from '@vben/common-ui';
import { Popconfirm, Space } from 'ant-design-vue'; import { Popconfirm, Space } from 'ant-design-vue';
const emit = defineEmits<{ (e: 'changeView', value: boolean): void }>(); import dayjs from 'dayjs';
const emit = defineEmits<{
(e: 'changeView', value: 'calender' | 'schedule'): void;
}>();
const props = defineProps<{ const props = defineProps<{
viewMode: 'calender' | 'schedule'; viewMode: 'calender' | 'schedule';
}>(); }>();
const value = ref<Dayjs>(); const value = ref<Dayjs>();
const onPanelChange = (value: Dayjs, mode: string) => { const onSelect = (value: Dayjs) => {
console.log(value, mode); currentDate.value = dayjs(value).format('YYYY-MM-DD');
tableApi.query();
}; };
let currentDate = ref<string>(dayjs().format('YYYY-MM-DD'));
// 切换视图模式 // 切换视图模式
function handleViewModeChange(e: RadioChangeEvent): void { function handleViewModeChange(e: RadioChangeEvent): void {
// 将父组件的isCalenderView变为false
emit('changeView', e.target.value); emit('changeView', e.target.value);
} }
@@ -45,11 +49,11 @@ const gridOptions: VxeGridProps = {
pagerConfig: {}, pagerConfig: {},
proxyConfig: { proxyConfig: {
ajax: { ajax: {
query: async ({ page }, formValues = {}) => { query: async ({ page }) => {
return await arrangementList({ return await queryScheduleView({
pageNum: page.currentPage, pageNum: page.currentPage,
pageSize: page.pageSize, pageSize: page.pageSize,
...formValues, currentDate: currentDate.value,
}); });
}, },
}, },
@@ -115,7 +119,7 @@ async function handleDelete(row: Required<ArrangementForm>) {
v-model:value="value" v-model:value="value"
:fullscreen="false" :fullscreen="false"
:mode="'month'" :mode="'month'"
@panelChange="onPanelChange" @select="onSelect"
/> />
</div> </div>
</div> </div>
@@ -133,7 +137,7 @@ async function handleDelete(row: Required<ArrangementForm>) {
<Popconfirm <Popconfirm
:get-popup-container="getVxePopupContainer" :get-popup-container="getVxePopupContainer"
placement="left" placement="left"
title="确认除?" title="确认除?"
@confirm="handleDelete(row)" @confirm="handleDelete(row)"
> >
<ghost-button <ghost-button
@@ -141,7 +145,7 @@ async function handleDelete(row: Required<ArrangementForm>) {
v-access:code="['property:arrangement:remove']" v-access:code="['property:arrangement:remove']"
@click.stop="" @click.stop=""
> >
{{ $t('pages.common.delete') }} 移除
</ghost-button> </ghost-button>
</Popconfirm> </Popconfirm>
</Space> </Space>
@@ -153,4 +157,8 @@ async function handleDelete(row: Required<ArrangementForm>) {
<ArrangementModal @reload="tableApi.query()" /> <ArrangementModal @reload="tableApi.query()" />
</div> </div>
</template> </template>
<style></style> <style scoped>
:deep(.ant-radio-group) {
display: none;
}
</style>