feat(douyin-mashida): 全面统一为 /h5/<订单号> 直充路径,更新面板提示与直发链接生成

- 抖音码速达买家直充链接与兜底配置基址统一改为 https://<域名>/h5(直充路径为 /h5/<订单号>)
- 前端配置面板示例与提示升级为真实 16 位平台订单号形态(如 /h5/2628301923197355)
- 一键填入域名同步适配 /h5 基址,并在后端发券与发货私信推送中直接生成 /h5/<订单号>
- 数据库本地配置同步更新为 http://localhost/h5

验证方式:前端类型检查与打包构建通过,全量 132 项前端单测与 674 项后端单测全部通过
This commit is contained in:
yml2213
2026-10-10 20:10:09 +08:00
parent d8ce40e346
commit c54dbda344
4 changed files with 46 additions and 29 deletions
@@ -246,23 +246,34 @@ async function notifyBuyerClaimLink(input: {
if (input.config.claimMessageEnabled === false) {
return
}
if (!String(input.config.claimLinkBase || '').trim()) {
return
}
const claimLink = await resolveOrderItemClaimLink({
orderId: input.order.id,
orderItemId: input.orderItem.id,
claimLinkBase: input.config.claimLinkBase,
})
if (!claimLink.claimUrl) {
const claimLinkBase = String(input.config.claimLinkBase || '').trim().replace(/\/+$/, '')
if (!claimLinkBase) {
return
}
const orderNo = resolveReceiptOrderId(input.order, input.orderItem)
let claimUrl = ''
let taskId: number | undefined
if (claimLinkBase.endsWith('/h5') || claimLinkBase.includes('/h5/')) {
claimUrl = `${claimLinkBase}/${orderNo}`
} else {
const claimLink = await resolveOrderItemClaimLink({
orderId: input.order.id,
orderItemId: input.orderItem.id,
claimLinkBase: input.config.claimLinkBase,
})
claimUrl = claimLink.claimUrl
taskId = claimLink.taskId
}
if (!claimUrl) {
return
}
const content = buildDouyinMashidaClaimMessage({
config: input.config,
claimUrl: claimLink.claimUrl,
claimUrl,
sku: input.orderItem.sku_code,
orderNo,
productTitle: input.orderItem.sku_name,
@@ -277,7 +288,7 @@ async function notifyBuyerClaimLink(input: {
orderId: input.order.id,
orderItemId: input.orderItem.id,
orderNo,
taskId: claimLink.taskId,
taskId,
})
}
@@ -140,10 +140,16 @@ export async function resolveDouyinMashidaCertLink(input: {
config: DouyinMashidaSourceConfig
}): Promise<string> {
const fallback = String(input.config.certLink || '').trim()
if (!String(input.config.claimLinkBase || '').trim()) {
const claimLinkBase = String(input.config.claimLinkBase || '').trim().replace(/\/+$/, '')
if (!claimLinkBase) {
return fallback
}
const orderNo = resolveReceiptOrderId(input.order, input.orderItem)
if (claimLinkBase.endsWith('/h5') || claimLinkBase.includes('/h5/')) {
return `${claimLinkBase}/${orderNo}`
}
const claimLink = await resolveOrderItemClaimLink({
orderId: input.order.id,
orderItemId: input.orderItem.id,
@@ -78,8 +78,8 @@ function createEmptyConfig(): AdminDouyinMashidaConfig {
secret: '',
secretMasked: '',
hasSecret: false,
certLink: '',
claimLinkBase: '',
certLink: 'http://localhost/h5',
claimLinkBase: 'http://localhost/h5',
messageTemplate: '您的订单已发货,请点击链接领取:{link}',
claimMessageEnabled: true,
afterVerifyLink: '',
@@ -144,11 +144,11 @@ export function DouyinMashidaPanel() {
const origin = window.location.origin
setConfig((prev) => ({
...prev,
claimLinkBase: `${origin}/claim`,
certLink: `${origin}/redeem`,
afterVerifyLink: `${origin}/redeem`,
claimLinkBase: `${origin}/h5`,
certLink: `${origin}/h5`,
afterVerifyLink: `${origin}/h5`,
}))
showSuccess('已自动填入当前域名,请点击右上角「保存配置」以生效')
showSuccess('已自动填入当前域名(/h5/<订单号>),请点击右上角「保存配置」以生效')
}
/** 向平台订阅或停用推送 */
@@ -439,11 +439,11 @@ export function DouyinMashidaPanel() {
<Row gutter={[20, 16]}>
<Col xs={24} md={12}>
<Space direction="vertical" size={4} style={{ width: '100%' }}>
<Text strong>买家领取页基址 (claimLinkBase)</Text>
<Text strong>买家 H5 直充链接基址 (claimLinkBase)</Text>
<Input
value={config.claimLinkBase}
onChange={(event) => updateField('claimLinkBase', event.target.value)}
placeholder="https://你的公网域名/claim"
placeholder="https://你的公网域名/h5"
/>
{claimLinkPreview ? (
<Text type="secondary" style={{ fontSize: 12 }}>
@@ -464,14 +464,14 @@ export function DouyinMashidaPanel() {
<Col xs={24} md={12}>
<Space direction="vertical" size={4} style={{ width: '100%' }}>
<Text strong>通用兑换链接 (certLink)</Text>
<Text strong>兜底领取链接 (certLink)</Text>
<Input
value={config.certLink}
onChange={(event) => updateField('certLink', event.target.value)}
placeholder="https://你的公网域名/redeem"
placeholder="https://你的公网域名/h5"
/>
<Text type="secondary" style={{ fontSize: 12 }}>
通用兜底兑换链接(无商品映射或旧单卡券兜底)
通用兜底链接,默认与直充 H5 基址保持一致
</Text>
</Space>
</Col>
+5 -5
View File
@@ -64,9 +64,9 @@ export function describeMissingConfigFields(config: MissingConfigCheck): string[
}
/**
* 面板预览用的示例 token(48 位 hex,与真实 claim token 形态一致)。
* 面板预览用的示例订单号(与真实 16 位平台订单号形态一致)。
*/
const CLAIM_LINK_PREVIEW_TOKEN = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'
const CLAIM_LINK_PREVIEW_TOKEN = '2628301923197355'
/**
* 拼一条领取链接预览:`claimLinkBase` 去尾斜杠 + '/' + token。
@@ -88,16 +88,16 @@ export function buildDouyinMashidaClaimLinkPreview(
* 领取链接基址的误配提示(无问题返回空串)。
*
* 重点拦 `#`:`#/claim/{token}` 是**打手**领取页(要绑游戏 UID),
* 皮肤买家链接必须是路径式,配错会把买家带到打手流程里。
* 皮肤买家链接必须是路径式,例如 https://你的域名/h5
*/
export function describeClaimLinkBaseWarning(claimLinkBase: string): string {
const text = String(claimLinkBase ?? '').trim()
if (!text) return ''
if (text.includes('#')) {
return '不要带 #:#/claim 是打手领取页,皮肤买家链接请用路径式,例如 https://你的域名/claim'
return '不要带 #:#/claim 是打手领取页,买家直充链接请用路径式,例如 https://你的域名/h5'
}
if (!/^https?:\/\//i.test(text)) {
return '请填完整地址(http:// 或 https:// 开头),例如 https://你的域名/claim'
return '请填完整地址(http:// 或 https:// 开头),例如 https://你的域名/h5'
}
return ''
}