feat(duty): add web-admin calendar page and public H5 grab UI

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-08-14 17:14:05 +08:00
1 parent 36fc7f286c
commit 35e09fa09b
9 files changed
+3152

No files matched your search

+71
View File
@@ -0,0 +1,71 @@
import request from '@/utils/http'
export type ShiftType = 'morning' | 'evening' | 'duty'
export type LinkStatus = 'open' | 'closed'
export interface DutyAssignmentItem {
id?: string
source: 'assign' | 'grab'
userId?: string | null
personName: string
}
export interface DutySlotItem {
id?: string
shiftType: ShiftType
shiftLabel?: string
capacity: number
taken?: number
assignments: DutyAssignmentItem[]
}
export interface DutyDayItem {
id?: string | null
dutyDate: string
linkStatus: LinkStatus
accessToken?: string | null
publicUrl?: string | null
slots: DutySlotItem[]
}
export function fetchDutyMonth(year: number, month: number) {
return request.get<DutyDayItem[]>({
url: '/web/admin/duty',
params: { year, month }
})
}
export function fetchDutyDay(dutyDate: string) {
return request.get<DutyDayItem>({
url: '/web/admin/duty/day',
params: { dutyDate }
})
}
export function saveDutyDay(data: {
dutyDate: string
slots: Array<{
shiftType: ShiftType
capacity: number
assignments: DutyAssignmentItem[]
}>
linkStatus?: LinkStatus
}) {
return request.post<DutyDayItem>({
url: '/web/admin/duty/day',
data
})
}
export function setDutyLinkStatus(dayId: string, linkStatus: LinkStatus) {
return request.post<DutyDayItem>({
url: `/web/admin/duty/day/${dayId}/link`,
data: { linkStatus }
})
}
export function deleteDutyAssignment(id: string) {
return request.delete({
url: `/web/admin/duty/assignments/${id}`
})
}
+32
View File
@@ -0,0 +1,32 @@
import { publicPlGet, publicPlPost } from '@/utils/http/public-pl'
import type { ShiftType } from '@/api/duty'
export interface PublicDutySlot {
id?: string
shiftType: ShiftType
shiftLabel?: string
capacity: number
taken: number
assignments: Array<{ id?: string; source: string; personName: string }>
}
export interface PublicDutyPage {
dutyDate: string
linkStatus: 'open' | 'closed'
closed?: boolean
slots: PublicDutySlot[]
}
export interface PublicDutyGrabResult {
dutyDate: string
shiftType: ShiftType
shiftLabel: string
personName: string
status: string
}
export const publicDutyApi = {
getPage: (token: string) => publicPlGet<PublicDutyPage>(`/public/duty/${token}`),
grab: (token: string, data: { shiftType: string; personName: string }) =>
publicPlPost<PublicDutyGrabResult>(`/public/duty/${token}/grab`, data)
}