130 lines
4.7 KiB
TypeScript
130 lines
4.7 KiB
TypeScript
import { extractXmlValue, normalizeAppMessageContent } from './xmlExtractor'
|
|
|
|
export function buildGroupNicknameIdCandidates(values: Array<string | undefined | null>): string[] {
|
|
const set = new Set<string>()
|
|
for (const rawValue of values) {
|
|
const raw = String(rawValue || '').trim()
|
|
if (!raw) continue
|
|
set.add(raw)
|
|
}
|
|
return Array.from(set)
|
|
}
|
|
|
|
function normalizeGroupNicknameIdentity(value: string): string {
|
|
return String(value || '').trim().toLowerCase()
|
|
}
|
|
|
|
function normalizeGroupNickname(value: string): string {
|
|
const trimmed = (value || '').trim()
|
|
if (!trimmed) return ''
|
|
const cleaned = trimmed.replace(/[\x00-\x1F\x7F]/g, '')
|
|
if (!cleaned) return ''
|
|
if (/^[,"'“”‘’,、]+$/.test(cleaned)) return ''
|
|
return cleaned
|
|
}
|
|
|
|
export function resolveGroupNicknameByCandidates(groupNicknamesMap: Map<string, string>, candidates: Array<string | undefined | null>): string {
|
|
const idCandidates = buildGroupNicknameIdCandidates(candidates)
|
|
if (idCandidates.length === 0) return ''
|
|
|
|
let resolved = ''
|
|
for (const id of idCandidates) {
|
|
const normalizedId = normalizeGroupNicknameIdentity(id)
|
|
if (!normalizedId) continue
|
|
const candidateNickname = normalizeGroupNickname(groupNicknamesMap.get(normalizedId) || '')
|
|
if (!candidateNickname) continue
|
|
if (!resolved) {
|
|
resolved = candidateNickname
|
|
continue
|
|
}
|
|
if (resolved !== candidateNickname) return ''
|
|
}
|
|
|
|
return resolved
|
|
}
|
|
|
|
export async function resolveTransferDesc(
|
|
content: string,
|
|
myWxid: string,
|
|
groupNicknamesMap: Map<string, string>,
|
|
getContactName: (username: string) => Promise<string>
|
|
): Promise<string | null> {
|
|
const normalizedContent = normalizeAppMessageContent(content || '')
|
|
if (!normalizedContent) return null
|
|
|
|
const xmlType = extractXmlValue(normalizedContent, 'type')
|
|
if (xmlType && xmlType !== '2000') return null
|
|
|
|
const payerUsername = extractXmlValue(normalizedContent, 'payer_username')
|
|
const receiverUsername = extractXmlValue(normalizedContent, 'receiver_username')
|
|
if (!payerUsername || !receiverUsername) return null
|
|
|
|
const cleanedMyWxid = myWxid
|
|
|
|
const resolveName = async (username: string): Promise<string> => {
|
|
if (myWxid && (username === myWxid || username === cleanedMyWxid)) {
|
|
const groupNick = resolveGroupNicknameByCandidates(groupNicknamesMap, [username, myWxid, cleanedMyWxid])
|
|
if (groupNick) return groupNick
|
|
return '我'
|
|
}
|
|
const groupNick = resolveGroupNicknameByCandidates(groupNicknamesMap, [username])
|
|
if (groupNick) return groupNick
|
|
return getContactName(username)
|
|
}
|
|
|
|
const [payerName, receiverName] = await Promise.all([
|
|
resolveName(payerUsername),
|
|
resolveName(receiverUsername)
|
|
])
|
|
|
|
return `${payerName} 转账给 ${receiverName}`
|
|
}
|
|
|
|
export function isSameWxid(lhs?: string, rhs?: string): boolean {
|
|
const left = new Set(buildGroupNicknameIdCandidates([lhs]).map((id) => id.toLowerCase()))
|
|
if (left.size === 0) return false
|
|
const right = buildGroupNicknameIdCandidates([rhs]).map((id) => id.toLowerCase())
|
|
return right.some((id) => left.has(id))
|
|
}
|
|
|
|
export function getTransferPrefix(content: string, myWxid?: string, senderWxid?: string, isSend?: boolean): '[转账]' | '[转账收款]' {
|
|
const normalizedContent = normalizeAppMessageContent(content || '')
|
|
if (!normalizedContent) return '[转账]'
|
|
|
|
const paySubtype = extractXmlValue(normalizedContent, 'paysubtype')
|
|
if (paySubtype === '3') return '[转账收款]'
|
|
if (paySubtype === '1') return '[转账]'
|
|
|
|
const payerUsername = extractXmlValue(normalizedContent, 'payer_username')
|
|
const receiverUsername = extractXmlValue(normalizedContent, 'receiver_username')
|
|
const senderIsPayer = senderWxid ? isSameWxid(senderWxid, payerUsername) : false
|
|
const senderIsReceiver = senderWxid ? isSameWxid(senderWxid, receiverUsername) : false
|
|
|
|
if (senderWxid) {
|
|
if (senderIsReceiver && !senderIsPayer) return '[转账]'
|
|
if (senderIsPayer && !senderIsReceiver) return '[转账收款]'
|
|
}
|
|
|
|
if (myWxid) {
|
|
if (isSameWxid(myWxid, receiverUsername)) return '[转账]'
|
|
if (isSameWxid(myWxid, payerUsername)) return '[转账收款]'
|
|
}
|
|
|
|
return '[转账]'
|
|
}
|
|
|
|
export function isTransferExportContent(content: string): boolean {
|
|
return content.startsWith('[转账]') || content.startsWith('[转账收款]')
|
|
}
|
|
|
|
export function appendTransferDesc(content: string, transferDesc: string): string {
|
|
const prefix = content.startsWith('[转账收款]') ? '[转账收款]' : '[转账]'
|
|
return content.replace(prefix, `${prefix} (${transferDesc})`)
|
|
}
|
|
|
|
export function extractAmountFromText(text: string): string | null {
|
|
if (!text) return null
|
|
const match = /([¥¥]\s*\d+(?:\.\d+)?|\d+(?:\.\d+)?)/.exec(text)
|
|
return match ? match[1].replace(/\s+/g, '') : null
|
|
}
|