feat: 完成营业时间模块拆分并补充页面注释规范
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// Mock 数据入口,仅在开发环境下使用
|
||||
import './store';
|
||||
import './store-hours';
|
||||
|
||||
console.warn('[Mock] Mock 数据已启用');
|
||||
|
||||
417
apps/web-antd/src/mock/store-hours.ts
Normal file
417
apps/web-antd/src/mock/store-hours.ts
Normal file
@@ -0,0 +1,417 @@
|
||||
import Mock from 'mockjs';
|
||||
|
||||
const Random = Mock.Random;
|
||||
|
||||
/** mockjs 请求回调参数 */
|
||||
interface MockRequestOptions {
|
||||
url: string;
|
||||
type: string;
|
||||
body: null | string;
|
||||
}
|
||||
|
||||
interface TimeSlotMock {
|
||||
id: string;
|
||||
type: number;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
capacity?: number;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
interface DayHoursMock {
|
||||
dayOfWeek: number;
|
||||
isOpen: boolean;
|
||||
slots: TimeSlotMock[];
|
||||
}
|
||||
|
||||
interface HolidayMock {
|
||||
id: string;
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
type: number;
|
||||
startTime?: string;
|
||||
endTime?: string;
|
||||
reason: string;
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
interface StoreHoursState {
|
||||
holidays: HolidayMock[];
|
||||
weeklyHours: DayHoursMock[];
|
||||
}
|
||||
|
||||
function parseUrlParams(url: string) {
|
||||
const parsed = new URL(url, 'http://localhost');
|
||||
const params: Record<string, string> = {};
|
||||
parsed.searchParams.forEach((value, key) => {
|
||||
params[key] = value;
|
||||
});
|
||||
return params;
|
||||
}
|
||||
|
||||
function parseBody(options: MockRequestOptions) {
|
||||
if (!options.body) return {};
|
||||
try {
|
||||
return JSON.parse(options.body);
|
||||
} catch (error) {
|
||||
console.error('[mock-store-hours] parseBody error:', error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeDate(date?: string) {
|
||||
if (!date) return '';
|
||||
return String(date).slice(0, 10);
|
||||
}
|
||||
|
||||
function normalizeTime(time?: string) {
|
||||
if (!time) return '';
|
||||
const matched = /(\d{2}:\d{2})/.exec(time);
|
||||
return matched?.[1] ?? '';
|
||||
}
|
||||
|
||||
function sortSlots(slots: TimeSlotMock[]) {
|
||||
return [...slots].toSorted((a, b) => {
|
||||
const startA = a.startTime;
|
||||
const startB = b.startTime;
|
||||
if (startA !== startB) return startA.localeCompare(startB);
|
||||
return a.type - b.type;
|
||||
});
|
||||
}
|
||||
|
||||
function sortHolidays(holidays: HolidayMock[]) {
|
||||
return [...holidays].toSorted((a, b) => {
|
||||
const dateCompare = a.startDate.localeCompare(b.startDate);
|
||||
if (dateCompare !== 0) return dateCompare;
|
||||
return a.id.localeCompare(b.id);
|
||||
});
|
||||
}
|
||||
|
||||
function cloneWeeklyHours(weeklyHours: DayHoursMock[]) {
|
||||
return weeklyHours.map((day) => ({
|
||||
...day,
|
||||
slots: day.slots.map((slot) => ({ ...slot })),
|
||||
}));
|
||||
}
|
||||
|
||||
function cloneHolidays(holidays: HolidayMock[]) {
|
||||
return holidays.map((holiday) => ({ ...holiday }));
|
||||
}
|
||||
|
||||
function createDefaultWeeklyHours(): DayHoursMock[] {
|
||||
const weekdays = [
|
||||
{
|
||||
dayOfWeek: 0,
|
||||
bizEnd: '22:00',
|
||||
delEnd: '21:30',
|
||||
delCap: 50,
|
||||
pickEnd: '21:00',
|
||||
},
|
||||
{
|
||||
dayOfWeek: 1,
|
||||
bizEnd: '22:00',
|
||||
delEnd: '21:30',
|
||||
delCap: 50,
|
||||
pickEnd: '21:00',
|
||||
},
|
||||
{
|
||||
dayOfWeek: 2,
|
||||
bizEnd: '22:00',
|
||||
delEnd: '21:30',
|
||||
delCap: 50,
|
||||
pickEnd: '21:00',
|
||||
},
|
||||
{
|
||||
dayOfWeek: 3,
|
||||
bizEnd: '22:00',
|
||||
delEnd: '21:30',
|
||||
delCap: 50,
|
||||
pickEnd: '21:00',
|
||||
},
|
||||
{
|
||||
dayOfWeek: 4,
|
||||
bizEnd: '23:00',
|
||||
delEnd: '22:30',
|
||||
delCap: 80,
|
||||
pickEnd: '22:00',
|
||||
},
|
||||
{
|
||||
dayOfWeek: 5,
|
||||
bizEnd: '23:00',
|
||||
delEnd: '22:30',
|
||||
delCap: 80,
|
||||
pickEnd: '22:00',
|
||||
},
|
||||
];
|
||||
|
||||
const result = weekdays.map((day) => ({
|
||||
dayOfWeek: day.dayOfWeek,
|
||||
isOpen: true,
|
||||
slots: [
|
||||
{ id: Random.guid(), type: 1, startTime: '09:00', endTime: day.bizEnd },
|
||||
{
|
||||
id: Random.guid(),
|
||||
type: 2,
|
||||
startTime: '10:00',
|
||||
endTime: day.delEnd,
|
||||
capacity: day.delCap,
|
||||
},
|
||||
{ id: Random.guid(), type: 3, startTime: '09:00', endTime: day.pickEnd },
|
||||
],
|
||||
}));
|
||||
|
||||
result.push({
|
||||
dayOfWeek: 6,
|
||||
isOpen: true,
|
||||
slots: [
|
||||
{ id: Random.guid(), type: 1, startTime: '10:00', endTime: '22:00' },
|
||||
{
|
||||
id: Random.guid(),
|
||||
type: 2,
|
||||
startTime: '10:30',
|
||||
endTime: '21:30',
|
||||
capacity: 60,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createDefaultHolidays(): HolidayMock[] {
|
||||
return [
|
||||
{
|
||||
id: Random.guid(),
|
||||
startDate: '2026-02-17',
|
||||
endDate: '2026-02-19',
|
||||
type: 1,
|
||||
reason: '春节假期',
|
||||
},
|
||||
{
|
||||
id: Random.guid(),
|
||||
startDate: '2026-04-05',
|
||||
endDate: '2026-04-05',
|
||||
type: 1,
|
||||
reason: '清明节',
|
||||
},
|
||||
{
|
||||
id: Random.guid(),
|
||||
startDate: '2026-02-14',
|
||||
endDate: '2026-02-14',
|
||||
type: 2,
|
||||
startTime: '09:00',
|
||||
endTime: '23:30',
|
||||
reason: '情人节延长营业',
|
||||
},
|
||||
{
|
||||
id: Random.guid(),
|
||||
startDate: '2026-05-01',
|
||||
endDate: '2026-05-01',
|
||||
type: 2,
|
||||
startTime: '10:00',
|
||||
endTime: '20:00',
|
||||
reason: '劳动节缩短营业',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function normalizeWeeklyHoursInput(list: any): DayHoursMock[] {
|
||||
const dayMap = new Map<number, DayHoursMock>();
|
||||
|
||||
if (Array.isArray(list)) {
|
||||
for (const item of list) {
|
||||
const dayOfWeek = Number(item?.dayOfWeek);
|
||||
if (!Number.isInteger(dayOfWeek) || dayOfWeek < 0 || dayOfWeek > 6)
|
||||
continue;
|
||||
|
||||
const slots: TimeSlotMock[] = Array.isArray(item?.slots)
|
||||
? item.slots.map((slot: any) => ({
|
||||
id: String(slot?.id || Random.guid()),
|
||||
type: Number(slot?.type) || 1,
|
||||
startTime: normalizeTime(slot?.startTime) || '09:00',
|
||||
endTime: normalizeTime(slot?.endTime) || '22:00',
|
||||
capacity:
|
||||
Number(slot?.type) === 2 && slot?.capacity !== undefined
|
||||
? Number(slot.capacity)
|
||||
: undefined,
|
||||
remark: slot?.remark || undefined,
|
||||
}))
|
||||
: [];
|
||||
|
||||
dayMap.set(dayOfWeek, {
|
||||
dayOfWeek,
|
||||
isOpen: Boolean(item?.isOpen),
|
||||
slots: sortSlots(slots),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Array.from({ length: 7 }).map((_, dayOfWeek) => {
|
||||
return (
|
||||
dayMap.get(dayOfWeek) ?? {
|
||||
dayOfWeek,
|
||||
isOpen: false,
|
||||
slots: [],
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeHolidayInput(holiday: any): HolidayMock {
|
||||
const type = Number(holiday?.type) === 2 ? 2 : 1;
|
||||
|
||||
return {
|
||||
id: String(holiday?.id || Random.guid()),
|
||||
startDate:
|
||||
normalizeDate(holiday?.startDate) || normalizeDate(holiday?.date),
|
||||
endDate:
|
||||
normalizeDate(holiday?.endDate) ||
|
||||
normalizeDate(holiday?.startDate) ||
|
||||
normalizeDate(holiday?.date),
|
||||
type,
|
||||
startTime:
|
||||
type === 2 ? normalizeTime(holiday?.startTime) || undefined : undefined,
|
||||
endTime:
|
||||
type === 2 ? normalizeTime(holiday?.endTime) || undefined : undefined,
|
||||
reason: holiday?.reason || '',
|
||||
remark: holiday?.remark || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const storeHoursMap = new Map<string, StoreHoursState>();
|
||||
|
||||
function ensureStoreState(storeId = '') {
|
||||
const key = storeId || 'default';
|
||||
let state = storeHoursMap.get(key);
|
||||
if (!state) {
|
||||
state = {
|
||||
weeklyHours: createDefaultWeeklyHours(),
|
||||
holidays: createDefaultHolidays(),
|
||||
};
|
||||
storeHoursMap.set(key, state);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// 获取门店营业时间
|
||||
Mock.mock(/\/store\/hours(?:\?|$)/, 'get', (options: MockRequestOptions) => {
|
||||
const params = parseUrlParams(options.url);
|
||||
const storeId = params.storeId || '';
|
||||
const state = ensureStoreState(storeId);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
storeId,
|
||||
weeklyHours: cloneWeeklyHours(state.weeklyHours),
|
||||
holidays: cloneHolidays(state.holidays),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
// 保存每周营业时间
|
||||
Mock.mock(/\/store\/hours\/weekly/, 'post', (options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = String(body.storeId || '');
|
||||
const state = ensureStoreState(storeId);
|
||||
state.weeklyHours = normalizeWeeklyHoursInput(body.weeklyHours);
|
||||
return { code: 200, data: null };
|
||||
});
|
||||
|
||||
// 删除特殊日期
|
||||
Mock.mock(
|
||||
/\/store\/hours\/holiday\/delete/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const holidayId = String(body.id || '');
|
||||
if (!holidayId) return { code: 200, data: null };
|
||||
|
||||
for (const [, state] of storeHoursMap) {
|
||||
const index = state.holidays.findIndex(
|
||||
(holiday) => holiday.id === holidayId,
|
||||
);
|
||||
if (index !== -1) {
|
||||
state.holidays.splice(index, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return { code: 200, data: null };
|
||||
},
|
||||
);
|
||||
|
||||
// 新增 / 编辑特殊日期
|
||||
Mock.mock(
|
||||
/\/store\/hours\/holiday(?!\/delete)/,
|
||||
'post',
|
||||
(options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const storeId = String(body.storeId || '');
|
||||
const state = ensureStoreState(storeId);
|
||||
const incomingHoliday = normalizeHolidayInput(body.holiday);
|
||||
|
||||
const existingIndex = state.holidays.findIndex(
|
||||
(item) => item.id === incomingHoliday.id,
|
||||
);
|
||||
if (existingIndex === -1) {
|
||||
state.holidays.push(incomingHoliday);
|
||||
} else {
|
||||
state.holidays[existingIndex] = incomingHoliday;
|
||||
}
|
||||
|
||||
state.holidays = sortHolidays(state.holidays);
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: { ...incomingHoliday },
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
// 复制营业时间
|
||||
Mock.mock(/\/store\/hours\/copy/, 'post', (options: MockRequestOptions) => {
|
||||
const body = parseBody(options);
|
||||
const sourceStoreId = String(body.sourceStoreId || '');
|
||||
const targetStoreIds: string[] = Array.isArray(body.targetStoreIds)
|
||||
? body.targetStoreIds.map(String).filter(Boolean)
|
||||
: [];
|
||||
|
||||
if (!sourceStoreId || targetStoreIds.length === 0) {
|
||||
return {
|
||||
code: 200,
|
||||
data: { copiedCount: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
const includeWeeklyHours = body.includeWeeklyHours !== false;
|
||||
const includeHolidays = body.includeHolidays !== false;
|
||||
const sourceState = ensureStoreState(sourceStoreId);
|
||||
|
||||
const uniqueTargets = [...new Set<string>(targetStoreIds)].filter(
|
||||
(id) => id !== sourceStoreId,
|
||||
);
|
||||
|
||||
for (const targetId of uniqueTargets) {
|
||||
const targetState = ensureStoreState(targetId);
|
||||
if (includeWeeklyHours) {
|
||||
targetState.weeklyHours = cloneWeeklyHours(sourceState.weeklyHours);
|
||||
}
|
||||
if (includeHolidays) {
|
||||
targetState.holidays = cloneHolidays(sourceState.holidays).map(
|
||||
(holiday) => ({
|
||||
...holiday,
|
||||
id: Random.guid(),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
code: 200,
|
||||
data: {
|
||||
copiedCount: uniqueTargets.length,
|
||||
includeHolidays,
|
||||
includeWeeklyHours,
|
||||
},
|
||||
};
|
||||
});
|
||||
Reference in New Issue
Block a user