feat(work-order): 新增一次性补资料链接

This commit is contained in:
2026-11-01 10:46:31 +08:00
parent fba0a13d44
commit 15956e704f
26 changed files with 1768 additions and 4 deletions
@@ -17,6 +17,7 @@ export * from './work-order-deposit-query-repo.js'
export * from './work-order-deposit-repo.js'
export * from './work-order-event-repo.js'
export * from './work-order-share-repo.js'
export * from './work-order-material-link-repo.js'
export * from './work-category-repo.js'
export * from './work-product-rule-repo.js'
export * from './worker-order-note-repo.js'
@@ -0,0 +1,167 @@
import type { PoolClient } from 'pg'
import { query } from '../../db/client.js'
import type { WorkOrderRow } from './types.js'
export type WorkOrderMaterialLinkStatus = 'active' | 'used' | 'expired' | 'revoked'
export type WorkOrderMaterialLinkRow = {
id: number
work_order_id: number
token: string
status: WorkOrderMaterialLinkStatus
expires_at: string
used_at: string | null
created_by: string
created_at: string
updated_at: string
}
export async function findWorkOrderMaterialLinkByToken(
token: string,
): Promise<WorkOrderMaterialLinkRow | null> {
const result = await query<WorkOrderMaterialLinkRow>(
'SELECT * FROM work_order_material_links WHERE token = $1 LIMIT 1',
[String(token || '').trim()],
)
return result.rows[0] || null
}
export async function findActiveWorkOrderMaterialLink(
workOrderId: number | string,
now: string,
): Promise<WorkOrderMaterialLinkRow | null> {
const result = await query<WorkOrderMaterialLinkRow>(
`SELECT * FROM work_order_material_links
WHERE work_order_id = $1 AND status = 'active' AND expires_at > $2
ORDER BY id DESC
LIMIT 1`,
[Number(workOrderId), now],
)
return result.rows[0] || null
}
export async function getWorkOrderForUpdateWithClient(
client: PoolClient,
workOrderId: number | string,
): Promise<WorkOrderRow | null> {
const result = await client.query<WorkOrderRow>(
'SELECT * FROM work_orders WHERE id = $1 FOR UPDATE',
[Number(workOrderId)],
)
return result.rows[0] || null
}
export async function getWorkOrderMaterialLinkForUpdateWithClient(
client: PoolClient,
linkId: number | string,
): Promise<WorkOrderMaterialLinkRow | null> {
const result = await client.query<WorkOrderMaterialLinkRow>(
'SELECT * FROM work_order_material_links WHERE id = $1 FOR UPDATE',
[Number(linkId)],
)
return result.rows[0] || null
}
export async function findActiveWorkOrderMaterialLinkWithClient(
client: PoolClient,
workOrderId: number | string,
now: string,
): Promise<WorkOrderMaterialLinkRow | null> {
const result = await client.query<WorkOrderMaterialLinkRow>(
`SELECT * FROM work_order_material_links
WHERE work_order_id = $1 AND status = 'active' AND expires_at > $2
ORDER BY id DESC
LIMIT 1`,
[Number(workOrderId), now],
)
return result.rows[0] || null
}
/** 重新生成前清掉旧 active:已过期标 expired,未过期标 revoked。 */
export async function revokeActiveWorkOrderMaterialLinksWithClient(
client: PoolClient,
workOrderId: number | string,
now: string,
): Promise<number> {
const result = await client.query(
`UPDATE work_order_material_links
SET status = CASE WHEN expires_at <= $2 THEN 'expired' ELSE 'revoked' END,
updated_at = $2
WHERE work_order_id = $1 AND status = 'active'`,
[Number(workOrderId), now],
)
return result.rowCount || 0
}
export async function createWorkOrderMaterialLinkWithClient(
client: PoolClient,
input: {
workOrderId: number | string
token: string
expiresAt: string
createdBy: string
now: string
},
): Promise<WorkOrderMaterialLinkRow> {
const result = await client.query<WorkOrderMaterialLinkRow>(
`INSERT INTO work_order_material_links (
work_order_id, token, status, expires_at, created_by, created_at, updated_at
) VALUES ($1, $2, 'active', $3, $4, $5, $5)
RETURNING *`,
[
Number(input.workOrderId),
input.token,
input.expiresAt,
String(input.createdBy || '').trim(),
input.now,
],
)
return result.rows[0]!
}
export async function markWorkOrderMaterialLinkUsedWithClient(
client: PoolClient,
linkId: number | string,
now: string,
): Promise<WorkOrderMaterialLinkRow | null> {
const result = await client.query<WorkOrderMaterialLinkRow>(
`UPDATE work_order_material_links
SET status = 'used', used_at = $2, updated_at = $2
WHERE id = $1 AND status = 'active'
RETURNING *`,
[Number(linkId), now],
)
return result.rows[0] || null
}
export async function markWorkOrderMaterialLinkExpired(
linkId: number | string,
now: string,
): Promise<void> {
await query(
`UPDATE work_order_material_links
SET status = 'expired', updated_at = $2
WHERE id = $1 AND status = 'active'`,
[Number(linkId), now],
)
}
export async function updateWorkOrderMaterialWithClient(
client: PoolClient,
input: {
workOrderId: number | string
status: string
materialJson: string
now: string
},
): Promise<WorkOrderRow | null> {
const result = await client.query<WorkOrderRow>(
`UPDATE work_orders
SET status = $2, material_json = $3::jsonb, updated_at = $4
WHERE id = $1
RETURNING *`,
[Number(input.workOrderId), input.status, input.materialJson, input.now],
)
return result.rows[0] || null
}