chore: 初始化文档站仓库
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
// 向测试环境补充标签与自定义规则演示数据。
|
||||
import axios from 'axios'
|
||||
import { login } from './browser.js'
|
||||
import { API_URL } from './config.js'
|
||||
|
||||
/** 需要补充的标签:名称与颜色 */
|
||||
const TAGS: Array<{ name: string; color: string }> = [
|
||||
{ name: '咖啡', color: '#8B5A2B' },
|
||||
{ name: '外卖', color: '#F97316' },
|
||||
]
|
||||
|
||||
/**
|
||||
* 创建标签并返回其主键。
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @param name 标签名称
|
||||
* @param color 标签颜色
|
||||
* @returns 标签主键
|
||||
*/
|
||||
async function createTag(token: string, name: string, color: string): Promise<number> {
|
||||
const headers = { Authorization: `Bearer ${token}` }
|
||||
const res = await axios.post(`${API_URL}/tag`, { name, color }, { headers })
|
||||
console.log(`标签 ${name} -> ${res.data.code}`)
|
||||
// 创建接口不返回主键,统一从列表中按名称查找
|
||||
const list = await axios.get(`${API_URL}/tag/list`, { headers })
|
||||
const found = (list.data.data as Array<{ id: number; name: string }>).find((t) => t.name === name)
|
||||
if (!found) throw new Error(`未找到标签: ${name}`)
|
||||
return found.id
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建自定义归类规则。
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @param payload 规则请求体
|
||||
*/
|
||||
async function createRule(token: string, payload: Record<string, unknown>): Promise<void> {
|
||||
const res = await axios.post(`${API_URL}/rule`, payload, { headers: { Authorization: `Bearer ${token}` } })
|
||||
console.log(`规则 ${payload.name} -> ${res.data.code}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查询分类主键。
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @param name 分类名称
|
||||
* @returns 分类主键
|
||||
*/
|
||||
async function getCategoryId(token: string, name: string): Promise<number> {
|
||||
const headers = { Authorization: `Bearer ${token}` }
|
||||
const res = await axios.get(`${API_URL}/category/list`, { headers })
|
||||
const found = (res.data.data as Array<{ id: number; name: string }>).find((c) => c.name === name)
|
||||
if (!found) throw new Error(`未找到分类: ${name}`)
|
||||
return found.id
|
||||
}
|
||||
|
||||
/**
|
||||
* 按名称查询标签主键,不存在时创建。
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @param name 标签名称
|
||||
* @param color 标签颜色
|
||||
* @returns 标签主键
|
||||
*/
|
||||
async function getTagId(token: string, name: string, color: string): Promise<number> {
|
||||
const headers = { Authorization: `Bearer ${token}` }
|
||||
const res = await axios.get(`${API_URL}/tag/list`, { headers })
|
||||
const found = (res.data.data as Array<{ id: number; name: string }>).find((t) => t.name === name)
|
||||
if (found) return found.id
|
||||
return createTag(token, name, color)
|
||||
}
|
||||
|
||||
/** 交易记录(用于给若干记录打标签,供「AI 生成规则」截图使用) */
|
||||
interface TransactionRow {
|
||||
id: number
|
||||
categoryId: number | null
|
||||
type: string
|
||||
amount: number
|
||||
channel: string | null
|
||||
remark: string | null
|
||||
transactionTime: string
|
||||
includeInStats: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* 给若干记录打上标签,便于「AI 生成规则」按已打标签记录归纳。
|
||||
*
|
||||
* @param token 访问令牌
|
||||
* @param coffeeId 咖啡标签主键
|
||||
* @param takeoutId 外卖标签主键
|
||||
* @param bigAmountId 大额消费标签主键
|
||||
*/
|
||||
async function tagSomeTransactions(
|
||||
token: string,
|
||||
coffeeId: number,
|
||||
takeoutId: number,
|
||||
bigAmountId: number,
|
||||
): Promise<void> {
|
||||
const headers = { Authorization: `Bearer ${token}` }
|
||||
const res = await axios.get(`${API_URL}/transaction/page`, { headers, params: { page: 1, size: 50 } })
|
||||
const rows = (res.data.data?.records ?? []) as TransactionRow[]
|
||||
let tagged = 0
|
||||
for (const row of rows) {
|
||||
if (tagged >= 6) break
|
||||
const remark = row.remark ?? ''
|
||||
let tagIds: number[] = []
|
||||
if (remark.includes('星巴克') || remark.includes('瑞幸') || remark.includes('咖啡')) {
|
||||
tagIds = [coffeeId]
|
||||
} else if (remark.includes('美团') || remark.includes('外卖') || remark.includes('饿了么')) {
|
||||
tagIds = [takeoutId]
|
||||
} else if (Number(row.amount) >= 500) {
|
||||
tagIds = [bigAmountId]
|
||||
}
|
||||
if (tagIds.length === 0) continue
|
||||
await axios.put(`${API_URL}/transaction/${row.id}`, {
|
||||
categoryId: row.categoryId,
|
||||
type: row.type,
|
||||
amount: row.amount,
|
||||
channel: row.channel,
|
||||
remark: row.remark,
|
||||
transactionTime: row.transactionTime,
|
||||
includeInStats: row.includeInStats,
|
||||
tagIds,
|
||||
}, { headers })
|
||||
tagged++
|
||||
}
|
||||
console.log(`已为 ${tagged} 条记录打标签`)
|
||||
}
|
||||
|
||||
/** 清空现有规则,避免重复创建 */
|
||||
async function clearRules(token: string): Promise<void> {
|
||||
const headers = { Authorization: `Bearer ${token}` }
|
||||
const res = await axios.get(`${API_URL}/rule/list`, { headers })
|
||||
for (const rule of res.data.data as Array<{ id: number }>) {
|
||||
await axios.delete(`${API_URL}/rule/${rule.id}`, { headers })
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const token = await login()
|
||||
await clearRules(token)
|
||||
const coffeeId = await getTagId(token, '咖啡', '#8B5A2B')
|
||||
const takeoutId = await getTagId(token, '外卖', '#F97316')
|
||||
const bigAmountId = await getTagId(token, '大额消费', '#F97316')
|
||||
const diningId = await getCategoryId(token, '餐饮')
|
||||
const transportId = await getCategoryId(token, '交通')
|
||||
console.log('标签:', { 咖啡: coffeeId, 外卖: takeoutId, 大额消费: bigAmountId })
|
||||
|
||||
const rules: Array<Record<string, unknown>> = [
|
||||
{ name: '星巴克归入餐饮', enabled: true, type: 'EXPENSE', keyword: '星巴克', categoryId: diningId, tagIds: [coffeeId] },
|
||||
{ name: '滴滴出行归入交通', enabled: true, type: 'EXPENSE', keyword: '滴滴', categoryId: transportId },
|
||||
{ name: '大额支出标记', enabled: true, type: 'EXPENSE', minAmount: 500, tagIds: [bigAmountId] },
|
||||
]
|
||||
for (const rule of rules) {
|
||||
await createRule(token, rule)
|
||||
}
|
||||
|
||||
// 给若干记录打标签,供「AI 生成规则」截图
|
||||
await tagSomeTransactions(token, coffeeId, takeoutId, bigAmountId)
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error('FAIL', err)
|
||||
process.exit(1)
|
||||
})
|
||||
Reference in New Issue
Block a user