feat(新增加班申请功能): 新增申请功能,可在工作台进行审核。

fix(dict_data): 在字典数据新增、编辑时可以操作颜色类型字段(color_type)。
This commit is contained in:
dk
2026-06-01 21:37:08 +08:00
parent b2da882b31
commit d3d0830820
29 changed files with 1966 additions and 23 deletions

View File

@@ -0,0 +1,280 @@
import { WEB_SERVICE_PREFIX } from '@/constants/service';
import { request } from '../request';
import { type ProjectLocalDateValue, normalizeProjectLocalDate } from './project-shared';
import {
type ServiceRequestResult,
mapServiceResult,
normalizeNullableStringId,
normalizeStringId,
safeJsonRequestConfig
} from './shared';
const OVERTIME_APPLICATION_PREFIX = `${WEB_SERVICE_PREFIX}/project/overtime-applications`;
type StringIdResponse = string | number;
type OvertimeApplicationResponse = Omit<
Api.OvertimeApplication.OvertimeApplication,
'id' | 'applicantId' | 'approverId' | 'overtimeDate' | 'allowEdit' | 'terminal'
> & {
id: StringIdResponse;
applicantId: StringIdResponse;
approverId: StringIdResponse;
overtimeDate: ProjectLocalDateValue;
allowEdit?: boolean | number | string | null;
terminal?: boolean | number | string | null;
};
type OvertimeApplicationPageResponse = Omit<Api.OvertimeApplication.OvertimeApplicationPageResult, 'total' | 'list'> & {
total: number | string;
list: OvertimeApplicationResponse[];
};
type OvertimeApplicationStatusLogResponse = Omit<
Api.OvertimeApplication.OvertimeApplicationStatusLog,
'id' | 'applicationId' | 'operatorUserId' | 'overtimeDateSnapshot'
> & {
id: StringIdResponse;
applicationId: StringIdResponse;
operatorUserId: StringIdResponse;
overtimeDateSnapshot: ProjectLocalDateValue;
};
function normalizeBooleanFlag(value: boolean | number | string | null | undefined) {
if (typeof value === 'boolean') {
return value;
}
if (typeof value === 'number') {
return value === 1;
}
if (typeof value === 'string') {
const normalized = value.trim().toLowerCase();
return !['', '0', 'false', 'n', 'no'].includes(normalized);
}
return false;
}
function normalizeTotal(total: number | string) {
const value = Number(total);
return Number.isFinite(value) ? Math.max(0, value) : 0;
}
function normalizeOvertimeApplication(
response: OvertimeApplicationResponse
): Api.OvertimeApplication.OvertimeApplication {
return {
...response,
id: normalizeStringId(response.id),
applicantId: normalizeStringId(response.applicantId),
approverId: normalizeStringId(response.approverId),
overtimeDate: normalizeProjectLocalDate(response.overtimeDate) ?? '',
statusName: response.statusName || response.statusCode,
allowEdit: normalizeBooleanFlag(response.allowEdit),
terminal: normalizeBooleanFlag(response.terminal),
approvalComment: response.approvalComment ?? null,
approvalTime: response.approvalTime ?? null
};
}
function normalizeStatusLog(
response: OvertimeApplicationStatusLogResponse
): Api.OvertimeApplication.OvertimeApplicationStatusLog {
return {
...response,
id: normalizeStringId(response.id),
applicationId: normalizeStringId(response.applicationId),
operatorUserId: normalizeStringId(response.operatorUserId),
overtimeDateSnapshot: normalizeProjectLocalDate(response.overtimeDateSnapshot) ?? '',
fromStatus: normalizeNullableStringId(response.fromStatus),
reason: response.reason ?? null,
remark: response.remark ?? null
};
}
function createPageQuery(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) {
const query = new URLSearchParams();
query.append('pageNo', String(params.pageNo ?? 1));
query.append('pageSize', String(params.pageSize ?? 10));
if (params.keyword) {
query.append('keyword', params.keyword);
}
if (params.applicantName) {
query.append('applicantName', params.applicantName);
}
if (params.approverId) {
query.append('approverId', params.approverId);
}
if (params.approverName) {
query.append('approverName', params.approverName);
}
if (params.statusCode) {
query.append('statusCode', params.statusCode);
}
params.overtimeDate?.forEach(item => {
if (item) {
query.append('overtimeDate', item);
}
});
params.createTime?.forEach(item => {
if (item) {
query.append('createTime', item);
}
});
return query.toString();
}
function toSaveRequest(data: Api.OvertimeApplication.SaveOvertimeApplicationParams) {
return {
overtimeDate: data.overtimeDate,
overtimeDuration: data.overtimeDuration,
overtimeReason: data.overtimeReason.trim(),
overtimeContent: data.overtimeContent.trim(),
approverId: data.approverId
};
}
function toStatusActionRequest(data: Api.OvertimeApplication.StatusActionParams = {}) {
return {
reason: data.reason?.trim() || undefined
};
}
export async function fetchGetOvertimeApplicationPage(
params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}
) {
const query = createPageQuery(params);
const result = await request<OvertimeApplicationPageResponse>({
...safeJsonRequestConfig,
url: query ? `${OVERTIME_APPLICATION_PREFIX}/page?${query}` : `${OVERTIME_APPLICATION_PREFIX}/page`,
method: 'get'
});
return mapServiceResult(result as ServiceRequestResult<OvertimeApplicationPageResponse>, data => ({
total: normalizeTotal(data.total),
list: data.list.map(normalizeOvertimeApplication)
}));
}
export async function fetchGetOvertimeApplicationApprovalPage(
params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}
) {
const query = createPageQuery(params);
const result = await request<OvertimeApplicationPageResponse>({
...safeJsonRequestConfig,
url: query
? `${OVERTIME_APPLICATION_PREFIX}/approval-page?${query}`
: `${OVERTIME_APPLICATION_PREFIX}/approval-page`,
method: 'get'
});
return mapServiceResult(result as ServiceRequestResult<OvertimeApplicationPageResponse>, data => ({
total: normalizeTotal(data.total),
list: data.list.map(normalizeOvertimeApplication)
}));
}
export async function fetchGetOvertimeApplicationDetail(id: string) {
const result = await request<OvertimeApplicationResponse>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}`,
method: 'get'
});
return mapServiceResult(result as ServiceRequestResult<OvertimeApplicationResponse>, normalizeOvertimeApplication);
}
export async function fetchCreateOvertimeApplication(data: Api.OvertimeApplication.SaveOvertimeApplicationParams) {
const result = await request<string | number>({
...safeJsonRequestConfig,
url: OVERTIME_APPLICATION_PREFIX,
method: 'post',
data: toSaveRequest(data)
});
return mapServiceResult(result as ServiceRequestResult<string | number>, normalizeStringId);
}
export function fetchUpdateRejectedOvertimeApplication(
id: string,
data: Api.OvertimeApplication.SaveOvertimeApplicationParams
) {
return request<boolean>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}`,
method: 'put',
data: toSaveRequest(data)
});
}
export function fetchApproveOvertimeApplication(id: string, data: Api.OvertimeApplication.StatusActionParams = {}) {
return request<boolean>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}/approve`,
method: 'post',
data: toStatusActionRequest(data)
});
}
export function fetchRejectOvertimeApplication(id: string, data: Api.OvertimeApplication.StatusActionParams) {
return request<boolean>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}/reject`,
method: 'post',
data: toStatusActionRequest(data)
});
}
export function fetchCancelOvertimeApplication(id: string, data: Api.OvertimeApplication.StatusActionParams) {
return request<boolean>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}/cancel`,
method: 'post',
data: toStatusActionRequest(data)
});
}
export function fetchDeleteOvertimeApplication(id: string) {
return request<boolean>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}`,
method: 'delete'
});
}
export async function fetchGetOvertimeApplicationStatusLogs(id: string) {
const result = await request<OvertimeApplicationStatusLogResponse[]>({
...safeJsonRequestConfig,
url: `${OVERTIME_APPLICATION_PREFIX}/${id}/status-logs`,
method: 'get'
});
return mapServiceResult(result as ServiceRequestResult<OvertimeApplicationStatusLogResponse[]>, data =>
data.map(normalizeStatusLog)
);
}
export function fetchExportOvertimeApplications(params: Api.OvertimeApplication.OvertimeApplicationSearchParams = {}) {
const query = createPageQuery(params);
return request<Blob, 'blob'>({
url: query ? `${OVERTIME_APPLICATION_PREFIX}/export?${query}` : `${OVERTIME_APPLICATION_PREFIX}/export`,
method: 'get',
responseType: 'blob'
});
}