拆分打手大厅服务
This commit is contained in:
@@ -9,6 +9,7 @@ export * from './worker-sms-service.js'
|
||||
export * from './worker-registration-service.js'
|
||||
export * from './worker-login-service.js'
|
||||
export * from './worker-profile-service.js'
|
||||
export * from './worker-hall-service.js'
|
||||
export * from './worker-platform-defaults.js'
|
||||
export * from './work-order-timeout-policy.js'
|
||||
export * from './after-sales-service.js'
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import { WORK_ORDER_STATUS } from '../../domain/work-order-status.js'
|
||||
import {
|
||||
listWorkCategories,
|
||||
listWorkerCompletionLeaderboard,
|
||||
listWorkOrderSharesByOrderIds,
|
||||
listWorkOrders,
|
||||
} from '../../repositories/worker-platform/index.js'
|
||||
import type { JsonObject } from '../../types/json.js'
|
||||
import { normalizePage, normalizePageSize } from '../admin/admin-query-utils.js'
|
||||
import {
|
||||
mapWorkCategory,
|
||||
mapWorkOrderForWorker,
|
||||
mapWorkOrderShare,
|
||||
normalizeOptionalId,
|
||||
resolveWorkerPermissions,
|
||||
} from './mappers.js'
|
||||
import { getWorkerHallConfig } from './worker-hall-config-service.js'
|
||||
import {
|
||||
getRequiredWorker,
|
||||
requireActiveWorkerSession,
|
||||
type WorkerSession,
|
||||
} from './worker-session-context-service.js'
|
||||
|
||||
export async function listWorkerHallOrders(query: JsonObject = {}, session: WorkerSession) {
|
||||
requireActiveWorkerSession(session)
|
||||
const page = normalizePage(query.page)
|
||||
const pageSize = normalizePageSize(query.pageSize)
|
||||
const categoryId = normalizeOptionalId(query.categoryId)
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
const permissions = resolveWorkerPermissions(worker)
|
||||
const visibleDelaySeconds = Number(permissions.visibleDelaySeconds || 0)
|
||||
const visibleAfterIso =
|
||||
visibleDelaySeconds > 0 ? new Date(Date.now() - visibleDelaySeconds * 1000).toISOString() : ''
|
||||
const hallConfig = getWorkerHallConfig()
|
||||
const { items, total } = await listWorkOrders({
|
||||
page,
|
||||
pageSize,
|
||||
statuses: [WORK_ORDER_STATUS.OPEN],
|
||||
keyword: String(query.keyword || '').trim(),
|
||||
categoryId: categoryId || 0,
|
||||
hallCandidateLimit: hallConfig.maxVisibleOrders,
|
||||
visibleAfterIso,
|
||||
excludeFilledSharing: true,
|
||||
pinnedFirst: true,
|
||||
})
|
||||
const categories = (await listWorkCategories()).map(mapWorkCategory)
|
||||
const orderIds = items.map((item) => Number(item.id))
|
||||
const shares = await listWorkOrderSharesByOrderIds(orderIds)
|
||||
const myShareByOrderId = new Map(
|
||||
shares
|
||||
.filter(
|
||||
(share) => share.status !== 'cancelled' && Number(share.worker_id) === Number(worker.id),
|
||||
)
|
||||
.map((share) => [Number(share.work_order_id), share]),
|
||||
)
|
||||
const sharingProgressByOrderId = new Map<
|
||||
number,
|
||||
{ joinedQuantity: number; pendingSubmissionCount: number }
|
||||
>()
|
||||
for (const share of shares) {
|
||||
if (share.status === 'cancelled') continue
|
||||
const orderId = Number(share.work_order_id)
|
||||
const progress = sharingProgressByOrderId.get(orderId) || {
|
||||
joinedQuantity: 0,
|
||||
pendingSubmissionCount: 0,
|
||||
}
|
||||
progress.joinedQuantity += Number(share.quantity || 0)
|
||||
if (share.status === 'joined') progress.pendingSubmissionCount += 1
|
||||
sharingProgressByOrderId.set(orderId, progress)
|
||||
}
|
||||
return {
|
||||
items: items.map((item) => {
|
||||
const myShare = myShareByOrderId.get(Number(item.id))
|
||||
return {
|
||||
...mapWorkOrderForWorker(item, permissions),
|
||||
myShare: myShare ? mapWorkOrderShare(myShare) : null,
|
||||
sharingProgress: sharingProgressByOrderId.get(Number(item.id)) || {
|
||||
joinedQuantity: 0,
|
||||
pendingSubmissionCount: 0,
|
||||
},
|
||||
}
|
||||
}),
|
||||
pagination: { page, pageSize, total },
|
||||
categories,
|
||||
visibleDelaySeconds,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getWorkerHallLeaderboard(session: WorkerSession, period: unknown = 'all') {
|
||||
requireActiveWorkerSession(session)
|
||||
const leaderboardPeriod = period === 'daily' ? 'daily' : 'all'
|
||||
const entries = await listWorkerCompletionLeaderboard({
|
||||
limit: 10,
|
||||
currentWorkerId: session.workerId,
|
||||
period: leaderboardPeriod,
|
||||
})
|
||||
const current = entries.find((entry) => entry.workerId === session.workerId)
|
||||
return {
|
||||
items: entries
|
||||
.filter((entry) => entry.rank <= 10)
|
||||
.map((entry) => ({
|
||||
...entry,
|
||||
displayName: maskWorkerLeaderboardDisplayName(entry.displayName),
|
||||
})),
|
||||
current: {
|
||||
rank: current?.rank || null,
|
||||
acceptedOrderCount: current?.acceptedOrderCount || 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function maskWorkerLeaderboardDisplayName(value: unknown): string {
|
||||
const firstCharacter = Array.from(String(value || '').trim())[0]
|
||||
return firstCharacter ? `${firstCharacter}****` : '****'
|
||||
}
|
||||
@@ -26,17 +26,14 @@ import {
|
||||
touchWorkerSession,
|
||||
joinWorkOrderShare,
|
||||
listPendingMaterialWorkOrdersByPlatformOrderId,
|
||||
listWorkerCompletionLeaderboard,
|
||||
listWorkerCancelRequests,
|
||||
listWorkerOrderFeedbacks,
|
||||
listWorkerSharesByWorker,
|
||||
listWorkerWorkOrderNotes,
|
||||
listWorkerWorkOrderViews,
|
||||
listWorkCategories,
|
||||
listWorkOrders,
|
||||
listWorkOrderEventsByOrderId,
|
||||
listWorkOrderShares,
|
||||
listWorkOrderSharesByOrderIds,
|
||||
getWorkerCancelRequestRisk,
|
||||
listOverdueWorkOrders,
|
||||
settleOverdueWorkOrder,
|
||||
@@ -79,7 +76,6 @@ import {
|
||||
|
||||
import {
|
||||
mapCollectLookupOrder,
|
||||
mapWorkCategory,
|
||||
mapWorkOrderForWorker,
|
||||
mapWorkOrderPublic,
|
||||
mapWorkOrderEvents,
|
||||
@@ -175,98 +171,11 @@ export {
|
||||
saveWorkerAlipayWithdrawalQrCode,
|
||||
} from './worker-profile-service.js'
|
||||
|
||||
export async function listWorkerHallOrders(query: JsonObject = {}, session: WorkerSession) {
|
||||
requireActiveWorkerSession(session)
|
||||
const page = normalizePage(query.page)
|
||||
const pageSize = normalizePageSize(query.pageSize)
|
||||
const categoryId = normalizeOptionalId(query.categoryId)
|
||||
const worker = await getRequiredWorker(session.workerId)
|
||||
const permissions = resolveWorkerPermissions(worker)
|
||||
const visibleDelaySeconds = Number(permissions.visibleDelaySeconds || 0)
|
||||
const visibleAfterIso =
|
||||
visibleDelaySeconds > 0 ? new Date(Date.now() - visibleDelaySeconds * 1000).toISOString() : ''
|
||||
const hallConfig = getWorkerHallConfig()
|
||||
const { items, total } = await listWorkOrders({
|
||||
page,
|
||||
pageSize,
|
||||
statuses: [WORK_ORDER_STATUS.OPEN],
|
||||
keyword: String(query.keyword || '').trim(),
|
||||
categoryId: categoryId || 0,
|
||||
hallCandidateLimit: hallConfig.maxVisibleOrders,
|
||||
visibleAfterIso,
|
||||
excludeFilledSharing: true,
|
||||
pinnedFirst: true,
|
||||
})
|
||||
const categories = (await listWorkCategories()).map(mapWorkCategory)
|
||||
const orderIds = items.map((item) => Number(item.id))
|
||||
const shares = await listWorkOrderSharesByOrderIds(orderIds)
|
||||
const myShareByOrderId = new Map(
|
||||
shares
|
||||
.filter(
|
||||
(share) => share.status !== 'cancelled' && Number(share.worker_id) === Number(worker.id),
|
||||
)
|
||||
.map((share) => [Number(share.work_order_id), share]),
|
||||
)
|
||||
const sharingProgressByOrderId = new Map<
|
||||
number,
|
||||
{ joinedQuantity: number; pendingSubmissionCount: number }
|
||||
>()
|
||||
for (const share of shares) {
|
||||
if (share.status === 'cancelled') continue
|
||||
const orderId = Number(share.work_order_id)
|
||||
const progress = sharingProgressByOrderId.get(orderId) || {
|
||||
joinedQuantity: 0,
|
||||
pendingSubmissionCount: 0,
|
||||
}
|
||||
progress.joinedQuantity += Number(share.quantity || 0)
|
||||
if (share.status === 'joined') progress.pendingSubmissionCount += 1
|
||||
sharingProgressByOrderId.set(orderId, progress)
|
||||
}
|
||||
return {
|
||||
items: items.map((item) => {
|
||||
const myShare = myShareByOrderId.get(Number(item.id))
|
||||
return {
|
||||
...mapWorkOrderForWorker(item, permissions),
|
||||
myShare: myShare ? mapWorkOrderShare(myShare) : null,
|
||||
sharingProgress: sharingProgressByOrderId.get(Number(item.id)) || {
|
||||
joinedQuantity: 0,
|
||||
pendingSubmissionCount: 0,
|
||||
},
|
||||
}
|
||||
}),
|
||||
pagination: { page, pageSize, total },
|
||||
categories,
|
||||
visibleDelaySeconds,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getWorkerHallLeaderboard(session: WorkerSession, period: unknown = 'all') {
|
||||
requireActiveWorkerSession(session)
|
||||
const leaderboardPeriod = period === 'daily' ? 'daily' : 'all'
|
||||
const entries = await listWorkerCompletionLeaderboard({
|
||||
limit: 10,
|
||||
currentWorkerId: session.workerId,
|
||||
period: leaderboardPeriod,
|
||||
})
|
||||
const current = entries.find((entry) => entry.workerId === session.workerId)
|
||||
return {
|
||||
items: entries
|
||||
.filter((entry) => entry.rank <= 10)
|
||||
.map((entry) => ({
|
||||
...entry,
|
||||
displayName: maskWorkerLeaderboardDisplayName(entry.displayName),
|
||||
})),
|
||||
current: {
|
||||
rank: current?.rank || null,
|
||||
acceptedOrderCount: current?.acceptedOrderCount || 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function maskWorkerLeaderboardDisplayName(value: unknown): string {
|
||||
const firstCharacter = Array.from(String(value || '').trim())[0]
|
||||
return firstCharacter ? `${firstCharacter}****` : '****'
|
||||
}
|
||||
export {
|
||||
getWorkerHallLeaderboard,
|
||||
listWorkerHallOrders,
|
||||
maskWorkerLeaderboardDisplayName,
|
||||
} from './worker-hall-service.js'
|
||||
|
||||
export async function grabWorkerHallOrder(workOrderId: number | string, session: WorkerSession) {
|
||||
requireActiveWorkerSession(session)
|
||||
|
||||
Reference in New Issue
Block a user