feat(新增加班申请功能): 新增申请功能,可在工作台进行审核。
fix(dict_data): 在字典数据新增、编辑时可以操作颜色类型字段(color_type)。
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { SYSTEM_SERVICE_PREFIX } from '@/constants/service';
|
||||
import { request } from '../request';
|
||||
import { type ServiceRequestResult, mapServiceResult } from './shared';
|
||||
|
||||
const DICT_TYPE_PREFIX = `${SYSTEM_SERVICE_PREFIX}/dict-type`;
|
||||
const DICT_DATA_PREFIX = `${SYSTEM_SERVICE_PREFIX}/dict-data`;
|
||||
@@ -15,6 +16,52 @@ function createBatchDeleteQuery(ids: number[]) {
|
||||
return query.toString();
|
||||
}
|
||||
|
||||
type DictDataResponse = Omit<Api.Dict.DictData, 'colorType'> & {
|
||||
colorType?: string | null;
|
||||
color_type?: string | null;
|
||||
};
|
||||
|
||||
type DictDataPageResponse = Omit<Api.Dict.PageResult<Api.Dict.DictData>, 'list'> & {
|
||||
list: DictDataResponse[];
|
||||
};
|
||||
|
||||
type FrontendDictDataResponse = Omit<Api.Dict.FrontendDictData, 'colorType'> & {
|
||||
colorType?: string | null;
|
||||
color_type?: string | null;
|
||||
};
|
||||
|
||||
type FrontendDictCacheResponse = Record<string, FrontendDictDataResponse[]>;
|
||||
|
||||
function normalizeColorType(value?: string | null) {
|
||||
return value?.trim() || null;
|
||||
}
|
||||
|
||||
function normalizeDictData(data: DictDataResponse): Api.Dict.DictData {
|
||||
const { color_type: colorTypeFromSnakeCase, ...rest } = data;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
colorType: normalizeColorType(data.colorType ?? colorTypeFromSnakeCase)
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeFrontendDictData(data: FrontendDictDataResponse): Api.Dict.FrontendDictData {
|
||||
const { color_type: colorTypeFromSnakeCase, ...rest } = data;
|
||||
|
||||
return {
|
||||
...rest,
|
||||
colorType: normalizeColorType(data.colorType ?? colorTypeFromSnakeCase)
|
||||
};
|
||||
}
|
||||
|
||||
function toSaveDictDataRequest(data: Api.Dict.SaveDictDataParams) {
|
||||
return {
|
||||
...data,
|
||||
colorType: normalizeColorType(data.colorType),
|
||||
remark: data.remark?.trim() || null
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取字典类型分页 */
|
||||
export function fetchGetDictTypePage(params?: Api.Dict.DictTypeSearchParams) {
|
||||
return request<Api.Dict.PageResult<Api.Dict.DictType>>({
|
||||
@@ -60,20 +107,40 @@ export function fetchBatchDeleteDictType(ids: number[]) {
|
||||
}
|
||||
|
||||
/** 获取字典数据分页 */
|
||||
export function fetchGetDictDataPage(params: Api.Dict.DictDataSearchParams) {
|
||||
return request<Api.Dict.PageResult<Api.Dict.DictData>>({
|
||||
export async function fetchGetDictDataPage(params: Api.Dict.DictDataSearchParams) {
|
||||
const result = await request<DictDataPageResponse>({
|
||||
url: `${DICT_DATA_PREFIX}/page`,
|
||||
method: 'get',
|
||||
params
|
||||
});
|
||||
|
||||
if (result.error || !result.data) {
|
||||
return result as unknown as Awaited<ReturnType<typeof request<Api.Dict.PageResult<Api.Dict.DictData>>>>;
|
||||
}
|
||||
|
||||
return {
|
||||
...result,
|
||||
data: {
|
||||
...result.data,
|
||||
list: result.data.list.map(normalizeDictData)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** 获取前端运行时字典缓存 */
|
||||
export function fetchGetFrontendDictCache() {
|
||||
return request<Api.Dict.FrontendDictCache>({
|
||||
export async function fetchGetFrontendDictCache() {
|
||||
const result = await request<FrontendDictCacheResponse>({
|
||||
url: `${DICT_DATA_PREFIX}/frontend-cache`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
return mapServiceResult(
|
||||
result as ServiceRequestResult<FrontendDictCacheResponse>,
|
||||
data =>
|
||||
Object.fromEntries(
|
||||
Object.entries(data).map(([dictType, list]) => [dictType, list.map(normalizeFrontendDictData)])
|
||||
) as Api.Dict.FrontendDictCache
|
||||
);
|
||||
}
|
||||
|
||||
/** 创建字典数据 */
|
||||
@@ -81,7 +148,7 @@ export function fetchCreateDictData(data: Api.Dict.SaveDictDataParams) {
|
||||
return request<number>({
|
||||
url: `${DICT_DATA_PREFIX}/create`,
|
||||
method: 'post',
|
||||
data
|
||||
data: toSaveDictDataRequest(data)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -90,7 +157,7 @@ export function fetchUpdateDictData(data: { id: number } & Api.Dict.SaveDictData
|
||||
return request<boolean>({
|
||||
url: `${DICT_DATA_PREFIX}/update`,
|
||||
method: 'put',
|
||||
data
|
||||
data: toSaveDictDataRequest(data)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,9 +179,14 @@ export function fetchBatchDeleteDictData(ids: number[]) {
|
||||
}
|
||||
|
||||
/** 通过岗位编码获取该字典的所有字典数据 */
|
||||
export function fetchGetDictDataByCode(code: string) {
|
||||
return request<Api.Dict.PageResult<Api.Dict.DictData>>({
|
||||
export async function fetchGetDictDataByCode(code: string) {
|
||||
const result = await request<DictDataPageResponse>({
|
||||
url: `${DICT_DATA_PREFIX}/code?code=${code}`,
|
||||
method: 'get'
|
||||
});
|
||||
|
||||
return mapServiceResult(result as ServiceRequestResult<DictDataPageResponse>, data => ({
|
||||
...data,
|
||||
list: data.list.map(normalizeDictData)
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from './dict';
|
||||
export * from './file';
|
||||
export * from './infra';
|
||||
export * from './object-context';
|
||||
export * from './overtime-application';
|
||||
export * from './personal-item';
|
||||
export * from './product';
|
||||
export * from './project';
|
||||
|
||||
280
src/service/api/overtime-application.ts
Normal file
280
src/service/api/overtime-application.ts
Normal 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'
|
||||
});
|
||||
}
|
||||
@@ -455,6 +455,19 @@ export async function fetchGetUserSimpleList() {
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取当前登录人的直属上级 */
|
||||
export async function fetchGetLoginUserDirectManager() {
|
||||
return request<UserSimpleResponse | null>({
|
||||
...safeJsonRequestConfig,
|
||||
url: `${USER_PREFIX}/profile/direct-manager`,
|
||||
method: 'get'
|
||||
}).then(result =>
|
||||
mapServiceResult(result as ServiceRequestResult<UserSimpleResponse | null>, data =>
|
||||
data ? normalizeUserSimple(data) : null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/** 获取用户分页 */
|
||||
export function fetchGetUserPage(params?: Api.SystemManage.UserSearchParams) {
|
||||
return request<Api.SystemManage.UserList>({
|
||||
|
||||
Reference in New Issue
Block a user