后端迁移后台管理写侧基础工具
This commit is contained in:
+33
-19
@@ -1,5 +1,3 @@
|
||||
// @ts-check
|
||||
|
||||
import { buildClaimUrl, createTaskClaimToken } from '../../claim/claim-service.js'
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
import {
|
||||
@@ -9,7 +7,27 @@ import {
|
||||
parseTaskContext,
|
||||
} from '../admin-read-shared-helpers.js'
|
||||
|
||||
export function maskPhone(value) {
|
||||
import type { TaskRow } from '../../../types/repository-rows.js'
|
||||
|
||||
type AssistedTaskAction = 'confirm' | 'redeem'
|
||||
|
||||
type AdminViewerContextLike = {
|
||||
canOperateAssistedTask?: boolean
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
type TaskClaimLink = {
|
||||
token: string
|
||||
expiredAt: string | null
|
||||
claimUrl: string
|
||||
}
|
||||
|
||||
type ErrorLike = {
|
||||
errorCode?: string
|
||||
code?: string
|
||||
}
|
||||
|
||||
export function maskPhone(value: unknown): string {
|
||||
const text = String(value || '').trim()
|
||||
if (!text) {
|
||||
return ''
|
||||
@@ -22,7 +40,7 @@ export function maskPhone(value) {
|
||||
return `${text.slice(0, 3)}****${text.slice(-4)}`
|
||||
}
|
||||
|
||||
export function maskCode(value) {
|
||||
export function maskCode(value: unknown): string {
|
||||
const text = String(value || '').trim()
|
||||
if (!text) {
|
||||
return ''
|
||||
@@ -35,18 +53,17 @@ export function maskCode(value) {
|
||||
return `${text.slice(0, 4)}****${text.slice(-4)}`
|
||||
}
|
||||
|
||||
export function resolveTaskInventoryGroupCodes(task) {
|
||||
export function resolveTaskInventoryGroupCodes(task: TaskRow): string[] | null {
|
||||
const taskContext = parseTaskContext(task)
|
||||
const inventoryGroupCode = String(taskContext?.inventoryGroupCode || '').trim()
|
||||
return inventoryGroupCode ? [inventoryGroupCode] : null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} task
|
||||
* @param {any} viewerContext
|
||||
* @param {'confirm' | 'redeem'} action
|
||||
*/
|
||||
export function ensureViewerCanOperateAssistedTask(task, viewerContext, action) {
|
||||
export function ensureViewerCanOperateAssistedTask(
|
||||
task: TaskRow,
|
||||
viewerContext: AdminViewerContextLike,
|
||||
action: AssistedTaskAction,
|
||||
): void {
|
||||
if (!viewerContext.canOperateAssistedTask || !isAssistedClaimTask(task)) {
|
||||
throw createHttpError('当前账号没有此操作权限', {
|
||||
statusCode: 403,
|
||||
@@ -69,12 +86,12 @@ export function ensureViewerCanOperateAssistedTask(task, viewerContext, action)
|
||||
}
|
||||
}
|
||||
|
||||
export function isRecoverableTaskSessionCloseError(error) {
|
||||
export function isRecoverableTaskSessionCloseError(error: ErrorLike | null | undefined): boolean {
|
||||
const errorCode = String(error?.errorCode || error?.code || '').trim()
|
||||
return errorCode === 'session_not_found' || errorCode === 'session_closed'
|
||||
}
|
||||
|
||||
export function normalizeManualDispatchOutcome(value) {
|
||||
export function normalizeManualDispatchOutcome(value: unknown): 'delivered' | 'failed' {
|
||||
const normalized = String(value || '').trim().toLowerCase()
|
||||
|
||||
if (normalized === 'failed') {
|
||||
@@ -84,14 +101,11 @@ export function normalizeManualDispatchOutcome(value) {
|
||||
return 'delivered'
|
||||
}
|
||||
|
||||
export function getTaskClaimExpiresAt(task) {
|
||||
export function getTaskClaimExpiresAt(task: Partial<TaskRow> | null | undefined): string | null {
|
||||
return task?.claim_expires_at || task?.primary_claim_expires_at || null
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} task
|
||||
*/
|
||||
export async function ensureTaskClaimLink(task) {
|
||||
export async function ensureTaskClaimLink(task: TaskRow): Promise<TaskClaimLink> {
|
||||
const tokenStatus = String(task?.primary_claim_token_status || '').trim()
|
||||
const token = String(task?.primary_claim_token || task?.claim_token || '').trim()
|
||||
const expiredAt = getTaskClaimExpiresAt(task)
|
||||
@@ -112,7 +126,7 @@ export async function ensureTaskClaimLink(task) {
|
||||
}
|
||||
}
|
||||
|
||||
function isClaimExpired(expiredAt) {
|
||||
function isClaimExpired(expiredAt: string | null): boolean {
|
||||
if (!expiredAt) {
|
||||
return false
|
||||
}
|
||||
+3
-7
@@ -1,15 +1,11 @@
|
||||
// @ts-check
|
||||
|
||||
import { getWebhookEventById } from '../../../repositories/webhook-event-repo.js'
|
||||
import { replayAgisoTradeWebhookEvent } from '../../order/webhook-service.js'
|
||||
import { createHttpError } from '../../../utils/http.js'
|
||||
|
||||
/** @typedef {import('../../../types/admin-read-inputs.js').AdminEntityIdInput} AdminEntityIdInput */
|
||||
/** @typedef {import('../../../types/admin-write-models.js').AdminWebhookReplayResponse} AdminWebhookReplayResponse */
|
||||
import type { AdminEntityIdInput } from '../../../types/admin-read-inputs.js'
|
||||
import type { AdminWebhookReplayResponse } from '../../../types/admin-write-models.js'
|
||||
|
||||
/** @returns {Promise<AdminWebhookReplayResponse>} */
|
||||
/** @param {AdminEntityIdInput} eventId */
|
||||
export async function replayAdminWebhookEvent(eventId) {
|
||||
export async function replayAdminWebhookEvent(eventId: AdminEntityIdInput): Promise<AdminWebhookReplayResponse> {
|
||||
const event = await getWebhookEventById(Number(eventId))
|
||||
|
||||
if (!event) {
|
||||
@@ -726,6 +726,15 @@
|
||||
- `npm run typecheck`
|
||||
- `npm run build`
|
||||
- `npm test` 共 139 个用例通过
|
||||
180. 后台 Admin 写侧共享 helper 与 Webhook 重放入口迁移到 `.ts`:
|
||||
- `src/services/admin/write/shared.ts`
|
||||
- `src/services/admin/write/webhook-events.ts`
|
||||
181. Admin 脱敏、任务库存组解析、辅助领取权限校验、任务 claim 链接补齐、手动发货结果归一化、Webhook 重放入口已进入 TS 编译链路;任务 row、viewer context、错误对象、entity id 与重放响应补齐类型
|
||||
182. Docker 内验证通过:
|
||||
- `src/services/admin/*.test.js` 共 8 个用例通过
|
||||
- `npm run typecheck`
|
||||
- `npm run build`
|
||||
- `npm test` 共 139 个用例通过
|
||||
|
||||
## 下一步建议
|
||||
|
||||
|
||||
Reference in New Issue
Block a user