fix(oa-board): stabilize filter and stage sync
This commit is contained in:
parent
8cc0dc5218
commit
9c696e1947
@ -298,7 +298,7 @@ export async function GET(request: NextRequest) {
|
||||
salesBrands: item.formSummary.salesBrands || '',
|
||||
spu: item.formSummary.spu || item.spu || '',
|
||||
openingBrand: item.formSummary.openingBrand || '',
|
||||
creatorLabel: item.originatorDeptName || item.boardKeyType || '',
|
||||
creatorLabel: item.originatorUserName || '',
|
||||
overallTargetHours: item.overallTargetHours ?? '',
|
||||
overallActualHours: item.overallActualHours ?? '',
|
||||
isOvertime: item.overallTimeoutFlag ? '是' : '否',
|
||||
|
||||
@ -274,8 +274,7 @@ function readMetricValue(
|
||||
}
|
||||
|
||||
function readCreatorDisplay(item: OaBoardProjectListItemDTO) {
|
||||
const initiator = item.nodeAssessments.find((node) => node.nodeName.includes('发起'))?.ownerLabel
|
||||
return initiator || item.originatorDeptName || item.boardKeyType || '-'
|
||||
return item.originatorUserName || '-'
|
||||
}
|
||||
|
||||
function buildTimingDetailFields(item: OaBoardProjectListItemDTO): TimingDetailField[] {
|
||||
@ -343,12 +342,12 @@ function FilterMultiSelect({
|
||||
return (
|
||||
<label className="flex flex-col gap-2">
|
||||
<span className="text-[12px] font-apple-medium text-apple-label-secondary">{label}</span>
|
||||
<details className="group relative">
|
||||
<details className="group">
|
||||
<summary className="flex h-11 cursor-pointer list-none items-center justify-between rounded-apple-lg border border-black/8 bg-white/80 px-3.5 text-sm text-apple-label-primary outline-none transition marker:hidden group-open:border-[color:var(--color-blue)] group-open:bg-white">
|
||||
<span className={values.length === 0 ? 'text-apple-label-tertiary' : ''}>{summaryLabel}</span>
|
||||
<span className="text-[11px] text-apple-label-secondary">{values.length > 0 ? `${values.length} 项` : '多选'}</span>
|
||||
</summary>
|
||||
<div className="absolute z-40 mt-2 w-full min-w-[220px] rounded-apple-xl border border-black/8 bg-white p-2 shadow-[0_24px_60px_rgba(15,23,42,0.12)]">
|
||||
<div className="mt-2 w-full min-w-[220px] rounded-apple-xl border border-black/8 bg-white p-2 shadow-[0_24px_60px_rgba(15,23,42,0.12)]">
|
||||
<div className="mb-2 flex items-center justify-between px-2 pt-1">
|
||||
<span className="text-[11px] text-apple-label-secondary">可多选</span>
|
||||
<button
|
||||
|
||||
@ -554,19 +554,21 @@ function joinUnique(values: Array<string | null | undefined>) {
|
||||
return items.join(';')
|
||||
}
|
||||
|
||||
async function resolveActiveApproverNameLookup(groups: PreparedProjectGroup[]) {
|
||||
async function resolveUserNameLookup(groups: PreparedProjectGroup[]) {
|
||||
const userIds = Array.from(
|
||||
new Set(
|
||||
groups
|
||||
.flatMap((group) => pickActiveTasks(group.flowRecords))
|
||||
.map((taskRecord) => normalizeText(taskRecord.userId))
|
||||
.flatMap((group) => [
|
||||
...pickActiveTasks(group.flowRecords).map((taskRecord) => normalizeText(taskRecord.userId)),
|
||||
...group.flowRecords.map((record) => normalizeText(record.originatorUserId)),
|
||||
])
|
||||
.filter((value): value is string => Boolean(value)),
|
||||
),
|
||||
)
|
||||
|
||||
const approverNameLookup = new Map<string, string>()
|
||||
const userNameLookup = new Map<string, string>()
|
||||
if (userIds.length === 0) {
|
||||
return approverNameLookup
|
||||
return userNameLookup
|
||||
}
|
||||
|
||||
const [users, employees] = await Promise.all([
|
||||
@ -595,19 +597,19 @@ async function resolveActiveApproverNameLookup(groups: PreparedProjectGroup[]) {
|
||||
const key = normalizeText(user.dingtalkUserId)
|
||||
const name = normalizeText(user.name)
|
||||
if (key && name) {
|
||||
approverNameLookup.set(key, name)
|
||||
userNameLookup.set(key, name)
|
||||
}
|
||||
})
|
||||
|
||||
employees.forEach((employee) => {
|
||||
const key = normalizeText(employee.dingtalkUserId)
|
||||
const name = normalizeText(employee.name)
|
||||
if (key && name && !approverNameLookup.has(key)) {
|
||||
approverNameLookup.set(key, name)
|
||||
if (key && name && !userNameLookup.has(key)) {
|
||||
userNameLookup.set(key, name)
|
||||
}
|
||||
})
|
||||
|
||||
const unresolvedUserIds = userIds.filter((userId) => !approverNameLookup.has(userId))
|
||||
const unresolvedUserIds = userIds.filter((userId) => !userNameLookup.has(userId))
|
||||
const externalResults = await Promise.allSettled(
|
||||
unresolvedUserIds.map(async (userId) => ({
|
||||
userId,
|
||||
@ -625,12 +627,12 @@ async function resolveActiveApproverNameLookup(groups: PreparedProjectGroup[]) {
|
||||
? normalizeText(result.value.employee.name)
|
||||
: null
|
||||
|
||||
if (key && employeeName && !approverNameLookup.has(key)) {
|
||||
approverNameLookup.set(key, employeeName)
|
||||
if (key && employeeName && !userNameLookup.has(key)) {
|
||||
userNameLookup.set(key, employeeName)
|
||||
}
|
||||
})
|
||||
|
||||
return approverNameLookup
|
||||
return userNameLookup
|
||||
}
|
||||
|
||||
function buildFieldSnapshots(rows: SourceSchemeRow[]): NormalizedFieldSnapshot[] {
|
||||
@ -657,9 +659,29 @@ function buildFieldSnapshots(rows: SourceSchemeRow[]): NormalizedFieldSnapshot[]
|
||||
function getSourceTaskRowSortValue(row: SourceTaskRow) {
|
||||
const finishedAt = parseChinaDateTime(row.finishTime)?.getTime() ?? 0
|
||||
const createdAt = parseChinaDateTime(row.createTime)?.getTime() ?? 0
|
||||
const normalizedStatus = normalizeText(row.status)?.toUpperCase() ?? ''
|
||||
const normalizedResult = normalizeText(row.result)?.toUpperCase() ?? ''
|
||||
const statusPriority =
|
||||
OA_BOARD_RUNNING_STATUSES.has(normalizedStatus)
|
||||
? 3
|
||||
: normalizedStatus === 'COMPLETED'
|
||||
? 2
|
||||
: normalizedStatus === 'CANCELED' || normalizedStatus === 'TERMINATED'
|
||||
? 1
|
||||
: 0
|
||||
const resultPriority =
|
||||
normalizedResult === 'REDIRECTED'
|
||||
? 2
|
||||
: normalizedResult === 'NONE'
|
||||
? 1
|
||||
: normalizedResult === 'REFUSE'
|
||||
? 0
|
||||
: 1
|
||||
return {
|
||||
eventTime: Math.max(finishedAt, createdAt),
|
||||
hasFinishedAt: finishedAt > 0 ? 1 : 0,
|
||||
createdAt,
|
||||
statusPriority,
|
||||
resultPriority,
|
||||
rowId: Number(row.id) || 0,
|
||||
}
|
||||
}
|
||||
@ -671,8 +693,14 @@ function isNewerSourceTaskRow(nextRow: SourceTaskRow, currentRow: SourceTaskRow)
|
||||
if (nextValue.eventTime !== currentValue.eventTime) {
|
||||
return nextValue.eventTime > currentValue.eventTime
|
||||
}
|
||||
if (nextValue.hasFinishedAt !== currentValue.hasFinishedAt) {
|
||||
return nextValue.hasFinishedAt > currentValue.hasFinishedAt
|
||||
if (nextValue.createdAt !== currentValue.createdAt) {
|
||||
return nextValue.createdAt > currentValue.createdAt
|
||||
}
|
||||
if (nextValue.statusPriority !== currentValue.statusPriority) {
|
||||
return nextValue.statusPriority > currentValue.statusPriority
|
||||
}
|
||||
if (nextValue.resultPriority !== currentValue.resultPriority) {
|
||||
return nextValue.resultPriority > currentValue.resultPriority
|
||||
}
|
||||
return nextValue.rowId > currentValue.rowId
|
||||
}
|
||||
@ -1402,7 +1430,7 @@ function buildTimelineMetrics(
|
||||
|
||||
function buildProjectGraph(
|
||||
group: PreparedProjectGroup,
|
||||
approverNameLookup: Map<string, string>,
|
||||
userNameLookup: Map<string, string>,
|
||||
): OaBoardProjectGraphInput {
|
||||
const records = [...group.flowRecords].sort((left, right) => {
|
||||
const leftPriority = OA_BOARD_FLOW_PRIORITY.indexOf(left.flowType)
|
||||
@ -1460,7 +1488,7 @@ function buildProjectGraph(
|
||||
currentOwnerDisplay: joinUnique(
|
||||
activeTasks.map((taskRecord) => {
|
||||
const userId = normalizeText(taskRecord.userId)
|
||||
const approverName = userId ? approverNameLookup.get(userId) ?? null : null
|
||||
const approverName = userId ? userNameLookup.get(userId) ?? null : null
|
||||
return approverName || taskRecord.ownerLabel || null
|
||||
}),
|
||||
) || '-',
|
||||
@ -1514,6 +1542,10 @@ function buildProjectGraph(
|
||||
pricingCode: pricingRecord?.pricingCode ?? null,
|
||||
sourceBusinessId: reviewRecord?.businessId ?? null,
|
||||
originatorUserId: reviewRecord?.originatorUserId ?? null,
|
||||
originatorUserName:
|
||||
reviewRecord?.originatorUserId
|
||||
? userNameLookup.get(reviewRecord.originatorUserId) ?? null
|
||||
: null,
|
||||
originatorDeptId: reviewRecord?.originatorDeptId ?? null,
|
||||
originatorDeptName: reviewRecord?.originatorDeptName ?? null,
|
||||
currentStageKey: runningTask?.timelineStageKey ?? currentFlow?.flowType ?? null,
|
||||
@ -1901,8 +1933,8 @@ export async function queryOaBoardPreview(limit?: number): Promise<OaBoardPrevie
|
||||
: undefined
|
||||
const sourceRecords = await fetchSourceData(normalizedLimit)
|
||||
const projectGroups = buildProjectGroups(sourceRecords)
|
||||
const approverNameLookup = await resolveActiveApproverNameLookup(projectGroups)
|
||||
const projectGraphs = projectGroups.map((group) => buildProjectGraph(group, approverNameLookup))
|
||||
const userNameLookup = await resolveUserNameLookup(projectGroups)
|
||||
const projectGraphs = projectGroups.map((group) => buildProjectGraph(group, userNameLookup))
|
||||
const counts = countNestedRecords(projectGraphs)
|
||||
|
||||
return {
|
||||
|
||||
@ -96,6 +96,7 @@ export interface OaBoardProjectListItemDTO {
|
||||
overallTimeoutFlag: boolean
|
||||
createdDate: string | null
|
||||
finishedDate: string | null
|
||||
originatorUserName: string | null
|
||||
originatorDeptName: string | null
|
||||
lastSourceUpdatedAt: string | null
|
||||
styleImages: OaBoardFormPreviewImageDTO[]
|
||||
@ -258,6 +259,7 @@ export interface OaBoardProjectGraphInput {
|
||||
pricingCode: string | null
|
||||
sourceBusinessId: string | null
|
||||
originatorUserId: string | null
|
||||
originatorUserName: string | null
|
||||
originatorDeptId: string | null
|
||||
originatorDeptName: string | null
|
||||
currentStageKey: string | null
|
||||
@ -376,6 +378,7 @@ function buildMockOaBoardItem(input: {
|
||||
overallTimeoutFlag: timeoutHours > 0,
|
||||
createdDate: input.createdDate,
|
||||
finishedDate: input.finishedDate,
|
||||
originatorUserName: '系统管理员',
|
||||
originatorDeptName: '产品开发中心',
|
||||
lastSourceUpdatedAt: new Date().toISOString(),
|
||||
styleImages: [],
|
||||
@ -840,6 +843,7 @@ function toProjectListItem(record: PreviewProjectRecord): OaBoardProjectListItem
|
||||
overallTimeoutFlag: record.overallTimeoutFlag,
|
||||
createdDate: toIsoString(reviewFlow?.createdAtSource ?? record.flowInstances[0]?.createdAtSource),
|
||||
finishedDate: toIsoString(reviewFlow?.finishedAtSource ?? record.flowInstances[0]?.finishedAtSource),
|
||||
originatorUserName: record.originatorUserName,
|
||||
originatorDeptName: record.originatorDeptName,
|
||||
lastSourceUpdatedAt: toIsoString(record.lastSourceUpdatedAt),
|
||||
styleImages,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user