拆分打手个人订单服务

This commit is contained in:
yml2213
2026-08-21 17:01:03 +08:00
parent 47c25664e4
commit e3089e20a6
3 changed files with 361 additions and 332 deletions
@@ -14,6 +14,7 @@ export * from './worker-order-timeout-service.js'
export * from './worker-order-realtime-service.js'
export * from './worker-collect-service.js'
export * from './worker-acceptance-service.js'
export * from './worker-my-order-service.js'
export * from './worker-platform-defaults.js'
export * from './work-order-timeout-policy.js'
export * from './after-sales-service.js'
@@ -0,0 +1,348 @@
import { runtimeConfig } from '../../config/runtime.js'
import {
createWorkerCancelRequest,
createWorkerOrderFeedback,
getWorkOrderShare,
getWorkerCancelRequestRisk,
getWorkerOrderOverview,
listWorkerCancelRequests,
listWorkerOrderFeedbacks,
listWorkerSharesByWorker,
listWorkerWorkOrderNotes,
listWorkerWorkOrderViews,
listWorkOrderEventsByOrderId,
listWorkOrders,
markWorkerWorkOrderViewed,
upsertWorkerWorkOrderNote,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { nowIso } from '../../utils/time.js'
import { normalizePage, normalizePageSize } from '../admin/admin-query-utils.js'
import { getWorkerAnnouncementConfig } from './worker-announcement-config-service.js'
import {
createWorkerCancelRequestAdminNotification,
createWorkerOrderFeedbackAdminNotification,
} from '../admin/admin-notification-service.js'
import { publishWorkOrderRealtimeChange } from '../realtime/realtime-event-service.js'
import {
mapWorkOrderEvents,
mapWorkOrderForWorker,
mapWorkerCancelRequest,
mapWorkerOrderFeedback,
normalizeBoolean,
normalizeStatuses,
resolveWorkerPermissions,
} from './mappers.js'
import {
getRequiredWorkOrder,
getRequiredWorker,
requireActiveWorkerSession,
type WorkerSession,
} from './worker-session-context-service.js'
import { settleOverdueWorkOrders } from './worker-order-timeout-service.js'
export async function listWorkerMyOrders(query: JsonObject = {}, session: WorkerSession) {
requireActiveWorkerSession(session)
const worker = await getRequiredWorker(session.workerId)
const page = normalizePage(query.page)
const pageSize = normalizePageSize(query.pageSize)
const vipEvidencePending = normalizeBoolean(query.vipEvidencePending, false)
const { items, total } = await listWorkOrders({
page,
pageSize,
statuses: normalizeStatuses(query.status),
keyword: String(query.keyword || '').trim(),
workerSharingId: worker.id,
vipEvidencePending,
sort: 'worker_claimed_at_desc',
})
const permissions = resolveWorkerPermissions(worker)
const myShares = await listWorkerSharesByWorker(worker.id)
const myShareByOrderId = new Map(myShares.map((share) => [Number(share.work_order_id), share]))
const workOrderIds = items.map((item) => Number(item.id))
const [notes, views] = await Promise.all([
listWorkerWorkOrderNotes(worker.id, workOrderIds),
listWorkerWorkOrderViews(worker.id, workOrderIds),
])
const noteByOrderId = new Map(
notes.map((item) => [Number(item.work_order_id), String(item.note || '')]),
)
const viewedAtByOrderId = new Map(
views.map((item) => [Number(item.work_order_id), String(item.viewed_at || '')]),
)
return {
items: items.map((item) =>
mapWorkOrderForWorker(
item,
permissions,
myShareByOrderId.get(Number(item.id)),
noteByOrderId.get(Number(item.id)) || '',
viewedAtByOrderId.get(Number(item.id)) || null,
),
),
pagination: { page, pageSize, total },
}
}
/** 打手订单标签概览:订单数与预计或已结算金额。 */
export async function getWorkerMyOrderOverview(session: WorkerSession) {
requireActiveWorkerSession(session)
const worker = await getRequiredWorker(session.workerId)
await settleOverdueWorkOrders({ workerId: worker.id, limit: 50 })
const rows = await getWorkerOrderOverview(worker.id)
const items = rows.map((row) => ({
status: row.status,
orderCount: row.orderCount,
settlementAmount: row.settlementAmount,
}))
const vipEvidencePending = rows.reduce(
(summary, row) => ({
orderCount: summary.orderCount + row.vipEvidencePendingCount,
settlementAmount: summary.settlementAmount + row.vipEvidencePendingSettlementAmount,
}),
{ orderCount: 0, settlementAmount: 0 },
)
const all = items.reduce(
(summary, item) => ({
orderCount: summary.orderCount + item.orderCount,
settlementAmount: summary.settlementAmount + item.settlementAmount,
}),
{ orderCount: 0, settlementAmount: 0 },
)
return {
items: [
...items,
{ status: 'vip_evidence_pending', ...vipEvidencePending },
{ status: 'all', ...all },
],
}
}
export async function getWorkerMyOrderEvents(workOrderId: number | string, session: WorkerSession) {
requireActiveWorkerSession(session)
if (runtimeConfig.worker.orderTimelineVisible !== true) {
throw createHttpError('流转记录暂未对打手开放', {
statusCode: 403,
errorCode: 'work_order_events_worker_disabled',
})
}
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能查看自己订单的流转记录', {
statusCode: 403,
errorCode: 'work_order_events_owner_required',
})
}
const events = await listWorkOrderEventsByOrderId(workOrderId)
return { items: await mapWorkOrderEvents(events) }
}
export async function getWorkerCancelRequestSummary(session: WorkerSession) {
requireActiveWorkerSession(session)
const [risk, requests] = await Promise.all([
getWorkerCancelRequestRisk(session.workerId, nowIso()),
listWorkerCancelRequests(session.workerId),
])
return { risk, items: requests.map(mapWorkerCancelRequest) }
}
export async function getWorkerAnnouncement(session: WorkerSession) {
requireActiveWorkerSession(session)
return getWorkerAnnouncementConfig()
}
export async function getWorkerOrderFeedbackSummary(session: WorkerSession) {
requireActiveWorkerSession(session)
return { items: (await listWorkerOrderFeedbacks(session.workerId)).map(mapWorkerOrderFeedback) }
}
export async function submitWorkerOrderFeedback(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const content = String(payload.content || '').trim()
if (!content) {
throw createHttpError('请填写问题反馈内容', {
statusCode: 400,
errorCode: 'worker_order_feedback_content_required',
})
}
if (content.length > 500) {
throw createHttpError('问题反馈不能超过 500 个字符', {
statusCode: 400,
errorCode: 'worker_order_feedback_content_too_long',
})
}
const result = await createWorkerOrderFeedback({
workOrderId: Number(workOrderId),
workerId: Number(session.workerId),
content,
now: nowIso(),
})
if (!result.feedback) {
throw createHttpError('只能反馈自己的订单问题', {
statusCode: 403,
errorCode: 'worker_order_feedback_owner_required',
})
}
const worker = await getRequiredWorker(session.workerId)
await createWorkerOrderFeedbackAdminNotification({
feedbackId: Number(result.feedback.id),
workOrderId: Number(result.feedback.work_order_id),
workOrderNo: result.feedback.work_order_no || '',
productName: result.feedback.product_name || '',
workerName: worker.display_name || worker.username,
content,
})
publishWorkOrderRealtimeChange({
workOrderId: Number(result.feedback.work_order_id),
workerIds: [Number(session.workerId)],
})
return { feedback: mapWorkerOrderFeedback(result.feedback) }
}
export async function submitWorkerCancelRequest(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const reason = String(payload.reason || '').trim()
if (!reason) {
throw createHttpError('请填写申请取消原因', {
statusCode: 400,
errorCode: 'worker_cancel_request_reason_required',
})
}
if (reason.length > 300) {
throw createHttpError('申请取消原因不能超过 300 个字符', {
statusCode: 400,
errorCode: 'worker_cancel_request_reason_too_long',
})
}
const now = nowIso()
const result = await createWorkerCancelRequest({
workOrderId: Number(workOrderId),
workerId: Number(session.workerId),
reason,
now,
})
if (result.failureReason === 'daily_limit_reached') {
throw createHttpError('今日最多申请取消 5 次,请明日再试', {
statusCode: 429,
errorCode: 'worker_cancel_request_daily_limit',
})
}
if (result.failureReason === 'request_pending') {
throw createHttpError('该订单已有待审核的取消申请', {
statusCode: 409,
errorCode: 'worker_cancel_request_pending',
})
}
if (result.failureReason === 'share_not_cancellable') {
throw createHttpError('当前拼单份额不能申请取消', {
statusCode: 409,
errorCode: 'worker_cancel_request_share_status_invalid',
})
}
if (!result.request) {
throw createHttpError('当前订单不能申请取消', {
statusCode: 409,
errorCode: 'worker_cancel_request_status_invalid',
})
}
const worker = await getRequiredWorker(session.workerId)
await createWorkerCancelRequestAdminNotification({
requestId: Number(result.request.id),
workOrderId: Number(result.request.work_order_id),
platformOrderId: result.request.platform_order_id || '',
productName: result.request.product_name || '',
workerName: worker.display_name || worker.username,
reason,
})
const risk = await getWorkerCancelRequestRisk(session.workerId, now)
publishWorkOrderRealtimeChange({
workOrderId: Number(result.request.work_order_id),
workerIds: [Number(session.workerId)],
})
return { request: mapWorkerCancelRequest(result.request), risk }
}
export async function saveWorkerOrderNote(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const note = String(payload.note || '').trim()
if (note.length > 100) {
throw createHttpError('备注不能超过 100 个字符', {
statusCode: 400,
errorCode: 'work_order_note_too_long',
})
}
const worker = await getRequiredWorker(workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能修改自己的订单备注', {
statusCode: 403,
errorCode: 'work_order_note_owner_required',
})
}
const savedNote = await upsertWorkerWorkOrderNote({
workOrderId: Number(workOrder.id),
workerId,
note,
now: nowIso(),
})
return {
order: mapWorkOrderForWorker(
workOrder,
resolveWorkerPermissions(worker),
sharingShare,
savedNote,
),
}
}
/** 标记打手本人已查看工单,首次操作后不再展示“新”标识。 */
export async function markWorkerOrderRead(workOrderId: number | string, session: WorkerSession) {
requireActiveWorkerSession(session)
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能标记自己的订单为已读', {
statusCode: 403,
errorCode: 'work_order_read_owner_required',
})
}
const viewedAt = await markWorkerWorkOrderViewed({
workOrderId: Number(workOrder.id),
workerId,
now: nowIso(),
})
publishWorkOrderRealtimeChange({
workOrderId: Number(workOrder.id),
workerIds: [workerId],
})
return { viewedAt, isUnread: false }
}
@@ -1,8 +1,5 @@
import { runtimeConfig } from '../../config/runtime.js'
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
import {
createWorkerCancelRequest,
createWorkerOrderFeedback,
countWorkerActiveOrders,
consumeWorkerSmsCode,
createWorkOrderEvent,
@@ -13,8 +10,6 @@ import {
getWorkerUserByUsername,
getWorkerUserByDisplayName,
getWorkOrderById,
getWorkOrderShare,
getWorkerOrderOverview,
grabWorkOrder,
createWorkerSessionRecord,
getWorkerSessionBySessionId,
@@ -22,24 +17,12 @@ import {
revokeWorkerSession,
touchWorkerSession,
joinWorkOrderShare,
listWorkerCancelRequests,
listWorkerOrderFeedbacks,
listWorkerSharesByWorker,
listWorkerWorkOrderNotes,
listWorkerWorkOrderViews,
listWorkOrders,
listWorkOrderEventsByOrderId,
getWorkerCancelRequestRisk,
upsertWorkerWorkOrderNote,
markWorkerWorkOrderViewed,
type WorkOrderRow,
type WorkerSessionRow,
} from '../../repositories/worker-platform/index.js'
import type { JsonObject } from '../../types/json.js'
import { createHttpError } from '../../utils/http.js'
import { nowIso } from '../../utils/time.js'
import { normalizePage, normalizePageSize } from '../admin/admin-query-utils.js'
import { getWorkerAnnouncementConfig } from './worker-announcement-config-service.js'
import { getWorkerHallConfig } from './worker-hall-config-service.js'
import {
getRequiredWorkOrder,
@@ -47,10 +30,6 @@ import {
requireActiveWorkerSession,
type WorkerSession,
} from './worker-session-context-service.js'
import {
createWorkerCancelRequestAdminNotification,
createWorkerOrderFeedbackAdminNotification,
} from '../admin/admin-notification-service.js'
import {
publishWorkerWalletRealtimeChange,
publishWorkOrderRealtimeChange,
@@ -58,14 +37,8 @@ import {
import {
mapWorkOrderForWorker,
mapWorkOrderEvents,
mapWorkOrderShare,
mapWorkerCancelRequest,
mapWorkerOrderFeedback,
normalizeBoolean,
normalizeOptionalId,
normalizePositiveInteger,
normalizeStatuses,
resolveFreezeDepositAmount,
resolveWorkerPermissions,
throwGrabWorkOrderFailure,
@@ -99,7 +72,6 @@ import {
} from './worker-session-auth-service.js'
import { normalizeWorkOrderTimeoutPolicy } from './work-order-timeout-policy.js'
import { publishWorkOrderParticipantChange } from './worker-order-realtime-service.js'
import { settleOverdueWorkOrders } from './worker-order-timeout-service.js'
export {
getRequiredWorkOrder,
@@ -255,310 +227,18 @@ export { settleDueDepositUnfreezes } from './worker-profile-service.js'
export { settleOverdueWorkOrders } from './worker-order-timeout-service.js'
export async function listWorkerMyOrders(query: JsonObject = {}, session: WorkerSession) {
requireActiveWorkerSession(session)
const worker = await getRequiredWorker(session.workerId)
const page = normalizePage(query.page)
const pageSize = normalizePageSize(query.pageSize)
const vipEvidencePending = normalizeBoolean(query.vipEvidencePending, false)
const { items, total } = await listWorkOrders({
page,
pageSize,
statuses: normalizeStatuses(query.status),
keyword: String(query.keyword || '').trim(),
workerSharingId: worker.id,
vipEvidencePending,
sort: 'worker_claimed_at_desc',
})
const permissions = resolveWorkerPermissions(worker)
const myShares = await listWorkerSharesByWorker(worker.id)
const myShareByOrderId = new Map(myShares.map((share) => [Number(share.work_order_id), share]))
const workOrderIds = items.map((item) => Number(item.id))
const [notes, views] = await Promise.all([
listWorkerWorkOrderNotes(worker.id, workOrderIds),
listWorkerWorkOrderViews(worker.id, workOrderIds),
])
const noteByOrderId = new Map(
notes.map((item) => [Number(item.work_order_id), String(item.note || '')]),
)
const viewedAtByOrderId = new Map(
views.map((item) => [Number(item.work_order_id), String(item.viewed_at || '')]),
)
return {
items: items.map((item) =>
mapWorkOrderForWorker(
item,
permissions,
myShareByOrderId.get(Number(item.id)),
noteByOrderId.get(Number(item.id)) || '',
viewedAtByOrderId.get(Number(item.id)) || null,
),
),
pagination: { page, pageSize, total },
}
}
/** 打手订单标签概览:订单数与预计/已结算金额。 */
export async function getWorkerMyOrderOverview(session: WorkerSession) {
requireActiveWorkerSession(session)
const worker = await getRequiredWorker(session.workerId)
await settleOverdueWorkOrders({ workerId: worker.id, limit: 50 })
const rows = await getWorkerOrderOverview(worker.id)
const items = rows.map((row) => ({
status: row.status,
orderCount: row.orderCount,
settlementAmount: row.settlementAmount,
}))
const vipEvidencePending = rows.reduce(
(summary, row) => ({
orderCount: summary.orderCount + row.vipEvidencePendingCount,
settlementAmount: summary.settlementAmount + row.vipEvidencePendingSettlementAmount,
}),
{ orderCount: 0, settlementAmount: 0 },
)
const all = items.reduce(
(summary, item) => ({
orderCount: summary.orderCount + item.orderCount,
settlementAmount: summary.settlementAmount + item.settlementAmount,
}),
{ orderCount: 0, settlementAmount: 0 },
)
return {
items: [
...items,
{ status: 'vip_evidence_pending', ...vipEvidencePending },
{ status: 'all', ...all },
],
}
}
export async function getWorkerMyOrderEvents(workOrderId: number | string, session: WorkerSession) {
requireActiveWorkerSession(session)
if (runtimeConfig.worker.orderTimelineVisible !== true) {
throw createHttpError('流转记录暂未对打手开放', {
statusCode: 403,
errorCode: 'work_order_events_worker_disabled',
})
}
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能查看自己订单的流转记录', {
statusCode: 403,
errorCode: 'work_order_events_owner_required',
})
}
const events = await listWorkOrderEventsByOrderId(workOrderId)
return { items: await mapWorkOrderEvents(events) }
}
export async function getWorkerCancelRequestSummary(session: WorkerSession) {
requireActiveWorkerSession(session)
const [risk, requests] = await Promise.all([
getWorkerCancelRequestRisk(session.workerId, nowIso()),
listWorkerCancelRequests(session.workerId),
])
return { risk, items: requests.map(mapWorkerCancelRequest) }
}
export async function getWorkerAnnouncement(session: WorkerSession) {
requireActiveWorkerSession(session)
return getWorkerAnnouncementConfig()
}
export async function getWorkerOrderFeedbackSummary(session: WorkerSession) {
requireActiveWorkerSession(session)
return { items: (await listWorkerOrderFeedbacks(session.workerId)).map(mapWorkerOrderFeedback) }
}
export async function submitWorkerOrderFeedback(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const content = String(payload.content || '').trim()
if (!content) {
throw createHttpError('请填写问题反馈内容', {
statusCode: 400,
errorCode: 'worker_order_feedback_content_required',
})
}
if (content.length > 500) {
throw createHttpError('问题反馈不能超过 500 个字符', {
statusCode: 400,
errorCode: 'worker_order_feedback_content_too_long',
})
}
const result = await createWorkerOrderFeedback({
workOrderId: Number(workOrderId),
workerId: Number(session.workerId),
content,
now: nowIso(),
})
if (!result.feedback) {
throw createHttpError('只能反馈自己的订单问题', {
statusCode: 403,
errorCode: 'worker_order_feedback_owner_required',
})
}
const worker = await getRequiredWorker(session.workerId)
await createWorkerOrderFeedbackAdminNotification({
feedbackId: Number(result.feedback.id),
workOrderId: Number(result.feedback.work_order_id),
workOrderNo: result.feedback.work_order_no || '',
productName: result.feedback.product_name || '',
workerName: worker.display_name || worker.username,
content,
})
publishWorkOrderRealtimeChange({
workOrderId: Number(result.feedback.work_order_id),
workerIds: [Number(session.workerId)],
})
return { feedback: mapWorkerOrderFeedback(result.feedback) }
}
export async function submitWorkerCancelRequest(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const reason = String(payload.reason || '').trim()
if (!reason) {
throw createHttpError('请填写申请取消原因', {
statusCode: 400,
errorCode: 'worker_cancel_request_reason_required',
})
}
if (reason.length > 300) {
throw createHttpError('申请取消原因不能超过 300 个字符', {
statusCode: 400,
errorCode: 'worker_cancel_request_reason_too_long',
})
}
const now = nowIso()
const result = await createWorkerCancelRequest({
workOrderId: Number(workOrderId),
workerId: Number(session.workerId),
reason,
now,
})
if (result.failureReason === 'daily_limit_reached') {
throw createHttpError('今日最多申请取消 5 次,请明日再试', {
statusCode: 429,
errorCode: 'worker_cancel_request_daily_limit',
})
}
if (result.failureReason === 'request_pending') {
throw createHttpError('该订单已有待审核的取消申请', {
statusCode: 409,
errorCode: 'worker_cancel_request_pending',
})
}
if (result.failureReason === 'share_not_cancellable') {
throw createHttpError('当前拼单份额不能申请取消', {
statusCode: 409,
errorCode: 'worker_cancel_request_share_status_invalid',
})
}
if (!result.request) {
throw createHttpError('当前订单不能申请取消', {
statusCode: 409,
errorCode: 'worker_cancel_request_status_invalid',
})
}
const worker = await getRequiredWorker(session.workerId)
await createWorkerCancelRequestAdminNotification({
requestId: Number(result.request.id),
workOrderId: Number(result.request.work_order_id),
platformOrderId: result.request.platform_order_id || '',
productName: result.request.product_name || '',
workerName: worker.display_name || worker.username,
reason,
})
const risk = await getWorkerCancelRequestRisk(session.workerId, now)
publishWorkOrderRealtimeChange({
workOrderId: Number(result.request.work_order_id),
workerIds: [Number(session.workerId)],
})
return { request: mapWorkerCancelRequest(result.request), risk }
}
export async function saveWorkerOrderNote(
workOrderId: number | string,
payload: JsonObject = {},
session: WorkerSession,
) {
requireActiveWorkerSession(session)
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const note = String(payload.note || '').trim()
if (note.length > 100) {
throw createHttpError('备注不能超过 100 个字符', {
statusCode: 400,
errorCode: 'work_order_note_too_long',
})
}
const worker = await getRequiredWorker(workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能修改自己的订单备注', {
statusCode: 403,
errorCode: 'work_order_note_owner_required',
})
}
const savedNote = await upsertWorkerWorkOrderNote({
workOrderId: Number(workOrder.id),
workerId,
note,
now: nowIso(),
})
return {
order: mapWorkOrderForWorker(
workOrder,
resolveWorkerPermissions(worker),
sharingShare,
savedNote,
),
}
}
/** 标记打手本人已查看工单,首次操作后不再展示“新”标识。 */
export async function markWorkerOrderRead(workOrderId: number | string, session: WorkerSession) {
requireActiveWorkerSession(session)
const workOrder = await getRequiredWorkOrder(workOrderId)
const workerId = Number(session.workerId)
const sharingShare = await getWorkOrderShare(workOrder.id, workerId)
const isOrderOwner =
Number(workOrder.assigned_worker_id || 0) === workerId ||
Number(workOrder.last_assigned_worker_id || 0) === workerId
if (!sharingShare && !isOrderOwner) {
throw createHttpError('只能标记自己的订单为已读', {
statusCode: 403,
errorCode: 'work_order_read_owner_required',
})
}
const viewedAt = await markWorkerWorkOrderViewed({
workOrderId: Number(workOrder.id),
workerId,
now: nowIso(),
})
publishWorkOrderRealtimeChange({
workOrderId: Number(workOrder.id),
workerIds: [workerId],
})
return { viewedAt, isUnread: false }
}
export {
getWorkerAnnouncement,
getWorkerCancelRequestSummary,
getWorkerMyOrderEvents,
getWorkerMyOrderOverview,
getWorkerOrderFeedbackSummary,
listWorkerMyOrders,
markWorkerOrderRead,
saveWorkerOrderNote,
submitWorkerCancelRequest,
submitWorkerOrderFeedback,
} from './worker-my-order-service.js'
export async function joinWorkerSharingOrder(
workOrderId: number | string,