| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- /**
- * finance.ts —— 费用管理接口封装(academic 域;对应旧 PHP 财务可操作面)。
- *
- * 覆盖旧系统用户可操作方法(对齐 modules/user + courses/RequestController):
- * 账户快照/可退额、充值、消费、退费、自定义退费(§3.1)、转结、坏账、余额清零(§3.2)、
- * spend 扣减、资金工单(建/审/驳/撤)、流水查询、仪表盘。
- *
- * 典型使用(views/academic/fee/index.vue):
- * - 流水列表:useListPage<ExpenseLogDTO> fetcher=listLogs({...scope.toQuery(), userId, page, pageSize})
- * - 各操作:直接调对应方法,后端恒 200 + body code;业务错误由调用方判 code
- *
- * 契约对齐(academic-frontend-contract-v1 v1.9;v1.6 B1/C1 已回改):
- * - 金额恒字符串两位小数(元);时间 RFC3339;分页 PageData 五字段;
- * - 写操作带 requestId 走幂等(重复提交 → repeated=true 回放首次)。
- */
- import { http } from '@/api/http';
- import type { PageR, R } from '@/types/api';
- /* ================= 读 ================= */
- /** 资金流水 DTO(端点 11 列表行;v1.5:流水表无作用域列,不含 institutionId/campusId) */
- export interface ExpenseLogDTO {
- /** 流水 id(int64 主键) */
- id: number;
- /** 用户 id(canonical_user_id ULID 字符串) */
- userId: string;
- /** 流水类型编码(100 充值 + / 101,201 消费 − / 207 退费 − / 208 清零 − / 106,206 转结 / 108 坏账 +) */
- type: number;
- /** 金额(字符串两位小数) */
- money: string;
- /** 变动后余额(字符串两位小数,全局账户快照) */
- balanceAfter: string;
- /** 业务时间(RFC3339;v1.6 C1:← legacy create_time) */
- createTime: string;
- /** 备注 */
- remark: string;
- }
- /** 流水查询参数(作用域由 useScope().toQuery() 注入;userId 定位账户) */
- export type LogQuery = {
- institutionId: number;
- campusId?: number;
- userId?: string;
- type?: number;
- from?: string;
- to?: string;
- page?: number;
- pageSize?: number;
- };
- /** 资金流水分页列表(端点 11,GET /api/admin/finance/logs)。 */
- export function listLogs(params: LogQuery): Promise<PageR<ExpenseLogDTO>> {
- return http.get<PageR<ExpenseLogDTO>>('/api/admin/finance/logs', { params }).then((r) => r.data);
- }
- /** 账户快照 DTO(端点 1;扁平结构) */
- export interface AccountDTO {
- userId: string;
- institutionId: number;
- campusId: number;
- totalBalance: string;
- campusBalance: string;
- specialExpenses: string;
- cumulativeIncome: string;
- }
- /** 账户快照(端点 1,GET /api/admin/finance/accounts/:userId)。 */
- export function fetchAccount(userId: string, params: { institutionId: number; campusId?: number }): Promise<R<AccountDTO>> {
- return http.get<R<AccountDTO>>(`/api/admin/finance/accounts/${userId}`, { params }).then((r) => r.data);
- }
- /** 可退额(端点 2,GET /api/admin/finance/accounts/:userId/refundable)。 */
- export function fetchRefundable(
- userId: string,
- params: { institutionId: number; campusId?: number },
- ): Promise<R<{ refundableAmount: string }>> {
- return http
- .get<R<{ refundableAmount: string }>>(`/api/admin/finance/accounts/${userId}/refundable`, { params })
- .then((r) => r.data);
- }
- /** 仪表盘 DTO(端点 21;账户维度 + 校区余额分布) */
- export interface DashboardDTO {
- balance: string;
- totalIncome: string;
- totalExpenditure: string;
- specialExpenses: string;
- netReceivable: string;
- balanceDistribution: { campusId: number; balance: string }[];
- }
- /** 仪表盘(端点 21,GET /api/admin/finance/dashboard)。 */
- export function fetchDashboard(params: { institutionId: number; campusId?: number; userId?: string }): Promise<R<DashboardDTO>> {
- return http.get<R<DashboardDTO>>('/api/admin/finance/dashboard', { params }).then((r) => r.data);
- }
- /* ================= 写(用户可操作;对齐旧 PHP 财务方法) ================= */
- /** 资金工单 DTO(端点 12) */
- export interface BalanceRequestDTO {
- id: number;
- bizNo: string;
- type: number;
- userId: string;
- institutionId: number;
- campusId: number;
- money: string;
- approved: number; // 0 待审 / 1 通过 / -1 驳回 / -2 撤销
- applicantId: string;
- approverId: string;
- remark: string;
- /** 申请时间(RFC3339;v1.6 B2:requestTime ← request_time) */
- requestTime: string;
- /** 审批时间(RFC3339;未审批时 null) */
- responseTime: string | null;
- }
- /** 工单列表(端点 12,GET /api/admin/finance/requests)。 */
- export function listRequests(params: {
- institutionId: number;
- campusId?: number;
- type?: number;
- approved?: number;
- userId?: string;
- page?: number;
- pageSize?: number;
- }): Promise<PageR<BalanceRequestDTO>> {
- return http.get<PageR<BalanceRequestDTO>>('/api/admin/finance/requests', { params }).then((r) => r.data);
- }
- /** 充值(端点 3,POST /api/admin/finance/recharges)。入参:userId+campusId+money+requestId。 */
- export function recharge(body: {
- userId: string;
- campusId: number;
- money: string;
- requestId: string;
- institutionId: number;
- }): Promise<R<{ logId: number; balance: string; repeated: boolean }>> {
- return http.post<R<{ logId: number; balance: string; repeated: boolean }>>('/api/admin/finance/recharges', body).then((r) => r.data);
- }
- /** 消费(端点 4,POST /api/admin/finance/expenditures)。 */
- export function expenditure(body: {
- userId: string;
- campusId: number;
- type?: number;
- money: string;
- institutionId: number;
- }): Promise<R<{ logId: number; balance: string }>> {
- return http.post<R<{ logId: number; balance: string }>>('/api/admin/finance/expenditures', body).then((r) => r.data);
- }
- /** 退费(端点 5,POST /api/admin/finance/refunds)。余额≤0 → 3102。 */
- export function refund(body: {
- userId: string;
- campusId: number;
- money: string;
- institutionId: number;
- }): Promise<R<{ logId: number; balance: string; changed: boolean }>> {
- return http.post<R<{ logId: number; balance: string; changed: boolean }>>('/api/admin/finance/refunds', body).then((r) => r.data);
- }
- /** 自定义退费结果(端点 6 §3.1;可退不足 → 3103 warn + badDebt;校区不存在 → 3104) */
- export interface CustomRefundResult {
- requested: string;
- refunded: string;
- badDebt: string;
- refundableAmount: string;
- balance: string;
- totalBalance: string;
- totalIncome: string;
- specialExpenses: string;
- logId207: number;
- logId108: number | null;
- expiredActivityIds: number[];
- warnings: { code: number; message: string }[];
- repeated: boolean;
- }
- /** 自定义退费(端点 6,POST /api/admin/finance/refunds/custom)。 */
- export function customRefund(body: {
- userId: string;
- campusId: number;
- money: string;
- requestId: string;
- institutionId: number;
- }): Promise<R<CustomRefundResult>> {
- return http.post<R<CustomRefundResult>>('/api/admin/finance/refunds/custom', body).then((r) => r.data);
- }
- /** 转结(端点 7,POST /api/admin/finance/transfers;校区间转账)。 */
- export function transfer(body: {
- userId: string;
- fromCampusId: number;
- toCampusId: number;
- money: string;
- institutionId: number;
- }): Promise<R<{ logId106: number; logId206: number }>> {
- return http.post<R<{ logId106: number; logId206: number }>>('/api/admin/finance/transfers', body).then((r) => r.data);
- }
- /** 坏账(端点 8,POST /api/admin/finance/bad-debts)。 */
- export function badDebt(body: {
- userId: string;
- campusId: number;
- money: string;
- requestId: string;
- institutionId: number;
- }): Promise<R<{ logId: number; specialExpenses: string; repeated: boolean }>> {
- return http.post<R<{ logId: number; specialExpenses: string; repeated: boolean }>>('/api/admin/finance/bad-debts', body).then((r) => r.data);
- }
- /** 余额清零结果(端点 9 §3.2;前置不满足 → 3120) */
- export interface ClearBalanceResult {
- cleared: string;
- campusBalanceBefore: string;
- totalBalanceBefore: string;
- balance: string;
- totalBalance: string;
- specialExpenses: string;
- logId208: number;
- expiredActivityIds: number[];
- repeated: boolean;
- }
- /** 余额清零(端点 9,POST /api/admin/finance/cleared-balances)。 */
- export function clearBalance(body: { userId: string; campusId: number; institutionId: number }): Promise<R<ClearBalanceResult>> {
- return http.post<R<ClearBalanceResult>>('/api/admin/finance/cleared-balances', body).then((r) => r.data);
- }
- /** spend 扣减(端点 10,POST /api/admin/finance/spends;课时扣费;v1.6 B1:旧库只 UPDATE spend 列不写流水 → 仅回 `{spend}`,无 logId)。 */
- export function spend(body: { userId: string; campusId: number; spendMoney: string; institutionId: number }): Promise<R<{ spend: string }>> {
- return http.post<R<{ spend: string }>>('/api/admin/finance/spends', body).then((r) => r.data);
- }
- /** 建工单(端点 13,POST /api/admin/finance/requests)。 */
- export function createRequest(body: {
- type: number;
- userId: string;
- campusId: number;
- money: string;
- remark?: string;
- institutionId: number;
- }): Promise<R<{ id: number; bizNo: string }>> {
- return http.post<R<{ id: number; bizNo: string }>>('/api/admin/finance/requests', body).then((r) => r.data);
- }
- /** 审批通过(端点 14,POST /api/admin/finance/requests/:id/approve)。已处理 → 3140。 */
- export function approveRequest(id: number, params: { institutionId: number; campusId?: number }): Promise<R<{ approved: number; result: { logId: number; balance: string } }>> {
- return http.post<R<{ approved: number; result: { logId: number; balance: string } }>>(`/api/admin/finance/requests/${id}/approve`, {}, { params }).then((r) => r.data);
- }
- /** 驳回(端点 15,POST /api/admin/finance/requests/:id/reject)。 */
- export function rejectRequest(id: number, params: { institutionId: number; campusId?: number }): Promise<R<{ approved: number }>> {
- return http.post<R<{ approved: number }>>(`/api/admin/finance/requests/${id}/reject`, {}, { params }).then((r) => r.data);
- }
- /** 撤销(端点 16,POST /api/admin/finance/requests/:id/cancel;仅待审)。 */
- export function cancelRequest(id: number, params: { institutionId: number; campusId?: number }): Promise<R<{ approved: number }>> {
- return http.post<R<{ approved: number }>>(`/api/admin/finance/requests/${id}/cancel`, {}, { params }).then((r) => r.data);
- }
- /* ================= 收支记录 / 收支字典(端点 60;v1.9 三条修正) ================= */
- /** 收支记录 DTO(端点 60 列表行;记录表无 type/name/direction 列——type/name 由后端 JOIN 字典下发)。 */
- export interface ExpenditureRecordDTO {
- /** 记录 id */
- id: number;
- /** 收支字典 id(← expenditure_id;编辑表单回填用) */
- expenditureId: number;
- /** 收支方向编码:1 = 支出 / 2 = 收入(用 type 判方向,两表无 direction 列) */
- type: number;
- /** 收支类型名(JOIN 字典 t_expenditure.name) */
- name: string;
- /** 金额(字符串两位小数) */
- money: string;
- /** 记账人(← create_user_id;语义 = 记账人,非"收付对象";可空) */
- createUserId: string | null;
- campusId: number;
- /** 业务单号 */
- bizNo: string;
- /** 业务时间(RFC3339) */
- createTime: string;
- }
- /** 收支记录查询参数(作用域由 useScope().toQuery() 注入;type 1 支出 / 2 收入) */
- export type ExpenditureQuery = {
- institutionId: number;
- campusId?: number;
- type?: number;
- page?: number;
- pageSize?: number;
- };
- /** 收支记录分页列表(端点 60,GET /api/admin/expenditures)。 */
- export function listExpenditures(params: ExpenditureQuery): Promise<PageR<ExpenditureRecordDTO>> {
- return http.get<PageR<ExpenditureRecordDTO>>('/api/admin/expenditures', { params }).then((r) => r.data);
- }
- /** 收支类型字典项(端点 60 GET /types 行) */
- export interface ExpenditureTypeDTO {
- /** 字典 id(记录 expenditureId 指向它) */
- id: number;
- /** 收支方向编码:1 = 支出 / 2 = 收入 */
- type: number;
- name: string;
- /** 父级字典 id(0 = 顶级) */
- parentId: number;
- }
- /** 收支类型字典(端点 60,GET /api/admin/expenditures/types)。
- * ⚠ POST /types(新增收支类型)本轮不做——需要时提需求。 */
- export function fetchExpenditureTypes(params: { institutionId: number; campusId?: number }): Promise<R<{ types: ExpenditureTypeDTO[] }>> {
- return http.get<R<{ types: ExpenditureTypeDTO[] }>>('/api/admin/expenditures/types', { params }).then((r) => r.data);
- }
- /** 新增收支记录(端点 60,POST /api/admin/expenditures)→ {id, bizNo}。
- * expenditureId 指向字典(type/name 由后端 JOIN 字典得出,前端不传);createUserId 可空。 */
- export function createExpenditure(body: {
- expenditureId: number;
- money: string;
- campusId: number;
- createUserId?: string | null;
- institutionId: number;
- }): Promise<R<{ id: number; bizNo: string }>> {
- return http.post<R<{ id: number; bizNo: string }>>('/api/admin/expenditures', body).then((r) => r.data);
- }
|