feat(P18A-3,P18A-4): 实现资产台账接口与页面入口
这个提交包含在:
@@ -0,0 +1,196 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type AssetStatus = "in_stock" | "in_use" | "under_repair" | "retired" | "archived";
|
||||
|
||||
export type AssetCategoryItem = {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
documentCategoryId: string | null;
|
||||
enabled: boolean;
|
||||
archivedAt: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
documentCategory: {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
entityType: string;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type AssetAssigneeOption = {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
department: {
|
||||
id: string;
|
||||
name: string;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type AssetItem = {
|
||||
id: string;
|
||||
assetNo: string;
|
||||
name: string;
|
||||
categoryId: string;
|
||||
legalEntityId: string;
|
||||
costCenterId: string;
|
||||
purchaseRequestId: string | null;
|
||||
serialNo: string | null;
|
||||
location: string | null;
|
||||
status: AssetStatus;
|
||||
assigneeEmployeeId: string | null;
|
||||
activatedAt: string | null;
|
||||
retiredAt: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
category: {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
documentCategoryId: string | null;
|
||||
documentCategory: {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
} | null;
|
||||
} | null;
|
||||
legalEntity: {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
} | null;
|
||||
costCenter: {
|
||||
id: string;
|
||||
code: string;
|
||||
name: string;
|
||||
legalEntityId: string;
|
||||
} | null;
|
||||
purchaseRequest: {
|
||||
id: string;
|
||||
requestNo: string | null;
|
||||
title: string;
|
||||
status: string;
|
||||
} | null;
|
||||
assignee: {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
department: {
|
||||
id: string;
|
||||
name: string;
|
||||
} | null;
|
||||
} | null;
|
||||
permissions: {
|
||||
canEdit: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type AssetCategoryListResponse = {
|
||||
includeArchived: boolean;
|
||||
items: AssetCategoryItem[];
|
||||
};
|
||||
|
||||
export type AssetListResponse = {
|
||||
mine: boolean;
|
||||
items: AssetItem[];
|
||||
};
|
||||
|
||||
export type AssetListQuery = {
|
||||
status?: AssetStatus;
|
||||
categoryId?: string;
|
||||
assigneeId?: string;
|
||||
legalEntityId?: string;
|
||||
costCenterId?: string;
|
||||
mine?: boolean;
|
||||
};
|
||||
|
||||
export type AssetPayload = {
|
||||
name: string;
|
||||
categoryId: string;
|
||||
legalEntityId: string;
|
||||
costCenterId: string;
|
||||
purchaseRequestId?: string | null;
|
||||
serialNo?: string | null;
|
||||
location?: string | null;
|
||||
status?: AssetStatus;
|
||||
assigneeEmployeeId?: string | null;
|
||||
activatedAt?: string | null;
|
||||
retiredAt?: string | null;
|
||||
};
|
||||
|
||||
function toQueryString(query: Record<string, string | boolean | undefined>) {
|
||||
const params = new URLSearchParams();
|
||||
for (const [key, value] of Object.entries(query)) {
|
||||
if (value == null || value === "") {
|
||||
continue;
|
||||
}
|
||||
params.set(key, typeof value === "boolean" ? (value ? "1" : "0") : value);
|
||||
}
|
||||
const encoded = params.toString();
|
||||
return encoded ? `?${encoded}` : "";
|
||||
}
|
||||
|
||||
export async function fetchAssetCategories(params: { includeArchived?: boolean; enabled?: boolean } = {}) {
|
||||
return apiRequestData<AssetCategoryListResponse>(
|
||||
`/api/asset-categories${toQueryString(params as Record<string, string | boolean | undefined>)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function createAssetCategory(payload: {
|
||||
code: string;
|
||||
name: string;
|
||||
documentCategoryId?: string | null;
|
||||
enabled?: boolean;
|
||||
}) {
|
||||
return apiRequestData<{ assetCategory: AssetCategoryItem }>("/api/asset-categories", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchAssetCategory(
|
||||
assetCategoryId: string,
|
||||
payload: Partial<{
|
||||
code: string;
|
||||
name: string;
|
||||
documentCategoryId: string | null;
|
||||
enabled: boolean;
|
||||
}>,
|
||||
) {
|
||||
return apiRequestData<{ assetCategory: AssetCategoryItem }>(`/api/asset-categories/${assetCategoryId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchAssetAssignees(params: { q?: string } = {}) {
|
||||
return apiRequestData<{ items: AssetAssigneeOption[] }>(
|
||||
`/api/assets/assignees${toQueryString(params as Record<string, string | boolean | undefined>)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchAssets(params: AssetListQuery = {}) {
|
||||
return apiRequestData<AssetListResponse>(
|
||||
`/api/assets${toQueryString(params as Record<string, string | boolean | undefined>)}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchAssetDetail(assetId: string) {
|
||||
return apiRequestData<{ asset: AssetItem }>(`/api/assets/${assetId}`);
|
||||
}
|
||||
|
||||
export async function createAsset(payload: AssetPayload) {
|
||||
return apiRequestData<{ asset: AssetItem }>("/api/assets", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchAsset(assetId: string, payload: Partial<Omit<AssetPayload, "purchaseRequestId">>) {
|
||||
return apiRequestData<{ asset: AssetItem }>(`/api/assets/${assetId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户