feat(admin): 后台可配领取链接/发消息模板 + 可见买家账号 + 修正皮肤领取链接
**面板新增三项(抖音码速达接入配置)**
- 领取链接基址 (claimLinkBase):带实时预览「皮肤订单最终链接」,并拦截两类误配 ——
带 `#`(`#/claim` 是打手领取页,会把买家带进绑定 UID 流程)、缺 http(s) 协议
- 发消息模板 (messageTemplate):提示可用占位符;模板里没有 `{link}` 直接报错提示
- 付款后发领取消息开关 (claimMessageEnabled)
- 顺带把默认出网超时的展示值对齐后端(10s → 20s)
**后台可见买家提交的账号(运营发货依据)**
- `getAdminTaskDetail` 新增 `claimSubmission`,按 `canViewSensitiveTaskData` 门禁下发
(与 claimToken 明文同一门禁);任务详情新增「买家提交信息」卡片(可一键复制账号)
**修正:皮肤任务的领取链接**
- 详情接口原来用全局 `buildClaimUrl`(默认 hash 形式 `…/#/claim/…`),那是**打手**领取页;
皮肤任务改用 `claimLinkBase + '/' + token`,运营复制给买家的链接才是买家页
- 顺带把「履约渠道」筛选项加上「皮肤自动发货」、任务详情执行器标签加上它、
「来源渠道」加上「抖音码速达」(此前筛不出来抖音订单)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { buildClaimUrl } from '../claim/claim-service.js'
|
||||
import { buildClaimUrl, buildSkinClaimUrl } from '../claim/claim-service.js'
|
||||
import { buildClaimIdentityAdminSummary } from '../claim/claim-identity.js'
|
||||
import { parseSkinClaimSubmission } from '../claim/claim-skin-service.js'
|
||||
import { getClaimTokenById } from '../../repositories/claim-token-repo.js'
|
||||
import {
|
||||
listOrderItemsByOrderId,
|
||||
@@ -35,6 +36,8 @@ import {
|
||||
canRetryTaskStatus,
|
||||
} from '../../domain/task-status.js'
|
||||
import { getAffiliateDashConfig } from '../platforms/affiliate-dash/config.js'
|
||||
import { getDouyinMashidaSourceConfig } from '../platforms/douyin-mashida/source-config-service.js'
|
||||
import { isDouyinMashidaSkinExecutor } from '../fulfillment/executors/types.js'
|
||||
import {
|
||||
mergeAffiliateDashSkuMapping,
|
||||
resolveAffiliateDashDisplayProductName,
|
||||
@@ -307,8 +310,11 @@ export async function getAdminTaskDetail(
|
||||
const taskContext = parseTaskContext(task)
|
||||
const taskState = parseTaskState(task)
|
||||
const viewerContext = createAdminViewerContext(session)
|
||||
// 统一对外领取入口为本站 claim 链接;平台 H5 仅作内部上下文
|
||||
const claimUrl = claimToken ? buildClaimUrl(claimToken.token) : ''
|
||||
// 统一对外领取入口为本站领取链接;平台 H5 仅作内部上下文。
|
||||
// ⚠️ 皮肤自动发货走**路径式**领取页(`<claimLinkBase>/<token>`):
|
||||
// 全局 buildClaimUrl 用的是 orders.claimBaseUrl(默认 hash 形式 `…/#/claim`),
|
||||
// 那是**打手**领取页;皮肤任务若用它,运营复制给买家会把人带进绑定 UID 的打手流程。
|
||||
const claimUrl = resolveAdminTaskClaimUrl(task, claimToken)
|
||||
const screenshotUrl = await resolveAdminTaskScreenshotUrl(task, viewerContext)
|
||||
const cloudSourceLabelMap = buildCloudSourceLabelMap()
|
||||
const kuaishouCloudFulfillment =
|
||||
@@ -384,6 +390,11 @@ export async function getAdminTaskDetail(
|
||||
claimUrl,
|
||||
}
|
||||
: null,
|
||||
// 皮肤自动发货:买家在领取页提交的游戏账号。运营要靠它发货,但属买家隐私,
|
||||
// 因此与 claimToken 的明文一样按 canViewSensitiveTaskData 门禁下发。
|
||||
claimSubmission: viewerContext.canViewSensitiveTaskData
|
||||
? mapClaimSubmissionForAdmin(task)
|
||||
: null,
|
||||
artifacts: viewerContext.canViewSensitiveTaskData ? safeParseJson(task.artifacts_json) : {},
|
||||
screenshotUrl,
|
||||
review: {
|
||||
@@ -429,6 +440,51 @@ export async function getAdminTaskDetail(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 后台展示的领取链接。
|
||||
*
|
||||
* - 皮肤自动发货(`douyin_mashida_skin`):`claimLinkBase` + token(路径式,买家领取页);
|
||||
* 未配 `claimLinkBase` 时退回全局 claim 链接,至少链接不会为空。
|
||||
* - 其它执行器:沿用全局 `buildClaimUrl`(hash 打手领取页),历史行为不变。
|
||||
*/
|
||||
function resolveAdminTaskClaimUrl(
|
||||
task: Pick<TaskRow, 'executor_key'>,
|
||||
claimToken: { token: string } | null | undefined,
|
||||
): string {
|
||||
const token = String(claimToken?.token || '').trim()
|
||||
if (!token) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (isDouyinMashidaSkinExecutor(task.executor_key)) {
|
||||
const skinUrl = buildSkinClaimUrl(getDouyinMashidaSourceConfig().claimLinkBase, token)
|
||||
if (skinUrl) {
|
||||
return skinUrl
|
||||
}
|
||||
}
|
||||
|
||||
return buildClaimUrl(token)
|
||||
}
|
||||
|
||||
/**
|
||||
* 皮肤自动发货买家提交内容(游戏账号)。
|
||||
*
|
||||
* 只回传发货必需的字段;无提交(尚未领取)返回 null,前端据此区分「待领取」。
|
||||
* 敏感数据,调用方必须先判 `canViewSensitiveTaskData`。
|
||||
*/
|
||||
function mapClaimSubmissionForAdmin(task: Partial<TaskRow>): JsonRecord | null {
|
||||
const submission = parseSkinClaimSubmission(task)
|
||||
const gameAccount = String(submission.gameAccount || '').trim()
|
||||
if (!gameAccount) {
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
gameAccount,
|
||||
submittedAt: String(submission.submittedAt || '').trim(),
|
||||
}
|
||||
}
|
||||
|
||||
function mapKuaishouIndustryVoucherContext(value: unknown): JsonRecord | null {
|
||||
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
||||
return null
|
||||
|
||||
@@ -12,6 +12,8 @@ export type AdminTaskDetailView = {
|
||||
order: JsonObject | null
|
||||
orderItem: JsonObject | null
|
||||
claimToken: JsonObject | null
|
||||
/** 皮肤自动发货:买家在领取页提交的游戏账号(敏感数据,按后台角色门禁下发) */
|
||||
claimSubmission: JsonObject | null
|
||||
artifacts: JsonObject
|
||||
screenshotUrl: string
|
||||
review: JsonObject
|
||||
|
||||
Reference in New Issue
Block a user