R19/R20: 项目主域进 OA 并打通报销差旅周报待办
这个提交包含在:
@@ -0,0 +1,61 @@
|
||||
import { apiRequestData } from "./http";
|
||||
import type { ConfidentialityLevel, EmployeeBasic } from "./projects";
|
||||
|
||||
export type ContractRegistryItem = {
|
||||
id: string;
|
||||
contractNo: string;
|
||||
projectId: string | null;
|
||||
counterpartyName: string;
|
||||
summary: string;
|
||||
confidentialityLevel: ConfidentialityLevel;
|
||||
archiveLocation: string;
|
||||
offlineArchiveNo: string | null;
|
||||
ownerEmployeeId: string;
|
||||
status: string;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
owner: EmployeeBasic | null;
|
||||
project: { id: string; projectNo: string; name: string } | null;
|
||||
};
|
||||
|
||||
export async function fetchContractsRegistry(projectId?: string) {
|
||||
const suffix = projectId ? `?projectId=${encodeURIComponent(projectId)}` : "";
|
||||
return apiRequestData<{ items: ContractRegistryItem[] }>(`/api/contracts-registry${suffix}`);
|
||||
}
|
||||
|
||||
export async function createContractRegistry(payload: {
|
||||
contractNo: string;
|
||||
projectId?: string | null;
|
||||
counterpartyName: string;
|
||||
summary: string;
|
||||
confidentialityLevel?: ConfidentialityLevel;
|
||||
archiveLocation: string;
|
||||
offlineArchiveNo?: string | null;
|
||||
ownerEmployeeId?: string;
|
||||
status?: string;
|
||||
}) {
|
||||
return apiRequestData<{ item: ContractRegistryItem }>("/api/contracts-registry", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchContractRegistry(
|
||||
id: string,
|
||||
payload: Partial<{
|
||||
contractNo: string;
|
||||
projectId: string | null;
|
||||
counterpartyName: string;
|
||||
summary: string;
|
||||
confidentialityLevel: ConfidentialityLevel;
|
||||
archiveLocation: string;
|
||||
offlineArchiveNo: string | null;
|
||||
ownerEmployeeId: string;
|
||||
status: string;
|
||||
}>,
|
||||
) {
|
||||
return apiRequestData<{ item: ContractRegistryItem }>(`/api/contracts-registry/${id}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,443 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type ProjectStatus = "draft" | "active" | "paused" | "completed" | "archived";
|
||||
export type ProjectRole = "owner" | "manager" | "member" | "observer";
|
||||
export type ProjectMilestoneStatus = "pending" | "in_progress" | "done" | "delayed" | "cancelled";
|
||||
export type ProjectTaskStatus = "todo" | "doing" | "blocked" | "done" | "cancelled";
|
||||
export type ProjectTaskPriority = "low" | "normal" | "high" | "urgent";
|
||||
export type ProjectRiskLevel = "low" | "medium" | "high";
|
||||
export type ProjectDeliveryRecordType = "kickoff" | "onsite" | "stage_acceptance" | "final_acceptance" | "handover";
|
||||
export type ConfidentialityLevel = "public" | "internal" | "confidential" | "restricted";
|
||||
export type DocumentStorageType = "oa_link" | "nas" | "internal_share" | "offline_archive";
|
||||
|
||||
export type EmployeeBasic = {
|
||||
id: string;
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export type ProjectListItem = {
|
||||
id: string;
|
||||
projectNo: string;
|
||||
name: string;
|
||||
clientName: string;
|
||||
clientAlias: string | null;
|
||||
status: ProjectStatus;
|
||||
startsAt: string | null;
|
||||
targetEndAt: string | null;
|
||||
actualEndAt: string | null;
|
||||
summary: string | null;
|
||||
isConfidential: boolean;
|
||||
owner: EmployeeBasic | null;
|
||||
manager: EmployeeBasic | null;
|
||||
counts: {
|
||||
members: number;
|
||||
milestones: number;
|
||||
tasks: number;
|
||||
risks: number;
|
||||
overdueMilestones: number;
|
||||
highPriorityTasks: number;
|
||||
openRisks: number;
|
||||
};
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type ProjectMember = {
|
||||
id: string;
|
||||
employeeId: string;
|
||||
role: ProjectRole;
|
||||
joinedAt: string | null;
|
||||
leftAt: string | null;
|
||||
employee: EmployeeBasic | null;
|
||||
};
|
||||
|
||||
export type ProjectMilestone = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
status: ProjectMilestoneStatus;
|
||||
dueDate: string | null;
|
||||
completedAt: string | null;
|
||||
ownerEmployeeId: string | null;
|
||||
sortOrder: number;
|
||||
};
|
||||
|
||||
export type ProjectTask = {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string | null;
|
||||
status: ProjectTaskStatus;
|
||||
priority: ProjectTaskPriority;
|
||||
assigneeEmployeeId: string | null;
|
||||
dueDate: string | null;
|
||||
blockedReason: string | null;
|
||||
createdBy: string;
|
||||
assignee: EmployeeBasic | null;
|
||||
creator: EmployeeBasic | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type ProjectRisk = {
|
||||
id: string;
|
||||
title: string;
|
||||
detail: string;
|
||||
level: ProjectRiskLevel;
|
||||
status: string;
|
||||
ownerEmployeeId: string | null;
|
||||
owner: EmployeeBasic | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type ProjectDetail = {
|
||||
id: string;
|
||||
projectNo: string;
|
||||
name: string;
|
||||
clientName: string;
|
||||
clientAlias: string | null;
|
||||
ownerEmployeeId: string;
|
||||
managerEmployeeId: string | null;
|
||||
status: ProjectStatus;
|
||||
startsAt: string | null;
|
||||
targetEndAt: string | null;
|
||||
actualEndAt: string | null;
|
||||
summary: string | null;
|
||||
isConfidential: boolean;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
owner: EmployeeBasic | null;
|
||||
manager: EmployeeBasic | null;
|
||||
counts: {
|
||||
members: number;
|
||||
milestones: number;
|
||||
tasks: number;
|
||||
risks: number;
|
||||
reimbursements: number;
|
||||
travelRequests: number;
|
||||
todoItems: number;
|
||||
weeklyReports: number;
|
||||
contracts: number;
|
||||
deliveries: number;
|
||||
documentRefs: number;
|
||||
};
|
||||
members: ProjectMember[];
|
||||
milestones: ProjectMilestone[];
|
||||
tasks: ProjectTask[];
|
||||
risks: ProjectRisk[];
|
||||
};
|
||||
|
||||
export type ProjectExpenseSummary = {
|
||||
totalAmount: string;
|
||||
items: Array<{
|
||||
id: string;
|
||||
formNumber: string;
|
||||
status: string;
|
||||
totalAmount: string;
|
||||
reimbursementDate: string | null;
|
||||
updatedAt: string | null;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type ProjectTravelSummary = {
|
||||
totalAmount: string;
|
||||
items: Array<{
|
||||
id: string;
|
||||
requestNo: string;
|
||||
status: string;
|
||||
estimatedAmount: string;
|
||||
startDate: string | null;
|
||||
endDate: string | null;
|
||||
updatedAt: string | null;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type ProjectWeeklyReportLink = {
|
||||
id: string;
|
||||
weeklyReportId: string;
|
||||
weekStart: string | null;
|
||||
status: "draft" | "submitted";
|
||||
employee: EmployeeBasic | null;
|
||||
progressText: string | null;
|
||||
riskText: string | null;
|
||||
nextStepText: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
export type ProjectDeliveryRecord = {
|
||||
id: string;
|
||||
title: string;
|
||||
recordType: ProjectDeliveryRecordType;
|
||||
summary: string;
|
||||
occurredAt: string | null;
|
||||
owner: EmployeeBasic | null;
|
||||
createdAt: string | null;
|
||||
};
|
||||
|
||||
export type ConfidentialDocumentRef = {
|
||||
id: string;
|
||||
title: string;
|
||||
documentNo: string | null;
|
||||
confidentialityLevel: ConfidentialityLevel;
|
||||
storageType: DocumentStorageType;
|
||||
storagePath: string;
|
||||
offlineArchiveNo: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
|
||||
function toQueryString(query: Record<string, string | number | 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") : String(value));
|
||||
}
|
||||
const encoded = params.toString();
|
||||
return encoded ? `?${encoded}` : "";
|
||||
}
|
||||
|
||||
export async function fetchProjects(params: {
|
||||
status?: ProjectStatus;
|
||||
mine?: boolean;
|
||||
q?: string;
|
||||
} = {}) {
|
||||
return apiRequestData<{ items: ProjectListItem[] }>(`/api/projects${toQueryString(params)}`);
|
||||
}
|
||||
|
||||
export async function createProject(payload: {
|
||||
projectNo?: string;
|
||||
name: string;
|
||||
clientName: string;
|
||||
clientAlias?: string | null;
|
||||
ownerEmployeeId?: string;
|
||||
managerEmployeeId?: string | null;
|
||||
status?: ProjectStatus;
|
||||
startsAt?: string | null;
|
||||
targetEndAt?: string | null;
|
||||
actualEndAt?: string | null;
|
||||
summary?: string | null;
|
||||
isConfidential?: boolean;
|
||||
}) {
|
||||
return apiRequestData<{ item: ProjectDetail }>("/api/projects", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProject(projectId: string) {
|
||||
return apiRequestData<{ item: ProjectDetail }>(`/api/projects/${projectId}`);
|
||||
}
|
||||
|
||||
export async function patchProject(
|
||||
projectId: string,
|
||||
payload: Partial<{
|
||||
projectNo: string;
|
||||
name: string;
|
||||
clientName: string;
|
||||
clientAlias: string | null;
|
||||
ownerEmployeeId: string;
|
||||
managerEmployeeId: string | null;
|
||||
status: ProjectStatus;
|
||||
startsAt: string | null;
|
||||
targetEndAt: string | null;
|
||||
actualEndAt: string | null;
|
||||
summary: string | null;
|
||||
isConfidential: boolean;
|
||||
}>,
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectDetail }>(`/api/projects/${projectId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function archiveProject(projectId: string) {
|
||||
return apiRequestData<{ item: { id: string; status: ProjectStatus } }>(`/api/projects/${projectId}/archive`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectMembers(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectMember[] }>(`/api/projects/${projectId}/members`);
|
||||
}
|
||||
|
||||
export async function createProjectMember(projectId: string, payload: { employeeId: string; role?: ProjectRole }) {
|
||||
return apiRequestData<{ item: ProjectMember }>(`/api/projects/${projectId}/members`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchProjectMember(
|
||||
projectId: string,
|
||||
memberId: string,
|
||||
payload: Partial<{ role: ProjectRole; leftAt: string | null }>,
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectMember }>(`/api/projects/${projectId}/members/${memberId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectMilestones(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectMilestone[] }>(`/api/projects/${projectId}/milestones`);
|
||||
}
|
||||
|
||||
export async function createProjectMilestone(
|
||||
projectId: string,
|
||||
payload: {
|
||||
title: string;
|
||||
description?: string | null;
|
||||
status?: ProjectMilestoneStatus;
|
||||
dueDate?: string | null;
|
||||
completedAt?: string | null;
|
||||
ownerEmployeeId?: string | null;
|
||||
sortOrder?: number;
|
||||
},
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectMilestone }>(`/api/projects/${projectId}/milestones`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchProjectMilestone(
|
||||
projectId: string,
|
||||
milestoneId: string,
|
||||
payload: Partial<{
|
||||
title: string;
|
||||
description: string | null;
|
||||
status: ProjectMilestoneStatus;
|
||||
dueDate: string | null;
|
||||
completedAt: string | null;
|
||||
ownerEmployeeId: string | null;
|
||||
sortOrder: number;
|
||||
}>,
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectMilestone }>(`/api/projects/${projectId}/milestones/${milestoneId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectTasks(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectTask[] }>(`/api/projects/${projectId}/tasks`);
|
||||
}
|
||||
|
||||
export async function createProjectTask(
|
||||
projectId: string,
|
||||
payload: {
|
||||
title: string;
|
||||
description?: string | null;
|
||||
status?: ProjectTaskStatus;
|
||||
priority?: ProjectTaskPriority;
|
||||
assigneeEmployeeId?: string | null;
|
||||
dueDate?: string | null;
|
||||
blockedReason?: string | null;
|
||||
},
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectTask }>(`/api/projects/${projectId}/tasks`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchProjectTask(
|
||||
projectId: string,
|
||||
taskId: string,
|
||||
payload: Partial<{
|
||||
title: string;
|
||||
description: string | null;
|
||||
status: ProjectTaskStatus;
|
||||
priority: ProjectTaskPriority;
|
||||
assigneeEmployeeId: string | null;
|
||||
dueDate: string | null;
|
||||
blockedReason: string | null;
|
||||
}>,
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectTask }>(`/api/projects/${projectId}/tasks/${taskId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectRisks(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectRisk[] }>(`/api/projects/${projectId}/risks`);
|
||||
}
|
||||
|
||||
export async function createProjectRisk(
|
||||
projectId: string,
|
||||
payload: { title: string; detail: string; level?: ProjectRiskLevel; status?: string; ownerEmployeeId?: string | null },
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectRisk }>(`/api/projects/${projectId}/risks`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchProjectRisk(
|
||||
projectId: string,
|
||||
riskId: string,
|
||||
payload: Partial<{ title: string; detail: string; level: ProjectRiskLevel; status: string; ownerEmployeeId: string | null }>,
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectRisk }>(`/api/projects/${projectId}/risks/${riskId}`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectExpensesSummary(projectId: string) {
|
||||
return apiRequestData<ProjectExpenseSummary>(`/api/projects/${projectId}/expenses/summary`);
|
||||
}
|
||||
|
||||
export async function fetchProjectTravelSummary(projectId: string) {
|
||||
return apiRequestData<ProjectTravelSummary>(`/api/projects/${projectId}/travel/summary`);
|
||||
}
|
||||
|
||||
export async function fetchProjectWeeklyReports(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectWeeklyReportLink[] }>(`/api/projects/${projectId}/weekly-reports`);
|
||||
}
|
||||
|
||||
export async function fetchProjectDeliveries(projectId: string) {
|
||||
return apiRequestData<{ items: ProjectDeliveryRecord[] }>(`/api/projects/${projectId}/deliveries`);
|
||||
}
|
||||
|
||||
export async function createProjectDelivery(
|
||||
projectId: string,
|
||||
payload: {
|
||||
title: string;
|
||||
recordType: ProjectDeliveryRecordType;
|
||||
summary: string;
|
||||
occurredAt: string;
|
||||
ownerEmployeeId?: string;
|
||||
},
|
||||
) {
|
||||
return apiRequestData<{ item: ProjectDeliveryRecord }>(`/api/projects/${projectId}/deliveries`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchProjectDocumentRefs(projectId: string) {
|
||||
return apiRequestData<{ items: ConfidentialDocumentRef[] }>(`/api/projects/${projectId}/document-refs`);
|
||||
}
|
||||
|
||||
export async function createConfidentialDocumentRef(payload: {
|
||||
projectId?: string | null;
|
||||
contractRegistryId?: string | null;
|
||||
title: string;
|
||||
documentNo?: string | null;
|
||||
confidentialityLevel?: ConfidentialityLevel;
|
||||
storageType: DocumentStorageType;
|
||||
storagePath: string;
|
||||
offlineArchiveNo?: string | null;
|
||||
ownerEmployeeId?: string;
|
||||
accessRuleJson?: Record<string, unknown> | null;
|
||||
}) {
|
||||
return apiRequestData<{ item: ConfidentialDocumentRef & { owner?: EmployeeBasic | null; project?: { id: string; projectNo: string; name: string } | null; contractRegistry?: { id: string; contractNo: string } | null } }>("/api/confidential-doc-refs", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
@@ -48,6 +48,11 @@ export type ReimbursementListItem = {
|
||||
employeeNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
project: {
|
||||
id: string;
|
||||
projectNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
};
|
||||
@@ -86,6 +91,12 @@ export type ReimbursementDetail = {
|
||||
reimbursementDate: string | null;
|
||||
totalAmount: string | null;
|
||||
description: string | null;
|
||||
projectId: string | null;
|
||||
project: {
|
||||
id: string;
|
||||
projectNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
owner: {
|
||||
id: string;
|
||||
employee_no: string;
|
||||
@@ -270,3 +281,11 @@ export async function deleteReimbursementItem(reimbursementId: string, itemId: s
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
export async function linkReimbursementProject(reimbursementId: string, projectId: string | null) {
|
||||
return apiRequestData<{ projectId: string | null; project: { id: string; projectNo: string; name: string } | null }>(`/api/reimbursements/${reimbursementId}/link-project`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ projectId }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ export type TodoItem = {
|
||||
priority: TodoPriority;
|
||||
status: TodoStatus;
|
||||
source: TodoSource;
|
||||
projectId: string | null;
|
||||
project: { id: string; projectNo: string; name: string } | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
completedAt: string | null;
|
||||
@@ -43,6 +45,7 @@ export async function createTodo(payload: {
|
||||
dueDate?: string | null;
|
||||
priority?: TodoPriority;
|
||||
source?: TodoSource;
|
||||
projectId?: string | null;
|
||||
}) {
|
||||
return apiRequestData<{ item: TodoItem }>("/api/todos", {
|
||||
method: "POST",
|
||||
@@ -57,6 +60,7 @@ export async function patchTodo(id: string, payload: Partial<{
|
||||
dueDate: string | null;
|
||||
priority: TodoPriority;
|
||||
status: TodoStatus;
|
||||
projectId: string | null;
|
||||
}>) {
|
||||
return apiRequestData<{ item: TodoItem }>(`/api/todos/${id}`, {
|
||||
method: "PATCH",
|
||||
|
||||
@@ -20,6 +20,12 @@ export type TravelRequestSummary = {
|
||||
startDate: string | null;
|
||||
endDate: string | null;
|
||||
estimatedAmount: string;
|
||||
projectId: string | null;
|
||||
project: {
|
||||
id: string;
|
||||
projectNo: string;
|
||||
name: string;
|
||||
} | null;
|
||||
status: TravelRequestStatus;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
@@ -233,3 +239,11 @@ export async function withdrawTravelRequest(travelRequestId: string) {
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export async function linkTravelRequestProject(travelRequestId: string, projectId: string | null) {
|
||||
return apiRequestData<{ projectId: string | null; project: { id: string; projectNo: string; name: string } | null }>(`/api/travel-requests/${travelRequestId}/link-project`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ projectId }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -32,6 +32,10 @@ export type MeResponse = {
|
||||
directManagerId: string | null;
|
||||
status: string;
|
||||
roleCodes: string[];
|
||||
wecomBinding?: {
|
||||
externalUserId: string;
|
||||
createdAt: string | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
export type AuthState = {
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { apiRequestData } from "./http";
|
||||
|
||||
export type WeeklyReportProjectLink = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
progressText: string | null;
|
||||
riskText: string | null;
|
||||
nextStepText: string | null;
|
||||
project: { id: string; projectNo: string; name: string } | null;
|
||||
};
|
||||
|
||||
export type WeeklyReport = {
|
||||
id: string;
|
||||
employeeId: string;
|
||||
@@ -12,6 +21,7 @@ export type WeeklyReport = {
|
||||
submittedAt: string | null;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
projectLinks: WeeklyReportProjectLink[];
|
||||
};
|
||||
|
||||
export type WeeklyReportTeamItem = {
|
||||
@@ -44,6 +54,7 @@ export async function updateMyWeeklyReport(payload: {
|
||||
blockersText?: string;
|
||||
nextWeekText?: string;
|
||||
needsHelp?: boolean;
|
||||
projectLinks?: Array<{ projectId: string; progressText?: string; riskText?: string; nextStepText?: string }>;
|
||||
}) {
|
||||
return apiRequestData<{ item: WeeklyReport }>("/api/weekly-reports/me", {
|
||||
method: "PUT",
|
||||
|
||||
在新工单中引用
屏蔽一个用户