feat 完善注释

This commit is contained in:
Ironsp
2026-10-01 17:24:57 +08:00
parent 2b59f68fd7
commit 9f4a5c7cda
183 changed files with 485 additions and 3615 deletions

View File

@@ -17,10 +17,6 @@ import { toBills, toPlanBills, type PlanLike } from '@/utils/billVo'
import { toPayMethod } from '@/utils/payMeta'
import { request } from '@/utils/request'
// 说明:账单 / 支付相关接口已接后端真数据;仅「发票」与「统计」仍是 mock。
// 另有已下线的遗留演示扫码页(pay.vue)用的一组 mock,见文件中部注释。
/** 遗留演示页用的假账单(真账单走 `GET /web/bill/list`,不读这里) */
const MOCK_BILLS: Bill[] = [
{
id: 'bill-001',
@@ -80,7 +76,6 @@ const MOCK_BILLS: Bill[] = [
},
]
/** 发票 mock(可变:申请开票后状态在前端内存中翻转演示) */
const MOCK_INVOICES: Invoice[] = [
{
id: 'invoice-001',
@@ -113,7 +108,6 @@ const MOCK_INVOICES: Invoice[] = [
},
]
/** 发票抬头 mock(可变,CRUD 在前端内存中演示) */
const MOCK_TITLES: InvoiceTitle[] = [
{
id: 'title-001',
@@ -131,10 +125,8 @@ const MOCK_TITLES: InvoiceTitle[] = [
},
]
/** 支付进行单(billId → 当前二维码) */
const MOCK_PAYMENTS = new Map<string, Payment>()
/** 已产生支付结果的账单(billId → 结果),预置已支付账单 */
const MOCK_RESULTS = new Map<string, PaymentResult>()
MOCK_RESULTS.set('bill-001', {
method: 'wechat',
@@ -163,18 +155,15 @@ const DEFAULT_STATS: FinanceStats = {
],
}
/** 财务统计(period 为展示周期参数,mock 恒返回原型数据) */
export function getFinanceStats(period?: string): Promise<FinanceStats> {
void period
return Promise.resolve(structuredClone(DEFAULT_STATS))
}
/** 真账单 id 一定是纯数字(`vm_bill.id` 是 bigint);非数字只可能来自已下线的演示mock */
function isRealBillId(id: string): boolean {
return /^\d+$/.test(id)
}
/** 拉取「当前登录用户」的全部账单(`GET /web/bill/list`,不带 ids) */
async function fetchOwnBills(): Promise<Bill[]> {
const rows = await request<BillVo[]>({ url: '/web/bill/list', method: 'get' })
return toBills(rows)
@@ -190,13 +179,6 @@ function matchBillKeyword(item: Bill, keyword: string): boolean {
)
}
/**
* 账单列表(筛选 + 分页)。
*
* <p>⚠️ `GET /web/bill/list` 只按登录用户返回**全量**账单,后端没有 pageNum / keyword /
* status 查询参数;单个客户的账单量级是「几条 ~ 几十条」,故筛选与分页放在前端做。
* 若日后账单量变大,应给该端点补后端分页参数,这里再切成一次请求。</p>
*/
export async function getBillList(query: BillQuery): Promise<PageResult<Bill>> {
const all = await fetchOwnBills()
const filtered = all.filter((item) => {
@@ -207,22 +189,15 @@ export async function getBillList(query: BillQuery): Promise<PageResult<Bill>> {
return { list: filtered.slice(start, start + query.pageSize), total: filtered.length }
}
/** 账单详情(不存在返回 null) */
export async function getBillDetail(id: string): Promise<Bill | null> {
const rows = await request<BillVo[]>({ url: '/web/bill/list', method: 'get', params: { ids: id } })
return toBills(rows)[0] ?? null
}
// ═══════════════════════════════════════════════════════════════════════
// 遗留演示扫码页(`/finance/bills/:id/pay`,页面 pay.vue)
// ---------------------------------------------------------------------
// 该页已无任何入口(收银台 checkout.vue 取代了它),但按既定决定保留。
// 它用的是下面这几个 mock 函数,与真账单互不干扰:真账单 id 一定是数字,
// 假账单 id 形如 `bill-001`,两条路径靠 `isRealBillId` 分流。
// 若要下线该页,这一整段(含 MOCK_PAYMENTS / MOCK_RESULTS)可一并删除。
// ═══════════════════════════════════════════════════════════════════════
/** 创建支付单(遗留页演示用:生成二维码支付信息) */
export function createPayment(billId: string, method: PayMethod): Promise<Payment> {
const bill = MOCK_BILLS.find((item) => item.id === billId)
if (!bill) return Promise.reject(new Error('账单不存在'))
@@ -236,21 +211,10 @@ export function createPayment(billId: string, method: PayMethod): Promise<Paymen
return Promise.resolve({ ...payment })
}
/** 切换支付方式(遗留页演示用:刷新二维码) */
export function switchPaymentMethod(billId: string, method: PayMethod): Promise<Payment> {
return createPayment(billId, method)
}
/**
* 查询支付结果。
*
* <p><b>真账单</b>:直接读 `vm_bill` —— 账单被回调置为 PAID 时,`pay_time` /
* `transaction_no` / `pay_channel` 已由后端一并回写,这里拼出结果页所需结构;
* 未支付则返回 null。</p>
*
* <p><b>假账单</b>(id 形如 `bill-001`):走下面的遗留演示逻辑。真账单 id 一定是数字,
* 故只有已下线的 pay.vue 会命中这条分支。</p>
*/
export async function getPayResult(billId: string): Promise<PaymentResult | null> {
if (isRealBillId(billId)) {
const bill = await getBillDetail(billId)
@@ -266,7 +230,6 @@ export async function getPayResult(billId: string): Promise<PaymentResult | null
return getLegacyPayResult(billId)
}
/** 遗留演示:假账单的支付结果(详见上方说明,随 pay.vue 一起可删) */
function getLegacyPayResult(billId: string): Promise<PaymentResult | null> {
const existing = MOCK_RESULTS.get(billId)
if (existing) return Promise.resolve(structuredClone(existing))
@@ -275,7 +238,6 @@ function getLegacyPayResult(billId: string): Promise<PaymentResult | null> {
const bill = MOCK_BILLS.find((item) => item.id === billId)
if (!payment || !bill) return Promise.resolve(null)
// 演示:存在支付单即视为完成支付(createPayment 由「完成支付」触发)
const tradeNo = bill.tradeNo ?? 'T20260819153035678K2M001'
if (bill.status !== '已支付') {
bill.status = '已支付'
@@ -302,7 +264,6 @@ function matchInvoiceKeyword(item: Invoice, keyword: string): boolean {
)
}
/** 发票列表(筛选 + 分页) */
export function getInvoiceList(query: InvoiceQuery): Promise<PageResult<Invoice>> {
const filtered = MOCK_INVOICES.filter((item) => {
if (query.status !== 'all' && item.status !== query.status) return false
@@ -315,7 +276,6 @@ export function getInvoiceList(query: InvoiceQuery): Promise<PageResult<Invoice>
})
}
/** 申请开票(演示:状态置为开票中),返回最新发票 */
export function applyInvoice(id: string): Promise<Invoice> {
const found = MOCK_INVOICES.find((item) => item.id === id)
if (!found) return Promise.reject(new Error('发票记录不存在'))
@@ -323,12 +283,10 @@ export function applyInvoice(id: string): Promise<Invoice> {
return Promise.resolve({ ...found })
}
/** 发票抬头列表 */
export function getInvoiceTitles(): Promise<InvoiceTitle[]> {
return Promise.resolve(MOCK_TITLES.map((item) => ({ ...item })))
}
/** 新增发票抬头 */
export function createInvoiceTitle(payload: InvoiceTitlePayload): Promise<InvoiceTitle> {
const created: InvoiceTitle = {
id: `title-${Date.now()}`,
@@ -339,7 +297,6 @@ export function createInvoiceTitle(payload: InvoiceTitlePayload): Promise<Invoic
return Promise.resolve({ ...created })
}
/** 编辑发票抬头 */
export function updateInvoiceTitle(id: string, payload: InvoiceTitlePayload): Promise<InvoiceTitle> {
const found = MOCK_TITLES.find((item) => item.id === id)
if (!found) return Promise.reject(new Error('抬头不存在'))
@@ -349,7 +306,6 @@ export function updateInvoiceTitle(id: string, payload: InvoiceTitlePayload): Pr
return Promise.resolve({ ...found })
}
/** 删除发票抬头 */
export function deleteInvoiceTitle(id: string): Promise<void> {
const index = MOCK_TITLES.findIndex((item) => item.id === id)
if (index < 0) return Promise.reject(new Error('抬头不存在'))
@@ -357,7 +313,6 @@ export function deleteInvoiceTitle(id: string): Promise<void> {
return Promise.resolve()
}
/** 设为默认抬头(唯一默认) */
export function setDefaultTitle(id: string): Promise<InvoiceTitle[]> {
for (const item of MOCK_TITLES) {
item.isDefault = item.id === id
@@ -365,30 +320,13 @@ export function setDefaultTitle(id: string): Promise<InvoiceTitle[]> {
return Promise.resolve(MOCK_TITLES.map((item) => ({ ...item })))
}
/** 导出报表(演示:稍后由页面提示成功) */
export function exportReport(): Promise<void> {
return Promise.resolve()
}
// ═══════════════════════════════════════════════════════════════════════
// 收银台(确认支付)——以下为**真实后端接口**,不是 mock
// 后端类:vermis-modules/…/controller/pc/pay/WebScanPayController,类级 @SaIgnore(匿名可调)
// ═══════════════════════════════════════════════════════════════════════
/**
* 取收银台「订单明细」——**复用项目详情「合同财务」那个现成接口**,不另开端点。
*
* <p>`GET /web/requirementPool/get/finance/{requirementId}`(`ProjectRequirementUserController`)
* 的 `{id}` 是**需求 id**;后端把「需求 + 项目」拼成一条联合结构(`loadProject` 用
* `vm_rd_project.requirement_id` 反查项目),再把该项目的付款计划随 `billPlans` 一并下发。</p>
*
* <p>本栈支付口径是 `vm_bill_plan.id`(`vm_finance_payment.bill_id` 实测存的就是计划 id),
* 故订单明细直接取这份 `billPlans`,只保留**本次要付的期**:
* URL 带 `ids`(期次 id)时按期次过滤,不带则取状态为「待支付」的期。</p>
*
* @param requirementId 需求 id(项目详情路由 `:id`)
* @param ids 期次 id(`vm_bill_plan.id`)列表,可选,用于精确指定付哪一期
*/
export async function getCheckoutBills(requirementId: string, ids: string[] = []): Promise<Bill[]> {
if (!/^\d+$/.test(requirementId)) return []
const vo = await request<{ billPlans?: PlanLike[] }>({
@@ -401,12 +339,6 @@ export async function getCheckoutBills(requirementId: string, ids: string[] = []
: all.filter((bill) => bill.status === '待支付')
}
/**
* 支付结果(收银台「我已完成支付」→ 结果页)。
*
* <p>口径同 {@link getCheckoutBills}:按**需求 id + 期次 id** 从 `billPlans` 里取出该期,
* 支付单状态为 `SUCCESS` 才算已支付——计划本身的 status 可能还没被回调推到 DONE。</p>
*/
export async function getPlanPayResult(requirementId: string, planId: string): Promise<PaymentResult | null> {
const bills = await getCheckoutBills(requirementId, [planId])
const bill = bills[0]
@@ -420,17 +352,6 @@ export async function getPlanPayResult(requirementId: string, planId: string): P
}
}
/**
* 微信 Native 下单(PC 网站扫码):`POST /pay/web/wechat/native`,`@SaIgnore`。
*
* @param orderNo 商户订单号(前端生成,见 `utils/payMeta.ts#createMerchantOrderNo`)
* @param amount 支付金额,单位 **元**(后端内部 `×100` 转「分」提交微信)
* @param billIds 本笔支付覆盖的账单 id(合并支付传多张)。
* 后端落 `vm_finance_payment`(status=CREATED)时把它序列化进
* `request_payload`,支付成功回调据此为**每张账单**落一行
* `vm_finance_payment_bill`,缺了它回调分摊落库会跳过。
* @returns `codeUrl`(形如 `weixin://wxpay/bizpayurl?pr=xxx`),前端渲染成二维码供扫
*/
export function createWechatNativeOrder(
orderNo: string,
amount: number,
@@ -443,16 +364,6 @@ export function createWechatNativeOrder(
})
}
/**
* 支付宝电脑网站支付下单:`POST /pay/web/alipay/page`,`@SaIgnore`。
*
* <p>入参对应后端 `IFinancePaymentBo`。其 `outTradeNo` / `status` 上的 `@NotBlank`
* 只声明在 AddGroup / EditGroup 分组上,而控制器用的是默认分组 ⇒ 只传
* `outTradeNo` + `amount` 即可(`payChannel` / `status` 由后端自己补),不会校验失败。</p>
*
* @returns `formBody` —— 后端走 `pageExecute(request, "GET")`,实测内容是
* **支付宝收银台跳转地址**(`https://…/gateway.do?…`)而不是 HTML 表单;前端两种形态都兜住。
*/
export function createAlipayPageOrder(
outTradeNo: string,
amount: number,