Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/store/staff/components/ShiftTemplateCard.vue

136 lines
3.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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;
isTemplateConfigured: 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 undefined;
return dayjs(`2000-01-01 ${time}`);
}
/** 将时间组件值转换为 HH:mm 字符串。 */
function toTimeText(value: Dayjs | null | string | undefined) {
if (!value) return '';
if (typeof value === 'string') return value;
return value ? value.format('HH:mm') : '';
}
/** 处理模板时间变更。 */
function handleTemplateTimeChange(payload: {
field: 'endTime' | 'startTime';
shiftType: Exclude<ShiftType, 'off'>;
value: Dayjs | null | string;
}) {
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 v-if="!props.isTemplateConfigured" class="template-guide">
当前门店尚未配置班次模板请先设置并保存模板再进行员工排班
</div>
<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">
{{
props.isTemplateConfigured
? '调整模板后,个人排班和周排班中的同类型班次会同步到新的时间段。'
: '模板保存成功后,员工列表中的“排班”和“编辑排班”会自动可用。'
}}
</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>