bx.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /**
  2. * 报销模块 API(REST,协议 code===0 / msg / data.rows)
  3. * 路径挂在 /api 下:/reimburses、/advances、/expense-items、/attachments
  4. */
  5. import { request, parseResponseJson } from '@/utils/request'
  6. function unwrap(res) {
  7. const body = parseResponseJson(res)
  8. if (!body || typeof body !== 'object') {
  9. throw new Error('接口响应异常')
  10. }
  11. if (body.code != null && body.code !== 0) {
  12. throw new Error(body.msg || body.message || '请求失败')
  13. }
  14. return body.data != null ? body.data : body
  15. }
  16. async function get(url, params = {}) {
  17. const res = await request({ url, method: 'GET', data: params, params })
  18. return unwrap(res)
  19. }
  20. async function post(url, data = {}) {
  21. const res = await request({ url, method: 'POST', data })
  22. return unwrap(res)
  23. }
  24. async function put(url, data = {}, params = {}) {
  25. const res = await request({ url, method: 'PUT', data, params })
  26. return unwrap(res)
  27. }
  28. function pageParams(query = {}) {
  29. const { pageNum, page, pageSize, ...rest } = query
  30. const params = {
  31. page: pageNum ?? page ?? 1,
  32. pageSize: pageSize ?? 20
  33. }
  34. Object.keys(rest).forEach((k) => {
  35. if (rest[k] != null && rest[k] !== '') params[k] = rest[k]
  36. })
  37. return params
  38. }
  39. function normalizeList(data) {
  40. if (Array.isArray(data)) return { rows: data, total: data.length }
  41. const d = data || {}
  42. return {
  43. rows: d.rows || d.list || [],
  44. total: d.total ?? 0
  45. }
  46. }
  47. // ── 费用项目 ──
  48. export async function getExpenseItemTree() {
  49. const data = await get('/expense-items/tree')
  50. return Array.isArray(data) ? data : []
  51. }
  52. /** 展平可选叶子费用项目(供 picker) */
  53. export function flattenExpenseLeaves(tree, path = []) {
  54. const out = []
  55. ;(tree || []).forEach((node) => {
  56. const name = node.itemName || node.item_name || ''
  57. const nextPath = path.concat(name)
  58. const children = node.children || []
  59. if (children.length) {
  60. out.push(...flattenExpenseLeaves(children, nextPath))
  61. } else {
  62. out.push({
  63. id: String(node.id),
  64. name,
  65. pathLabel: nextPath.join(' / ')
  66. })
  67. }
  68. })
  69. return out
  70. }
  71. // ── 报销 ──
  72. export async function listMyReimburse(query = {}) {
  73. return normalizeList(await get('/reimburses/my', pageParams(query)))
  74. }
  75. export async function listPendingReimburse(query = {}) {
  76. return normalizeList(await get('/reimburses/pending-approval', pageParams(query)))
  77. }
  78. export async function listApprovedByMeReimburse(query = {}) {
  79. return normalizeList(await get('/reimburses/approved-by-me', pageParams(query)))
  80. }
  81. export async function getReimburse(id) {
  82. return get(`/reimburses/${String(id)}`)
  83. }
  84. export async function generateReimburseTitle(reimburseDate) {
  85. const params = {}
  86. if (reimburseDate) params.reimburseDate = reimburseDate
  87. return get('/reimburses/generate-title', params)
  88. }
  89. export function createReimburse(data) {
  90. return post('/reimburses/', data)
  91. }
  92. export function updateReimburse(id, data) {
  93. return put(`/reimburses/${String(id)}`, data)
  94. }
  95. export function submitReimburse(id) {
  96. return post(`/reimburses/${String(id)}/submit`)
  97. }
  98. export function approveReimburse(id, approvalOpinion = '') {
  99. return post(`/reimburses/${String(id)}/approve`, { approvalOpinion })
  100. }
  101. export function rejectReimburse(id, approvalOpinion = '') {
  102. return post(`/reimburses/${String(id)}/reject`, { approvalOpinion })
  103. }
  104. export async function getReimburseApprovalHistory(id) {
  105. const data = await get(`/reimburses/${String(id)}/approval-history`)
  106. return Array.isArray(data) ? data : []
  107. }
  108. // ── 借款(备用金) ──
  109. export async function listMyAdvance(query = {}) {
  110. return normalizeList(await get('/advances/my', pageParams(query)))
  111. }
  112. export async function listPendingAdvance(query = {}) {
  113. return normalizeList(await get('/advances/pending-approval', pageParams(query)))
  114. }
  115. export async function listApprovedByMeAdvance(query = {}) {
  116. return normalizeList(await get('/advances/approved-by-me', pageParams(query)))
  117. }
  118. export async function getAdvance(id) {
  119. return get(`/advances/${String(id)}`)
  120. }
  121. export function createAdvance(data) {
  122. return post('/advances/', data)
  123. }
  124. export function submitAdvance(id) {
  125. return post(`/advances/${String(id)}/submit`)
  126. }
  127. export function approveAdvance(id, approvalOpinion = '') {
  128. return post(`/advances/${String(id)}/approve`, { approvalOpinion })
  129. }
  130. export function rejectAdvance(id, approvalOpinion = '') {
  131. return post(`/advances/${String(id)}/reject`, { approvalOpinion })
  132. }
  133. export async function getAdvanceApprovalHistory(id) {
  134. const data = await get(`/advances/${String(id)}/approval-history`)
  135. return Array.isArray(data) ? data : []
  136. }
  137. // ── 附件 ──
  138. export async function listAttachments(bizType, bizId) {
  139. const data = await get('/attachments/list', {
  140. biz_type: bizType,
  141. biz_id: String(bizId)
  142. })
  143. return Array.isArray(data) ? data : []
  144. }
  145. export async function bindAttachments(ids, bizType, bizId) {
  146. if (!ids?.length) return 0
  147. const q = [
  148. `ids=${encodeURIComponent(ids.map(String).join(','))}`,
  149. `biz_type=${encodeURIComponent(bizType)}`,
  150. `biz_id=${encodeURIComponent(String(bizId))}`
  151. ].join('&')
  152. return put(`/attachments/bind-biz?${q}`, {})
  153. }
  154. export async function previewAttachment(id) {
  155. return get(`/attachments/preview/${String(id)}`)
  156. }