chore: 初始化文档站仓库

This commit is contained in:
2026-09-21 13:38:20 +08:00
commit a4ae7ac979
58 changed files with 4622 additions and 0 deletions
+104
View File
@@ -0,0 +1,104 @@
// 向测试环境灌入演示数据:登录测试账号,解析并确认导入样例账单。
import { readFile } from 'node:fs/promises'
import { basename, join, resolve } from 'node:path'
import axios from 'axios'
import { login } from './browser.js'
import { API_URL, ROOT } from './config.js'
/** 样例账单目录(doc-site 内的虚构样例,全部为虚假数据,禁止使用真实账单) */
const BILL_DIR = resolve(ROOT, 'scripts', 'samples')
/** 待导入样例:账单类型、相对路径、解压密码(仅使用虚构数据) */
const SAMPLES: Array<[string, string, string | null]> = [
['ALIPAY', 'alipay_fake.csv', null],
['TAOBAO', 'taobao_fake.xlsx', null],
['JD', 'jd_fake.csv', null],
]
interface ParsedRow {
externalNo: string
transactionTime: string
type: string
amount: number
counterparty?: string | null
product?: string | null
includeInStats?: boolean
importable?: boolean
rawData?: string | null
}
/**
* 调用解析接口解析账单文件。
*
* @param token 访问令牌
* @param billType 账单类型
* @param path 账单文件路径
* @param password 解压密码
* @returns 解析结果数据
*/
async function parseBill(token: string, billType: string, path: string, password: string | null): Promise<any> {
const buf = await readFile(path)
const form = new FormData()
form.append('file', new Blob([buf]), basename(path))
form.append('billType', billType)
if (password) form.append('password', password)
const res = await axios.post(`${API_URL}/transaction/import/parse`, form, {
headers: { Authorization: `Bearer ${token}` },
timeout: 120000,
})
if (res.data.code !== 200) throw new Error(res.data.message)
return res.data.data
}
/**
* 确认导入解析出的账单行。
*
* @param token 访问令牌
* @param billType 账单类型
* @param rows 解析结果行
* @returns 导入结果数据
*/
async function confirmBill(token: string, billType: string, rows: ParsedRow[]): Promise<any> {
const items = rows
.filter((r) => r.importable !== false)
.map((r) => ({
externalNo: r.externalNo,
transactionTime: r.transactionTime,
type: r.type,
amount: r.amount,
counterparty: r.counterparty ?? null,
product: r.product ?? null,
includeInStats: r.includeInStats ?? true,
rawData: r.rawData ?? null,
}))
const res = await axios.post(
`${API_URL}/transaction/import/confirm`,
{ billType, items },
{ headers: { Authorization: `Bearer ${token}` }, timeout: 120000 },
)
if (res.data.code !== 200) throw new Error(res.data.message)
return res.data.data
}
async function main(): Promise<void> {
const token = await login()
console.log('登录成功')
for (const [billType, relPath, password] of SAMPLES) {
const path = join(BILL_DIR, relPath)
try {
const data = await parseBill(token, billType, path, password)
const rows: ParsedRow[] = data.rows ?? []
const importable = rows.filter((r) => r.importable !== false)
console.log(`[解析成功] ${billType}: 共 ${rows.length} 行,可导入 ${importable.length} 行`)
const result = await confirmBill(token, billType, rows)
console.log(`[导入成功] ${billType}: ${JSON.stringify(result)}`)
} catch (err) {
console.log(`[失败] ${billType}: ${err}`)
}
}
}
main().catch((err) => {
console.error('FAIL', err)
process.exit(1)
})