diff --git a/apps/backend/src/db/migrations/132_backfill_pending_order_service_snapshots.sql b/apps/backend/src/db/migrations/132_backfill_pending_order_service_snapshots.sql new file mode 100644 index 00000000..c910564e --- /dev/null +++ b/apps/backend/src/db/migrations/132_backfill_pending_order_service_snapshots.sql @@ -0,0 +1,26 @@ +-- 132_backfill_pending_order_service_snapshots.sql +-- +-- 旧工单创建于“配置快照”上线之前,打开 /o 时会回退到旧的 requirement_json。 +-- 对本分类仍待客户提交资料、且未指派打手的工单,回填当前发布版本快照。 + +UPDATE work_orders wo +SET service_profile_id = p.id, + service_profile_version_id = v.id, + service_profile_snapshot_json = jsonb_build_object( + 'profileId', p.id, + 'categoryId', p.category_id, + 'versionId', v.id, + 'versionNo', v.version_no, + 'config', v.config_json + ), + requirement_json = jsonb_build_object( + 'fields', COALESCE(v.config_json -> 'fields', '[]'::jsonb) + ), + updated_at = NOW() +FROM order_service_profiles p +JOIN order_service_profile_versions v ON v.id = p.current_version_id +WHERE wo.category_id = p.category_id + AND p.status <> 'archived' + AND wo.status = 'pending_material' + AND wo.assigned_worker_id IS NULL + AND wo.service_profile_snapshot_json IS NULL; diff --git a/apps/backend/src/repositories/worker-platform/order-service-profile-repo.ts b/apps/backend/src/repositories/worker-platform/order-service-profile-repo.ts index f538d698..b8e98a86 100644 --- a/apps/backend/src/repositories/worker-platform/order-service-profile-repo.ts +++ b/apps/backend/src/repositories/worker-platform/order-service-profile-repo.ts @@ -202,6 +202,41 @@ export async function setOrderServiceProfileCurrentVersion( ) } +export async function backfillPendingOrderServiceSnapshotsForCategory( + client: PoolClient, + input: { categoryId: number; profileId: number; versionId: number }, +): Promise { + const result = await client.query( + ` + UPDATE work_orders wo + SET service_profile_id = $2, + service_profile_version_id = $3, + service_profile_snapshot_json = jsonb_build_object( + 'profileId', p.id, + 'categoryId', p.category_id, + 'versionId', v.id, + 'versionNo', v.version_no, + 'config', v.config_json + ), + requirement_json = jsonb_build_object( + 'fields', COALESCE(v.config_json -> 'fields', '[]'::jsonb) + ), + updated_at = NOW() + FROM order_service_profiles p + JOIN order_service_profile_versions v ON v.id = p.current_version_id + WHERE p.id = $2 + AND p.category_id = $1 + AND v.id = $3 + AND wo.category_id = p.category_id + AND wo.status = 'pending_material' + AND wo.assigned_worker_id IS NULL + AND wo.service_profile_snapshot_json IS NULL + `, + [input.categoryId, input.profileId, input.versionId], + ) + return Number(result.rowCount || 0) +} + export async function getOrderServiceProfileVersion( versionId: number | string, client?: Pick, diff --git a/apps/backend/src/services/worker-platform/order-service-profile-service.ts b/apps/backend/src/services/worker-platform/order-service-profile-service.ts index c0844791..a3038c08 100644 --- a/apps/backend/src/services/worker-platform/order-service-profile-service.ts +++ b/apps/backend/src/services/worker-platform/order-service-profile-service.ts @@ -7,6 +7,7 @@ import { createHttpError } from '../../utils/http.js' import { nowIso } from '../../utils/time.js' import { archiveOrderServiceProfile, + backfillPendingOrderServiceSnapshotsForCategory, createOrderServiceProfileVersion, getOrderServiceProfileVersion, getPublishedOrderServiceProfileByCategory, @@ -171,7 +172,12 @@ export async function publishAdminOrderServiceProfile( adminUserId, }) await setOrderServiceProfileCurrentVersion(client, { profileId, versionId }) - return { versionNo, profileId, versionId } + const backfilledPendingOrders = await backfillPendingOrderServiceSnapshotsForCategory(client, { + categoryId: Number(profile.category_id), + profileId, + versionId, + }) + return { versionNo, profileId, versionId, backfilledPendingOrders } }) } diff --git a/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx b/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx index 9de0f50a..ecc80876 100644 --- a/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx +++ b/apps/frontend/src/pages/admin/panels/OrderServicePanel.tsx @@ -252,7 +252,12 @@ export default function OrderServicePanel() { setPublishing(true) try { const response = await publishAdminOrderServiceProfile(profile.id) - message.success(`已发布 v${response.data.versionNo}`) + const backfilled = Number(response.data.backfilledPendingOrders || 0) + message.success( + backfilled > 0 + ? `已发布 v${response.data.versionNo},同步 ${backfilled} 个未提交工单` + : `已发布 v${response.data.versionNo}`, + ) await refresh() } catch (error) { message.error(error instanceof Error ? error.message : '发布失败') diff --git a/apps/frontend/src/services/admin/worker-platform.ts b/apps/frontend/src/services/admin/worker-platform.ts index d471d6f5..ef27a67d 100644 --- a/apps/frontend/src/services/admin/worker-platform.ts +++ b/apps/frontend/src/services/admin/worker-platform.ts @@ -1197,7 +1197,7 @@ export function saveAdminOrderServiceProfile(payload: { } export function publishAdminOrderServiceProfile(profileId: number) { - return apiPost<{ versionNo: number }>( + return apiPost<{ versionNo: number; backfilledPendingOrders: number }>( `/api/v1/admin/worker-platform/order-service/profiles/${profileId}/publish`, ) } diff --git a/docs/订单服务收集与状态页设计-2026-11-03.md b/docs/订单服务收集与状态页设计-2026-11-03.md index 5d1c89d0..96bc6850 100644 --- a/docs/订单服务收集与状态页设计-2026-11-03.md +++ b/docs/订单服务收集与状态页设计-2026-11-03.md @@ -79,6 +79,12 @@ work_orders.service_profile_snapshot_json 历史工单没有快照时继续读取其 `requirement_json`,不会突然切换到新分类配置。 +发布新版本时,会同步该分类下仍未提交资料且未指派打手的旧工单: + +- 写入最新配置版本和快照; +- 同步 `requirement_json.fields`; +- 已提交、已指派、已进入履约的工单保持不变。 + ## 4. 客户页面 `/o` 支持: