har.ts 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import request from "@/utils/request";
  2. const API_PATH = "/payment/har";
  3. /**
  4. * 分页结果 — 后端 PageResult 全局 SNAKE_CASE 序列化后 JSON key 为 `list`
  5. * (全局 PageResult<T> 声明的是 items,与后端契约不符;保留 items 兼容字段,
  6. * 调用方按 `?.items || ?.list || []` 双保险解包,与 batch.ts 一致)
  7. */
  8. export interface HarPageResult<T> {
  9. items?: T;
  10. list: T;
  11. total: number;
  12. page_no: number;
  13. page_size: number;
  14. }
  15. /** 商户配置(后端 HarMerchantVO)— merchant_code 由运营在上游报备进件后手工录入 */
  16. export interface HarMerchantVO {
  17. id?: string;
  18. /** 归属租户。超管建号时选定,之后不可改(列表侧供超管分辨各行属于谁) */
  19. tenant_id?: number;
  20. /** 选填。为空 ⇒ 租户级映射(同一租户下不再区分企业) */
  21. enterprise_id?: string;
  22. /** 上游分配的商户编号,全局唯一 */
  23. merchant_code: string;
  24. merchant_name?: string;
  25. contact_name?: string;
  26. contact_mobile?: string;
  27. description?: string;
  28. created_time?: string;
  29. updated_time?: string;
  30. }
  31. /**
  32. * 商户配置保存入参(HarMerchantSaveDTO)— id 为空即新增。
  33. *
  34. * ★ 该端点**只有超管**能调(后端 `@perm.hasRole('SUPERUSER')`),所以调用方必然在
  35. * 超管上下文里:`tenant_id` 新增时必填(替哪个租户建号),修改时后端忽略它。
  36. */
  37. export interface HarMerchantSaveParams {
  38. id?: string;
  39. /** 新增必填;修改时忽略(归属不可改) */
  40. tenant_id?: number;
  41. enterprise_id?: string;
  42. merchant_code: string;
  43. merchant_name?: string;
  44. contact_name?: string;
  45. contact_mobile?: string;
  46. description?: string;
  47. }
  48. /** 门店(后端 HarShopVO) */
  49. export interface HarShopVO {
  50. id?: string;
  51. enterprise_id: string;
  52. merchant_code?: string;
  53. /** 商户自己的门店编码,幂等键 */
  54. third_shop_id: string;
  55. shop_name?: string;
  56. /** 上游返回的平台门店编号,创建成功才有值 */
  57. shop_id?: string;
  58. /** PENDING=结果未知待人工核实 / SUCCESS=上游已确认 / FAILED=上游明确拒绝 */
  59. create_status: string;
  60. fail_reason?: string;
  61. retry_count?: number;
  62. description?: string;
  63. created_time?: string;
  64. updated_time?: string;
  65. }
  66. /** 门店创建入参(HarShopCreateDTO)— 上游无门店查询接口,本地落库是唯一的可查来源 */
  67. export interface HarShopCreateParams {
  68. third_shop_id: string;
  69. shop_name: string;
  70. /** 选填。为空 ⇒ 走**租户级**商户映射(enterprise_id IS NULL 的那一行) */
  71. enterprise_id?: string;
  72. /**
  73. * 用哪一条商户配置。一个租户可以配置**多个**商户(2026-09-24),此时必须指定:
  74. * 不指定而本租户有多条 ⇒ 后端 400「请在请求中指定 merchant_code」,
  75. * 不会替调用方挑一条(挑错了门店挂到别的商户名下,且没有任何报错)。
  76. * 取值必须是本租户的商户编号,跨租户的会被 404 挡掉。
  77. */
  78. merchant_code?: string;
  79. }
  80. /** 订单(后端 HarOrderVO)— 状态直接采用上游枚举,不做本地转义 */
  81. export interface HarOrderVO {
  82. id?: string;
  83. enterprise_id: string;
  84. /** 我方订单号(雪花ID),即上游的 third_order_no */
  85. order_no: string;
  86. /** 企业商户自己的订单号 */
  87. out_biz_no?: string;
  88. upstream_order_no?: string;
  89. platform_trade_no?: string;
  90. merchant_code?: string;
  91. shop_code?: string;
  92. third_shop_code?: string;
  93. price: string;
  94. title?: string;
  95. /** alipay_stage=花呗分期 / alipay_payment=支付宝支付 */
  96. trade_type?: string;
  97. stage_num?: string;
  98. /** 100=商户承担 / 0=用户承担 */
  99. percent?: string;
  100. pay_timeout?: number;
  101. extra_params?: string;
  102. /** 主扫下单返回的收款链接;被扫(auth_code)下单时为空 */
  103. pay_url?: string;
  104. /** 0=等待支付 / 1=支付成功 / 2=退款成功 / 4=退款中 / 8=交易关闭 */
  105. trade_status: string;
  106. trade_time?: string;
  107. refund_time?: string;
  108. upstream_create_time?: string;
  109. rcv_amount?: string;
  110. fee_amount?: string;
  111. channel_amount?: string;
  112. /** PENDING=未回调 / SUCCESS / FAILED */
  113. notify_status?: string;
  114. created_time?: string;
  115. updated_time?: string;
  116. }
  117. /** 下单入参(HarOrderCreateDTO)— auth_code 有值走被扫收款,为空走主扫下单 */
  118. export interface HarOrderCreateParams {
  119. /** 选填。为空 ⇒ 走**租户级**商户映射(enterprise_id IS NULL 的那一行) */
  120. enterprise_id?: string;
  121. /**
  122. * 用哪一条商户配置 —— 一个租户可以配置**多个**商户(2026-09-24)。
  123. * 不指定而本租户有多条 ⇒ 后端 400,不替调用方挑一条:
  124. * 挑错了钱会进另一个商户账号,且全程没有报错,对账时才发现。
  125. */
  126. merchant_code?: string;
  127. out_biz_no?: string;
  128. price: number | string;
  129. title: string;
  130. trade_type: string;
  131. /** 分期时必填,3/6/12/24 */
  132. stage_num?: string;
  133. /** 分期时必填 */
  134. percent?: string;
  135. third_shop_code?: string;
  136. shop_code?: string;
  137. pay_timeout?: number;
  138. extra_params?: string;
  139. auth_code?: string;
  140. }
  141. /** 订单列表查询条件 — 起止日期为 yyyy-MM-dd */
  142. export interface HarOrderQueryParams {
  143. enterprise_id?: string;
  144. merchant_code?: string;
  145. order_no?: string;
  146. out_biz_no?: string;
  147. trade_status?: string;
  148. trade_type?: string;
  149. start_date?: string;
  150. end_date?: string;
  151. page_no?: number;
  152. page_size?: number;
  153. }
  154. export const HAR_TRADE_TYPE_OPTIONS = [
  155. { label: "支付宝支付", value: "alipay_payment" },
  156. { label: "花呗分期", value: "alipay_stage" },
  157. ];
  158. /** 上游订单状态枚举,与后端 HarOrderStatus 逐字一致 */
  159. export const HAR_TRADE_STATUS_TEXT: Record<string, string> = {
  160. "0": "等待支付",
  161. "1": "支付成功",
  162. "2": "退款成功",
  163. "4": "退款中",
  164. "8": "交易关闭",
  165. };
  166. export type ElTagType = "primary" | "success" | "warning" | "info" | "danger";
  167. export const HAR_TRADE_STATUS_TAG: Record<string, ElTagType> = {
  168. "0": "warning",
  169. "1": "success",
  170. "2": "info",
  171. "4": "warning",
  172. "8": "info",
  173. };
  174. export const HAR_SHOP_STATUS_TEXT: Record<string, string> = {
  175. PENDING: "待核实",
  176. SUCCESS: "创建成功",
  177. FAILED: "创建失败",
  178. };
  179. export const HAR_SHOP_STATUS_TAG: Record<string, ElTagType> = {
  180. PENDING: "warning",
  181. SUCCESS: "success",
  182. FAILED: "danger",
  183. };
  184. export const HAR_NOTIFY_STATUS_TEXT: Record<string, string> = {
  185. PENDING: "未回调",
  186. SUCCESS: "回调成功",
  187. FAILED: "回调失败",
  188. };
  189. const HarAPI = {
  190. // ---------- 商户配置 ----------
  191. /** 商户配置列表(分页) */
  192. merchantList(params: {
  193. /** 租户筛选 —— 只有超管看得见所有租户的行(后端对超管跳过租户过滤) */
  194. tenant_id?: number;
  195. enterprise_id?: string;
  196. merchant_code?: string;
  197. merchant_name?: string;
  198. page_no?: number;
  199. page_size?: number;
  200. }) {
  201. return request<ApiResponse<HarPageResult<HarMerchantVO[]>>>({
  202. url: `${API_PATH}/merchant`,
  203. method: "get",
  204. params,
  205. });
  206. },
  207. /** 新增或修改商户配置(id 有值为修改) */
  208. merchantSave(data: HarMerchantSaveParams) {
  209. return request<ApiResponse<HarMerchantVO>>({
  210. url: `${API_PATH}/merchant`,
  211. method: "post",
  212. data,
  213. });
  214. },
  215. /** 删除商户配置 */
  216. merchantDelete(id: string) {
  217. return request<ApiResponse<void>>({
  218. url: `${API_PATH}/merchant/${id}`,
  219. method: "delete",
  220. });
  221. },
  222. // ---------- 门店 ----------
  223. /** 门店列表(分页) */
  224. shopList(params: {
  225. enterprise_id?: string;
  226. merchant_code?: string;
  227. third_shop_id?: string;
  228. create_status?: string;
  229. page_no?: number;
  230. page_size?: number;
  231. }) {
  232. return request<ApiResponse<HarPageResult<HarShopVO[]>>>({
  233. url: `${API_PATH}/shop`,
  234. method: "get",
  235. params,
  236. });
  237. },
  238. /** 门店详情 */
  239. shopDetail(id: string) {
  240. return request<ApiResponse<HarShopVO>>({
  241. url: `${API_PATH}/shop/${id}`,
  242. method: "get",
  243. });
  244. },
  245. /**
  246. * 创建门店(同步调用上游)。
  247. * 上游没有门店查询接口,超时后无法核实远端是否已创建 —— 此时本地落 PENDING,
  248. * 页面按「待核实」展示并引导人工与上游核对,不可盲目重试(third_shop_id 是幂等键)
  249. */
  250. shopCreate(data: HarShopCreateParams) {
  251. return request<ApiResponse<HarShopVO>>({
  252. url: `${API_PATH}/shop`,
  253. method: "post",
  254. data,
  255. });
  256. },
  257. // ---------- 订单 ----------
  258. /** 订单列表(分页) */
  259. orderList(params: HarOrderQueryParams) {
  260. return request<ApiResponse<HarPageResult<HarOrderVO[]>>>({
  261. url: `${API_PATH}/order`,
  262. method: "get",
  263. params,
  264. });
  265. },
  266. /** 订单详情 */
  267. orderDetail(id: string) {
  268. return request<ApiResponse<HarOrderVO>>({
  269. url: `${API_PATH}/order/${id}`,
  270. method: "get",
  271. });
  272. },
  273. /**
  274. * 后台下单(调用上游)。
  275. * 上游异步通知未回 success 时每 5s 重试、最多 5 次(约 25s 窗口),
  276. * 因此支付结果以主动查询为准,通知只是加速收敛
  277. */
  278. orderCreate(data: HarOrderCreateParams) {
  279. return request<ApiResponse<HarOrderVO>>({
  280. url: `${API_PATH}/order`,
  281. method: "post",
  282. data,
  283. });
  284. },
  285. /** 主动查询上游并回写状态 */
  286. orderSync(id: string) {
  287. return request<ApiResponse<HarOrderVO>>({
  288. url: `${API_PATH}/order/${id}/sync`,
  289. method: "post",
  290. });
  291. },
  292. };
  293. export default HarAPI;