feat: 完成员工排班模块并统一门店抽屉底部操作样式

This commit is contained in:
2026-02-16 22:43:45 +08:00
parent aebd0c285b
commit becef7e6cb
43 changed files with 5127 additions and 53 deletions

View File

@@ -0,0 +1,124 @@
<script setup lang="ts">
/**
* 文件职责:班次模板卡片。
* 1. 提供早班/晚班/全天模板时间编辑。
* 2. 透出保存与重置事件。
*/
import type { Dayjs } from 'dayjs';
import type { ShiftType, StoreShiftTemplatesDto } from '#/api/store-staff';
import { Button, Card, TimePicker } from 'ant-design-vue';
import dayjs from 'dayjs';
interface Props {
isSaving: boolean;
onSetTemplateTime: (payload: {
field: 'endTime' | 'startTime';
shiftType: Exclude<ShiftType, 'off'>;
value: string;
}) => void;
templates: StoreShiftTemplatesDto;
}
const props = defineProps<Props>();
const emit = defineEmits<{
(event: 'reset'): void;
(event: 'save'): void;
}>();
const templateRows: Array<{
colorClass: string;
label: string;
shiftType: Exclude<ShiftType, 'off'>;
}> = [
{ shiftType: 'morning', label: '早班', colorClass: 'template-dot-morning' },
{ shiftType: 'evening', label: '晚班', colorClass: 'template-dot-evening' },
{ shiftType: 'full', label: '全天', colorClass: 'template-dot-full' },
];
/** 将 HH:mm 字符串转换为时间组件值。 */
function toPickerValue(time: string) {
if (!time) return null;
return dayjs(`2000-01-01 ${time}`);
}
/** 将时间组件值转换为 HH:mm 字符串。 */
function toTimeText(value: Dayjs | null) {
return value ? value.format('HH:mm') : '';
}
/** 处理模板时间变更。 */
function handleTemplateTimeChange(payload: {
field: 'endTime' | 'startTime';
shiftType: Exclude<ShiftType, 'off'>;
value: Dayjs | null;
}) {
props.onSetTemplateTime({
shiftType: payload.shiftType,
field: payload.field,
value: toTimeText(payload.value),
});
}
</script>
<template>
<Card :bordered="false" class="staff-card">
<template #title>
<span class="section-title">班次模板</span>
</template>
<div class="template-list">
<div
v-for="row in templateRows"
:key="row.shiftType"
class="template-row"
>
<span class="template-dot" :class="row.colorClass"></span>
<span class="template-label">{{ row.label }}</span>
<div class="template-time-group">
<TimePicker
:value="toPickerValue(props.templates[row.shiftType].startTime)"
format="HH:mm"
:allow-clear="false"
@update:value="
(value) =>
handleTemplateTimeChange({
shiftType: row.shiftType,
field: 'startTime',
value,
})
"
/>
<span class="template-time-separator">~</span>
<TimePicker
:value="toPickerValue(props.templates[row.shiftType].endTime)"
format="HH:mm"
:allow-clear="false"
@update:value="
(value) =>
handleTemplateTimeChange({
shiftType: row.shiftType,
field: 'endTime',
value,
})
"
/>
</div>
</div>
</div>
<div class="template-tip">
调整模板后个人排班和周排班中的同类型班次会同步到新的时间段
</div>
<div class="staff-card-actions">
<Button :disabled="props.isSaving" @click="emit('reset')">重置</Button>
<Button type="primary" :loading="props.isSaving" @click="emit('save')">
保存模板
</Button>
</div>
</Card>
</template>