feat: map transfer/hb status labels into export and chat cards

This commit is contained in:
wuyouMaster
2026-09-24 19:01:15 +08:00
parent 95b3ba6121
commit 88ee3f19bb
10 changed files with 555 additions and 12 deletions
+68
View File
@@ -457,6 +457,74 @@ describe('export media', () => {
expect(html).toContain("if (event.key === 'Escape')")
expect(html).toContain('closeLightbox()')
})
it('always surfaces transfer and red-packet amount, memo and status wording', () => {
const html = renderExportPage('支付可读导出')
const dom = new JSDOM(html, { runScripts: 'outside-only' })
const messages: Message[] = [
{
...messageForArchive('transfer-paid', 'fixture', '支付可读导出', '收到转账2900.00元。', 1),
type: '转账',
contentData: {
type: 'share',
typeVal: '2000',
title: '微信转账',
des: '收到转账2900.00元。',
url: '',
transfer: {
amountText: '¥2900.00',
payMemo: '房租',
transferStatus: '2',
transferStatusText: '已收款',
transferId: '1000050001202609130232821248942',
paySubtype: '3'
}
}
},
{
...messageForArchive('hb-claimed', 'fixture', '支付可读导出', '我给你发了一个红包,赶紧去拆!', 2),
type: '微信红包',
contentData: {
type: 'redPacket',
title: '中秋快乐',
description: '我给你发了一个红包,赶紧去拆!',
pay: {
sendTitle: '中秋快乐',
sceneText: '微信红包',
hbStatus: '1',
redPacketStatusText: '已领取',
sendId: '1000039801202609247176036834007',
hbType: '1'
}
}
}
]
Object.assign(dom.window, {
__WECHAT_EXPORT__: {
version: 1,
sourceId: 'fixture',
name: '支付可读导出',
exportedAt: '2026-09-24T12:00:00.000Z',
messages
}
})
dom.window.eval(inlineScriptOf(html))
const cards = [...dom.window.document.querySelectorAll('.payment-content')]
expect(cards).toHaveLength(2)
const transfer = cards.find((node) => node.classList.contains('transfer'))!
const redPacket = cards.find((node) => node.classList.contains('red-packet'))!
// 即使消息带 des,金额/备注/状态也不能被盖住。
expect(transfer.textContent).toContain('¥2900.00')
expect(transfer.textContent).toContain('备注:房租')
expect(transfer.textContent).toContain('已收款')
expect(transfer.textContent).toContain('收到转账2900.00元。')
expect(transfer.textContent).toContain('单号 1000050001202609130232821248942')
expect(redPacket.textContent).toContain('已领取')
expect(redPacket.textContent).toContain('我给你发了一个红包,赶紧去拆!')
dom.window.close()
})
})
function messageForArchive(
+84
View File
@@ -206,4 +206,88 @@ describe('message parser', () => {
messageType: 999
})
})
it('parses transfer wcpayinfo fields (type 2000)', () => {
// 2026-09 真机转账采样字段名(含微信原文 transcationid 拼写)
const xml = [
'<msg><appmsg appid="" sdkver="">',
'<title><![CDATA[微信转账]]></title>',
'<des><![CDATA[收到转账2900.00元。]]></des>',
'<type>2000</type>',
'<url><![CDATA[https://support.weixin.qq.com/upgrade]]></url>',
'<wcpayinfo>',
'<paysubtype>3</paysubtype>',
'<feedesc><![CDATA[¥2900.00]]></feedesc>',
'<transcationid><![CDATA[53010003370089202609134087894875]]></transcationid>',
'<transferid><![CDATA[1000050001202609130232821248942]]></transferid>',
'<invalidtime><![CDATA[1789348128]]></invalidtime>',
'<begintransfertime><![CDATA[1789261728]]></begintransfertime>',
'<effectivedate><![CDATA[1]]></effectivedate>',
'<pay_memo><![CDATA[房租]]></pay_memo>',
'<receiver_username><![CDATA[wxid_receiver]]></receiver_username>',
'<payer_username><![CDATA[]]></payer_username>',
'<transfer_status>2</transfer_status>',
'</wcpayinfo></appmsg></msg>'
].join('')
const parsed = parseMessageContent(xml, 49)
expect(parsed).toMatchObject({
type: 'share',
typeVal: '2000',
title: '微信转账',
transfer: {
paySubtype: '3',
amountText: '¥2900.00',
transcationId: '53010003370089202609134087894875',
transferId: '1000050001202609130232821248942',
invalidTime: '1789348128',
beginTransferTime: '1789261728',
effectiveDate: '1',
payMemo: '房租',
receiverUsername: 'wxid_receiver',
transferStatus: '2',
transferStatusText: '已收款'
}
})
})
it('parses red packet wcpayinfo fields (type 2001 / mmpayhb)', () => {
const xml = [
'<msg><appmsg appid="" sdkver="">',
'<title><![CDATA[中秋快乐]]></title>',
'<des><![CDATA[我给你发了一个红包,赶紧去拆!]]></des>',
'<type>2001</type>',
'<wcpayinfo>',
'<templateid><![CDATA[7a2a165d31da7fce6dd77e05c300028a]]></templateid>',
'<url><![CDATA[https://wxapp.tenpay.com/mmpayhb/wxhb_personalreceive?msgtype=1&sendid=1000039801202609247176036834007&sign=abc]]></url>',
'<iconurl><![CDATA[https://wx.gtimg.com/hongbao/1800/hb.png]]></iconurl>',
'<receivertitle><![CDATA[恭喜发财,大吉大利]]></receivertitle>',
'<sendertitle><![CDATA[中秋快乐,望重置]]></sendertitle>',
'<scenetext><![CDATA[微信红包]]></scenetext>',
'<senderdes><![CDATA[查看红包]]></senderdes>',
'<receiverdes><![CDATA[领取红包]]></receiverdes>',
'<nativeurl><![CDATA[wxpay://c2cbizmessagehandler/hongbao/receivehongbao?sendid=1]]></nativeurl>',
'<hb_type>1</hb_type>',
'<hb_status>1</hb_status>',
'<receive_status>2</receive_status>',
'</wcpayinfo></appmsg></msg>'
].join('')
const parsed = parseMessageContent(xml, 49)
expect(parsed).toMatchObject({
type: 'redPacket',
title: '中秋快乐,望重置',
pay: {
templateId: '7a2a165d31da7fce6dd77e05c300028a',
receiveTitle: '恭喜发财,大吉大利',
sendTitle: '中秋快乐,望重置',
sceneText: '微信红包',
senderDes: '查看红包',
receiverDes: '领取红包',
sendId: '1000039801202609247176036834007',
hbType: '1',
hbStatus: '1',
receiveStatus: '2',
redPacketStatusText: '已领取'
}
})
})
})
+31
View File
@@ -0,0 +1,31 @@
import { describe, expect, it } from 'vitest'
import {
describePaySubtype,
describeRedPacketStatus,
describeTransferStatus
} from '../../src/shared/payment-status'
describe('payment status labels', () => {
it('maps transfer_status numbers and keywords to UI wording', () => {
expect(describeTransferStatus(2)).toBe('已收款')
expect(describeTransferStatus('3')).toBe('已退还')
expect(describeTransferStatus('paid')).toBe('已收款')
expect(describeTransferStatus('收款方过期未收款,已退还')).toBe('过期未收款,已退还')
expect(describeTransferStatus(undefined)).toBeUndefined()
})
it('maps red packet hb_status / receive_status', () => {
expect(describeRedPacketStatus('0', undefined)).toBe('待领取')
expect(describeRedPacketStatus('1', undefined)).toBe('已领取')
expect(describeRedPacketStatus(undefined, '2')).toBe('已被领完')
expect(describeRedPacketStatus('已被领取', undefined)).toBe('已领取')
expect(describeRedPacketStatus(undefined, undefined)).toBeUndefined()
})
it('passes through unknown status values', () => {
expect(describeTransferStatus('99-custom')).toBe('99-custom')
expect(describeRedPacketStatus('99', '98')).toBe('99')
expect(describePaySubtype('3')).toBe('收款')
expect(describePaySubtype('9')).toBe('9')
})
})