har.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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_un_stage=支付宝支付(260924 前叫 alipay_payment) */
  96. trade_type?: string;
  97. /** 业务类型。非分期传 har_ali_un_stage(规范 260924 订单创建参数表 biz 行) */
  98. biz?: string;
  99. stage_num?: string;
  100. /** 100=商户承担 / 0=用户承担 */
  101. percent?: string;
  102. pay_timeout?: number;
  103. extra_params?: string;
  104. /** 主扫下单返回的收款链接;被扫(auth_code)下单时为空 */
  105. pay_url?: string;
  106. /** 0=等待支付 / 1=支付成功 / 2=退款成功 / 4=退款中 / 8=交易关闭 */
  107. trade_status: string;
  108. trade_time?: string;
  109. refund_time?: string;
  110. /** 退款原因:我方发给上游的那一句。上游不回传,非退款单为 null */
  111. refund_reason?: string;
  112. upstream_create_time?: string;
  113. rcv_amount?: string;
  114. fee_amount?: string;
  115. channel_amount?: string;
  116. /** PENDING=未回调 / SUCCESS / FAILED */
  117. notify_status?: string;
  118. created_time?: string;
  119. updated_time?: string;
  120. }
  121. /** 下单入参(HarOrderCreateDTO)— auth_code 有值走被扫收款,为空走主扫下单 */
  122. export interface HarOrderCreateParams {
  123. /** 选填。为空 ⇒ 走**租户级**商户映射(enterprise_id IS NULL 的那一行) */
  124. enterprise_id?: string;
  125. /**
  126. * 用哪一条商户配置 —— 一个租户可以配置**多个**商户(2026-09-24)。
  127. * 不指定而本租户有多条 ⇒ 后端 400,不替调用方挑一条:
  128. * 挑错了钱会进另一个商户账号,且全程没有报错,对账时才发现。
  129. */
  130. merchant_code?: string;
  131. out_biz_no?: string;
  132. price: number | string;
  133. title: string;
  134. trade_type: string;
  135. /**
  136. * 业务类型。选填。规范 260924 订单创建参数表 biz 行:非分期传 `har_ali_un_stage`。
  137. *
  138. * 后端原样透传、不推导 —— 所以下单表单在非分期时自己带上这个值(见 order/index.vue)。
  139. */
  140. biz?: string;
  141. /** 分期时必填,3/6/12/24 */
  142. stage_num?: string;
  143. /** 分期时必填 */
  144. percent?: string;
  145. third_shop_code?: string;
  146. shop_code?: string;
  147. pay_timeout?: number;
  148. extra_params?: string;
  149. auth_code?: string;
  150. }
  151. /** 订单列表查询条件 — 起止日期为 yyyy-MM-dd */
  152. export interface HarOrderQueryParams {
  153. enterprise_id?: string;
  154. merchant_code?: string;
  155. order_no?: string;
  156. out_biz_no?: string;
  157. trade_status?: string;
  158. trade_type?: string;
  159. start_date?: string;
  160. end_date?: string;
  161. page_no?: number;
  162. page_size?: number;
  163. }
  164. /** 交易方式。非分期那个值 260924 起叫 alipay_un_stage(此前是 alipay_payment)。 */
  165. export const HAR_TRADE_TYPE_OPTIONS = [
  166. { label: "支付宝支付", value: "alipay_un_stage" },
  167. { label: "花呗分期", value: "alipay_stage" },
  168. ];
  169. /** 非分期的业务类型(上游 biz)。规范 260924 订单创建参数表 biz 行 只给了这一个取值。 */
  170. export const HAR_BIZ_UN_STAGE = "har_ali_un_stage";
  171. /**
  172. * 「1 支付成功」—— 本通道**唯一**允许发起退款的起点状态。
  173. *
  174. * 有名字才敢在模板里比:写死 "1" 的判据散在三处时,改枚举的人只会改到一处。
  175. * 上游语义:退款只能从已支付发起,4 退款中 / 2 退款成功 / 8 交易关闭 都会被拒。
  176. */
  177. export const HAR_ORDER_STATUS_PAID = "1";
  178. /** 上游订单状态枚举,与后端 HarOrderStatus 逐字一致 */
  179. export const HAR_TRADE_STATUS_TEXT: Record<string, string> = {
  180. "0": "等待支付",
  181. "1": "支付成功",
  182. "2": "退款成功",
  183. "4": "退款中",
  184. "8": "交易关闭",
  185. };
  186. export type ElTagType = "primary" | "success" | "warning" | "info" | "danger";
  187. export const HAR_TRADE_STATUS_TAG: Record<string, ElTagType> = {
  188. "0": "warning",
  189. "1": "success",
  190. "2": "info",
  191. "4": "warning",
  192. "8": "info",
  193. };
  194. export const HAR_SHOP_STATUS_TEXT: Record<string, string> = {
  195. PENDING: "待核实",
  196. SUCCESS: "创建成功",
  197. FAILED: "创建失败",
  198. };
  199. export const HAR_SHOP_STATUS_TAG: Record<string, ElTagType> = {
  200. PENDING: "warning",
  201. SUCCESS: "success",
  202. FAILED: "danger",
  203. };
  204. export const HAR_NOTIFY_STATUS_TEXT: Record<string, string> = {
  205. PENDING: "未回调",
  206. SUCCESS: "回调成功",
  207. FAILED: "回调失败",
  208. };
  209. const HarAPI = {
  210. // ---------- 商户配置 ----------
  211. /** 商户配置列表(分页) */
  212. merchantList(params: {
  213. /** 租户筛选 —— 只有超管看得见所有租户的行(后端对超管跳过租户过滤) */
  214. tenant_id?: number;
  215. enterprise_id?: string;
  216. merchant_code?: string;
  217. merchant_name?: string;
  218. page_no?: number;
  219. page_size?: number;
  220. }) {
  221. return request<ApiResponse<HarPageResult<HarMerchantVO[]>>>({
  222. url: `${API_PATH}/merchant`,
  223. method: "get",
  224. params,
  225. });
  226. },
  227. /** 新增或修改商户配置(id 有值为修改) */
  228. merchantSave(data: HarMerchantSaveParams) {
  229. return request<ApiResponse<HarMerchantVO>>({
  230. url: `${API_PATH}/merchant`,
  231. method: "post",
  232. data,
  233. });
  234. },
  235. /** 删除商户配置 */
  236. merchantDelete(id: string) {
  237. return request<ApiResponse<void>>({
  238. url: `${API_PATH}/merchant/${id}`,
  239. method: "delete",
  240. });
  241. },
  242. // ---------- 门店 ----------
  243. /** 门店列表(分页) */
  244. shopList(params: {
  245. enterprise_id?: string;
  246. merchant_code?: string;
  247. third_shop_id?: string;
  248. create_status?: string;
  249. page_no?: number;
  250. page_size?: number;
  251. }) {
  252. return request<ApiResponse<HarPageResult<HarShopVO[]>>>({
  253. url: `${API_PATH}/shop`,
  254. method: "get",
  255. params,
  256. });
  257. },
  258. /** 门店详情 */
  259. shopDetail(id: string) {
  260. return request<ApiResponse<HarShopVO>>({
  261. url: `${API_PATH}/shop/${id}`,
  262. method: "get",
  263. });
  264. },
  265. /**
  266. * 创建门店(同步调用上游)。
  267. * 上游没有门店查询接口,超时后无法核实远端是否已创建 —— 此时本地落 PENDING,
  268. * 页面按「待核实」展示并引导人工与上游核对,不可盲目重试(third_shop_id 是幂等键)
  269. */
  270. shopCreate(data: HarShopCreateParams) {
  271. return request<ApiResponse<HarShopVO>>({
  272. url: `${API_PATH}/shop`,
  273. method: "post",
  274. data,
  275. });
  276. },
  277. // ---------- 订单 ----------
  278. /** 订单列表(分页);silent = 后台静默刷新 */
  279. orderList(params: HarOrderQueryParams, silent = false) {
  280. return request<ApiResponse<HarPageResult<HarOrderVO[]>>>({
  281. url: `${API_PATH}/order`,
  282. method: "get",
  283. params,
  284. silent,
  285. });
  286. },
  287. /** 订单详情;silent = 后台静默刷新(详情弹窗实时联动用) */
  288. orderDetail(id: string, silent = false) {
  289. return request<ApiResponse<HarOrderVO>>({
  290. url: `${API_PATH}/order/${id}`,
  291. method: "get",
  292. silent,
  293. });
  294. },
  295. /**
  296. * 后台下单(调用上游)。
  297. * 上游异步通知未回 success 时每 5s 重试、最多 5 次(约 25s 窗口),
  298. * 因此支付结果以主动查询为准,通知只是加速收敛
  299. */
  300. orderCreate(data: HarOrderCreateParams) {
  301. return request<ApiResponse<HarOrderVO>>({
  302. url: `${API_PATH}/order`,
  303. method: "post",
  304. data,
  305. });
  306. },
  307. /** 主动查询上游并回写状态 */
  308. orderSync(id: string) {
  309. return request<ApiResponse<HarOrderVO>>({
  310. url: `${API_PATH}/order/${id}/sync`,
  311. method: "post",
  312. });
  313. },
  314. /**
  315. * 退款(全额,调用上游)。
  316. *
  317. * ★ **全额**:本通道上游没有金额字段,所以没有「退多少」这个选择,按钮上不要暗示能部分退。
  318. * ★ 返回的是**受理结果**(trade_status=4 退款中),**不是已退款到账** ——
  319. * 到账与否由通知/轮询把状态收敛成 2 退款成功,调用方必须按返回值如实提示。
  320. * ★ reason 留空由服务端补默认值:上游对空原因**整笔直接拒**,所以这里不能省成一个
  321. * 「服务端有默认值」的假设 —— 默认值兜的是调用方,界面仍应引导填一句真实原因。
  322. */
  323. orderRefund(id: string, reason?: string) {
  324. return request<ApiResponse<HarOrderVO>>({
  325. url: `${API_PATH}/order/${id}/refund`,
  326. method: "post",
  327. data: { reason },
  328. });
  329. },
  330. };
  331. export default HarAPI;