feat(projects): 新增项目、执行、任务等功能

This commit is contained in:
2026-05-09 11:30:34 +08:00
parent f4f43814b3
commit 824392b564
106 changed files with 13060 additions and 1049 deletions

View File

@@ -17,13 +17,20 @@ export type ProductActivityFilterType = 'all' | Api.Product.ProductActivityType;
export type ProductActivityTone = 'sky' | 'emerald' | 'amber' | 'rose' | 'slate';
export interface ProductActivityTextPart {
text: string;
strong?: boolean;
}
export interface ProductActivityDisplayItem extends Api.Product.ProductActivityTimelineItem {
tagLabel: string;
timeText: string;
actionText: string;
displaySummary: string;
compactText: string;
compactTextParts: ProductActivityTextPart[];
operatorText: string;
subjectText: string;
reasonText: string;
statusTransition: string;
tone: ProductActivityTone;
@@ -250,6 +257,10 @@ function isGenericActivitySummary(summaryText: string, actionText: string) {
return summaryText === actionText || summaryText === actionText.replace('执行了', '执行了');
}
function isMemberActivityAction(actionType: Api.Product.ProductActivityActionType) {
return actionType === 'add_member' || actionType === 'remove_member' || actionType === 'update_member';
}
function buildMemberChangeSummary(
item: Api.Product.ProductActivityTimelineItem,
detailsRecord: ActivityDetailRecord | null,
@@ -263,9 +274,10 @@ function buildMemberChangeSummary(
}
const memberDetail = roleName ? `${memberName}${roleName}` : memberName;
const actionLabel = item.actionType === 'add_member' ? '将成员加入产品' : '将成员移出产品';
return operatorText === '--' ? `${actionLabel}${memberDetail}` : `${operatorText}${actionLabel}${memberDetail}`;
return operatorText === '--'
? `执行了【${item.actionName}】:${memberDetail}`
: `${operatorText}执行了【${item.actionName}】:${memberDetail}`;
}
function buildMemberUpdateSummary(
@@ -279,8 +291,8 @@ function buildMemberUpdateSummary(
const roleText = roleTransitionText ? `,角色:${roleTransitionText}` : '';
return operatorText === '--'
? `调整成员${memberText}${roleText}`
: `${operatorText}调整成员${memberText}${roleText}`;
? `执行了【${item.actionName}${memberText}${roleText}`
: `${operatorText}执行了【${item.actionName}${memberText}${roleText}`;
}
function buildManagerChangeSummary(detailsRecord: ActivityDetailRecord | null, operatorText: string) {
@@ -309,15 +321,11 @@ function buildManagerChangeSummary(detailsRecord: ActivityDetailRecord | null, o
function resolveDetailedSummary(
item: Api.Product.ProductActivityTimelineItem,
operatorText: string,
actionText: string
detailsRecord: ActivityDetailRecord | null,
texts: { operatorText: string; actionText: string }
) {
const { operatorText, actionText } = texts;
const summaryText = item.summary?.trim() || '';
const detailsRecord = parseActivityDetails(item.details);
if (!isGenericActivitySummary(summaryText, actionText)) {
return summaryText;
}
if (item.actionType === 'add_member' || item.actionType === 'remove_member') {
return buildMemberChangeSummary(item, detailsRecord, operatorText) || summaryText || actionText;
@@ -327,6 +335,10 @@ function resolveDetailedSummary(
return buildMemberUpdateSummary(item, detailsRecord, operatorText);
}
if (!isGenericActivitySummary(summaryText, actionText)) {
return summaryText;
}
if (item.actionType === 'change_manager') {
return buildManagerChangeSummary(detailsRecord, operatorText) || summaryText || actionText;
}
@@ -334,13 +346,31 @@ function resolveDetailedSummary(
return summaryText || actionText;
}
function buildProductActivityTextParts(text: string, subjectText: string): ProductActivityTextPart[] {
const normalizedSubject = subjectText.trim();
const subjectIndex = normalizedSubject ? text.indexOf(normalizedSubject) : -1;
if (subjectIndex < 0) {
return [{ text }];
}
return [
{ text: text.slice(0, subjectIndex) },
{ text: normalizedSubject, strong: true },
{ text: text.slice(subjectIndex + normalizedSubject.length) }
].filter(part => part.text);
}
export function buildProductActivityDisplayItem(
item: Api.Product.ProductActivityTimelineItem
): ProductActivityDisplayItem {
const operatorText = item.operatorName?.trim() || '--';
const actionText =
operatorText === '--' ? `执行了【${item.actionName}` : `${operatorText}执行了【${item.actionName}`;
const displaySummary = item.type === 'status' ? actionText : resolveDetailedSummary(item, operatorText, actionText);
const detailsRecord = parseActivityDetails(item.details);
const subjectText = isMemberActivityAction(item.actionType) ? getActivityTargetUserName(item, detailsRecord) : '';
const displaySummary =
item.type === 'status' ? actionText : resolveDetailedSummary(item, detailsRecord, { operatorText, actionText });
const compactText = displaySummary;
return {
@@ -350,7 +380,9 @@ export function buildProductActivityDisplayItem(
actionText,
displaySummary,
compactText,
compactTextParts: buildProductActivityTextParts(compactText, subjectText),
operatorText,
subjectText,
reasonText: item.reason?.trim() || '',
statusTransition:
item.type === 'status' && item.fromStatus && item.toStatus