order.schema.ts 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. import { z } from '@hono/zod-openapi';
  2. // 订单状态枚举
  3. export const OrderStatus = {
  4. PENDING: 0, // 未发货
  5. SHIPPED: 1, // 已发货
  6. RECEIVED: 2, // 收货成功
  7. RETURNED: 3, // 已退货
  8. } as const;
  9. // 支付状态枚举
  10. export const PayStatus = {
  11. UNPAID: 0, // 未支付
  12. PAYING: 1, // 支付中
  13. SUCCESS: 2, // 支付成功
  14. REFUNDED: 3, // 已退款
  15. FAILED: 4, // 支付失败
  16. CLOSED: 5, // 订单关闭
  17. } as const;
  18. // 订单类型枚举
  19. export const OrderType = {
  20. PHYSICAL: 1, // 实物订单
  21. VIRTUAL: 2, // 虚拟订单
  22. } as const;
  23. // 支付类型枚举
  24. export const PayType = {
  25. POINTS: 1, // 积分
  26. COUPON: 2, // 礼券
  27. CREDIT: 3, // 额度支付
  28. WECHAT: 4, // 微信支付
  29. } as const;
  30. // 订单基础Schema
  31. export const OrderSchema = z.object({
  32. id: z.number().int().positive().openapi({
  33. description: '订单ID',
  34. example: 1
  35. }),
  36. orderNo: z.string().min(1, '订单号不能为空').max(50, '订单号最多50个字符').openapi({
  37. description: '订单号',
  38. example: 'ORD20240101123456'
  39. }),
  40. userId: z.number().int().positive().openapi({
  41. description: '用户ID',
  42. example: 1
  43. }),
  44. authCode: z.string().max(32, '付款码最多32个字符').nullable().optional().openapi({
  45. description: '付款码',
  46. example: '12345678901234567890123456789012'
  47. }),
  48. cardNo: z.string().max(32, '卡号最多32个字符').nullable().optional().openapi({
  49. description: '卡号',
  50. example: '6222********1234'
  51. }),
  52. sjtCardNo: z.string().max(32, '盛京通卡号最多32个字符').nullable().optional().openapi({
  53. description: '盛京通卡号',
  54. example: 'SJT1234567890'
  55. }),
  56. amount: z.coerce.number().min(0, '订单金额不能小于0').max(999999.99, '订单金额不能超过999999.99').openapi({
  57. description: '订单金额',
  58. example: 99.99
  59. }),
  60. costAmount: z.coerce.number().min(0, '成本金额不能小于0').max(999999.99, '成本金额不能超过999999.99').default(0).openapi({
  61. description: '成本金额',
  62. example: 50.00
  63. }),
  64. freightAmount: z.coerce.number().min(0, '运费不能小于0').max(999999.99, '运费不能超过999999.99').default(0).openapi({
  65. description: '运费',
  66. example: 10.00
  67. }),
  68. discountAmount: z.coerce.number().min(0, '优惠金额不能小于0').max(999999.99, '优惠金额不能超过999999.99').default(0).openapi({
  69. description: '优惠金额',
  70. example: 5.00
  71. }),
  72. payAmount: z.coerce.number().min(0, '实际支付金额不能小于0').max(999999.99, '实际支付金额不能超过999999.99').default(0).openapi({
  73. description: '实际支付金额',
  74. example: 94.99
  75. }),
  76. deviceNo: z.string().max(255, '设备编号最多255个字符').nullable().optional().openapi({
  77. description: '设备编号',
  78. example: 'DEV001234'
  79. }),
  80. description: z.string().max(255, '订单描述最多255个字符').nullable().optional().openapi({
  81. description: '订单描述',
  82. example: '购买商品'
  83. }),
  84. goodsDetail: z.string().max(2000, '订单详情最多2000个字符').nullable().optional().openapi({
  85. description: '订单详情(json格式)',
  86. example: '[{"goodsId":1,"name":"商品1","price":99.99,"num":1}]'
  87. }),
  88. goodsTag: z.string().max(255, '订单优惠标记最多255个字符').nullable().optional().openapi({
  89. description: '订单优惠标记',
  90. example: '满100减5'
  91. }),
  92. address: z.string().max(255, '地址最多255个字符').nullable().optional().openapi({
  93. description: '地址',
  94. example: '北京市朝阳区xxx路xxx号'
  95. }),
  96. orderType: z.coerce.number().int().min(1, '订单类型最小为1').max(2, '订单类型最大为2').default(1).openapi({
  97. description: '订单类型 1实物订单 2虚拟订单',
  98. example: 1
  99. }),
  100. payType: z.coerce.number().int().min(0, '支付类型最小为0').max(4, '支付类型最大为4').default(0).openapi({
  101. description: '支付类型1积分2礼券3额度支付4微信支付',
  102. example: 1
  103. }),
  104. payState: z.coerce.number().int().min(0, '支付状态最小为0').max(5, '支付状态最大为5').default(0).openapi({
  105. description: '支付状态 0未支付1支付中2支付成功3已退款4支付失败5订单关闭',
  106. example: 2
  107. }),
  108. state: z.coerce.number().int().min(0, '订单状态最小为0').max(3, '订单状态最大为3').default(0).openapi({
  109. description: '订单状态 0未发货1已发货2收货成功3已退货',
  110. example: 0
  111. }),
  112. userPhone: z.string().max(50, '用户手机号最多50个字符').nullable().optional().openapi({
  113. description: '用户手机号',
  114. example: '13800138000'
  115. }),
  116. merchantId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  117. description: '商户id',
  118. example: 1
  119. }),
  120. merchantNo: z.coerce.number().int().min(0, '不能小于0').nullable().optional().openapi({
  121. description: '商户号',
  122. example: 1001
  123. }),
  124. supplierId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  125. description: '供货商id',
  126. example: 1
  127. }),
  128. addressId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  129. description: '地址id',
  130. example: 1
  131. }),
  132. receiverMobile: z.string().max(255, '收货人手机号最多255个字符').nullable().optional().openapi({
  133. description: '收货人手机号',
  134. example: '13800138000'
  135. }),
  136. recevierName: z.string().max(255, '收货人姓名最多255个字符').nullable().optional().openapi({
  137. description: '收货人姓名',
  138. example: '张三'
  139. }),
  140. recevierProvince: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  141. description: '收货人所在省',
  142. example: 110000
  143. }),
  144. recevierCity: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  145. description: '收货人所在市',
  146. example: 110100
  147. }),
  148. recevierDistrict: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  149. description: '收货人所在区',
  150. example: 110105
  151. }),
  152. recevierTown: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  153. description: '收货人所在街道',
  154. example: 110105001
  155. }),
  156. refundTime: z.coerce.date().nullable().optional().openapi({
  157. description: '退款时间',
  158. example: '2024-01-01T12:00:00Z'
  159. }),
  160. closeTime: z.coerce.date().nullable().optional().openapi({
  161. description: '订单关闭时间',
  162. example: '2024-01-01T12:00:00Z'
  163. }),
  164. remark: z.string().max(255, '管理员备注信息最多255个字符').nullable().optional().openapi({
  165. description: '管理员备注信息',
  166. example: '请尽快发货'
  167. }),
  168. createdBy: z.number().int().positive().nullable().optional().openapi({
  169. description: '创建人ID',
  170. example: 1
  171. }),
  172. updatedBy: z.number().int().positive().nullable().optional().openapi({
  173. description: '更新人ID',
  174. example: 1
  175. }),
  176. createdAt: z.coerce.date().openapi({
  177. description: '创建时间',
  178. example: '2024-01-01T12:00:00Z'
  179. }),
  180. updatedAt: z.coerce.date().openapi({
  181. description: '更新时间',
  182. example: '2024-01-01T12:00:00Z'
  183. }),
  184. // 关联实体
  185. user: z.object({
  186. id: z.number().int().positive().openapi({ description: '用户ID' }),
  187. username: z.string().openapi({ description: '用户名', example: 'user123' }),
  188. phone: z.string().nullable().openapi({ description: '手机号', example: '13800138000' })
  189. }).nullable().optional().openapi({
  190. description: '用户信息'
  191. }),
  192. merchant: z.object({
  193. id: z.number().int().positive().openapi({ description: '商户ID' }),
  194. name: z.string().openapi({ description: '商户名称', example: '商户A' })
  195. }).nullable().optional().openapi({
  196. description: '商户信息'
  197. }),
  198. supplier: z.object({
  199. id: z.number().int().positive().openapi({ description: '供货商ID' }),
  200. name: z.string().openapi({ description: '供货商名称', example: '供货商A' })
  201. }).nullable().optional().openapi({
  202. description: '供货商信息'
  203. }),
  204. deliveryAddress: z.object({
  205. id: z.number().int().positive().openapi({ description: '地址ID' }),
  206. name: z.string().openapi({ description: '收货人姓名', example: '张三' }),
  207. phone: z.string().openapi({ description: '收货人电话', example: '13800138000' }),
  208. address: z.string().openapi({ description: '详细地址', example: '北京市朝阳区xxx路xxx号' })
  209. }).nullable().optional().openapi({
  210. description: '收货地址信息'
  211. })
  212. });
  213. // 创建订单DTO
  214. export const CreateOrderDto = z.object({
  215. orderNo: z.string().min(1, '订单号不能为空').max(50, '订单号最多50个字符').openapi({
  216. description: '订单号',
  217. example: 'ORD20240101123456'
  218. }),
  219. userId: z.number().int().positive('用户ID必须是正整数').openapi({
  220. description: '用户ID',
  221. example: 1
  222. }),
  223. authCode: z.string().max(32, '付款码最多32个字符').nullable().optional().openapi({
  224. description: '付款码',
  225. example: '12345678901234567890123456789012'
  226. }),
  227. cardNo: z.string().max(32, '卡号最多32个字符').nullable().optional().openapi({
  228. description: '卡号',
  229. example: '6222********1234'
  230. }),
  231. sjtCardNo: z.string().max(32, '盛京通卡号最多32个字符').nullable().optional().openapi({
  232. description: '盛京通卡号',
  233. example: 'SJT1234567890'
  234. }),
  235. amount: z.coerce.number().min(0, '订单金额不能小于0').max(999999.99, '订单金额不能超过999999.99').openapi({
  236. description: '订单金额',
  237. example: 99.99
  238. }),
  239. costAmount: z.coerce.number().min(0, '成本金额不能小于0').max(999999.99, '成本金额不能超过999999.99').default(0).optional().openapi({
  240. description: '成本金额',
  241. example: 50.00
  242. }),
  243. freightAmount: z.coerce.number().min(0, '运费不能小于0').max(999999.99, '运费不能超过999999.99').default(0).optional().openapi({
  244. description: '运费',
  245. example: 10.00
  246. }),
  247. discountAmount: z.coerce.number().min(0, '优惠金额不能小于0').max(999999.99, '优惠金额不能超过999999.99').default(0).optional().openapi({
  248. description: '优惠金额',
  249. example: 5.00
  250. }),
  251. payAmount: z.coerce.number().min(0, '实际支付金额不能小于0').max(999999.99, '实际支付金额不能超过999999.99').default(0).optional().openapi({
  252. description: '实际支付金额',
  253. example: 94.99
  254. }),
  255. deviceNo: z.string().max(255, '设备编号最多255个字符').nullable().optional().openapi({
  256. description: '设备编号',
  257. example: 'DEV001234'
  258. }),
  259. description: z.string().max(255, '订单描述最多255个字符').nullable().optional().openapi({
  260. description: '订单描述',
  261. example: '购买商品'
  262. }),
  263. goodsDetail: z.string().max(2000, '订单详情最多2000个字符').nullable().optional().openapi({
  264. description: '订单详情(json格式)',
  265. example: '[{"goodsId":1,"name":"商品1","price":99.99,"num":1}]'
  266. }),
  267. goodsTag: z.string().max(255, '订单优惠标记最多255个字符').nullable().optional().openapi({
  268. description: '订单优惠标记',
  269. example: '满100减5'
  270. }),
  271. address: z.string().max(255, '地址最多255个字符').nullable().optional().openapi({
  272. description: '地址',
  273. example: '北京市朝阳区xxx路xxx号'
  274. }),
  275. orderType: z.coerce.number().int().min(1, '订单类型最小为1').max(2, '订单类型最大为2').default(1).openapi({
  276. description: '订单类型 1实物订单 2虚拟订单',
  277. example: 1
  278. }),
  279. payType: z.coerce.number().int().min(0, '支付类型最小为0').max(4, '支付类型最大为4').default(0).openapi({
  280. description: '支付类型1积分2礼券3额度支付4微信支付',
  281. example: 1
  282. }),
  283. payState: z.coerce.number().int().min(0, '支付状态最小为0').max(5, '支付状态最大为5').default(0).openapi({
  284. description: '支付状态 0未支付1支付中2支付成功3已退款4支付失败5订单关闭',
  285. example: 2
  286. }),
  287. state: z.coerce.number().int().min(0, '订单状态最小为0').max(3, '订单状态最大为3').default(0).openapi({
  288. description: '订单状态 0未发货1已发货2收货成功3已退货',
  289. example: 0
  290. }),
  291. userPhone: z.string().max(50, '用户手机号最多50个字符').nullable().optional().openapi({
  292. description: '用户手机号',
  293. example: '13800138000'
  294. }),
  295. merchantId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  296. description: '商户id',
  297. example: 1
  298. }),
  299. merchantNo: z.coerce.number().int().min(0, '不能小于0').nullable().optional().openapi({
  300. description: '商户号',
  301. example: 1001
  302. }),
  303. supplierId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  304. description: '供货商id',
  305. example: 1
  306. }),
  307. addressId: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  308. description: '地址id',
  309. example: 1
  310. }),
  311. receiverMobile: z.string().max(255, '收货人手机号最多255个字符').nullable().optional().openapi({
  312. description: '收货人手机号',
  313. example: '13800138000'
  314. }),
  315. recevierName: z.string().max(255, '收货人姓名最多255个字符').nullable().optional().openapi({
  316. description: '收货人姓名',
  317. example: '张三'
  318. }),
  319. recevierProvince: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  320. description: '收货人所在省',
  321. example: 110000
  322. }),
  323. recevierCity: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  324. description: '收货人所在市',
  325. example: 110100
  326. }),
  327. recevierDistrict: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  328. description: '收货人所在区',
  329. example: 110105
  330. }),
  331. recevierTown: z.coerce.number().int().min(0, '不能小于0').default(0).openapi({
  332. description: '收货人所在街道',
  333. example: 110105001
  334. }),
  335. refundTime: z.coerce.date().nullable().optional().openapi({
  336. description: '退款时间',
  337. example: '2024-01-01T12:00:00Z'
  338. }),
  339. closeTime: z.coerce.date().nullable().optional().openapi({
  340. description: '订单关闭时间',
  341. example: '2024-01-01T12:00:00Z'
  342. }),
  343. remark: z.string().max(255, '管理员备注信息最多255个字符').nullable().optional().openapi({
  344. description: '管理员备注信息',
  345. example: '请尽快发货'
  346. })
  347. });
  348. // 更新订单DTO
  349. export const UpdateOrderDto = z.object({
  350. orderNo: z.string().min(1, '订单号不能为空').max(50, '订单号最多50个字符').optional().openapi({
  351. description: '订单号',
  352. example: 'ORD20240101123456'
  353. }),
  354. userId: z.number().int().positive('用户ID必须是正整数').optional().openapi({
  355. description: '用户ID',
  356. example: 1
  357. }),
  358. authCode: z.string().max(32, '付款码最多32个字符').nullable().optional().openapi({
  359. description: '付款码',
  360. example: '12345678901234567890123456789012'
  361. }),
  362. cardNo: z.string().max(32, '卡号最多32个字符').nullable().optional().openapi({
  363. description: '卡号',
  364. example: '6222********1234'
  365. }),
  366. sjtCardNo: z.string().max(32, '盛京通卡号最多32个字符').nullable().optional().openapi({
  367. description: '盛京通卡号',
  368. example: 'SJT1234567890'
  369. }),
  370. amount: z.coerce.number().min(0, '订单金额不能小于0').max(999999.99, '订单金额不能超过999999.99').optional().openapi({
  371. description: '订单金额',
  372. example: 99.99
  373. }),
  374. costAmount: z.coerce.number().min(0, '成本金额不能小于0').max(999999.99, '成本金额不能超过999999.99').optional().openapi({
  375. description: '成本金额',
  376. example: 50.00
  377. }),
  378. freightAmount: z.coerce.number().min(0, '运费不能小于0').max(999999.99, '运费不能超过999999.99').optional().openapi({
  379. description: '运费',
  380. example: 10.00
  381. }),
  382. discountAmount: z.coerce.number().min(0, '优惠金额不能小于0').max(999999.99, '优惠金额不能超过999999.99').optional().openapi({
  383. description: '优惠金额',
  384. example: 5.00
  385. }),
  386. payAmount: z.coerce.number().min(0, '实际支付金额不能小于0').max(999999.99, '实际支付金额不能超过999999.99').optional().openapi({
  387. description: '实际支付金额',
  388. example: 94.99
  389. }),
  390. deviceNo: z.string().max(255, '设备编号最多255个字符').nullable().optional().openapi({
  391. description: '设备编号',
  392. example: 'DEV001234'
  393. }),
  394. description: z.string().max(255, '订单描述最多255个字符').nullable().optional().openapi({
  395. description: '订单描述',
  396. example: '购买商品'
  397. }),
  398. goodsDetail: z.string().max(2000, '订单详情最多2000个字符').nullable().optional().openapi({
  399. description: '订单详情(json格式)',
  400. example: '[{"goodsId":1,"name":"商品1","price":99.99,"num":1}]'
  401. }),
  402. goodsTag: z.string().max(255, '订单优惠标记最多255个字符').nullable().optional().openapi({
  403. description: '订单优惠标记',
  404. example: '满100减5'
  405. }),
  406. address: z.string().max(255, '地址最多255个字符').nullable().optional().openapi({
  407. description: '地址',
  408. example: '北京市朝阳区xxx路xxx号'
  409. }),
  410. orderType: z.coerce.number().int().min(1, '订单类型最小为1').max(2, '订单类型最大为2').optional().openapi({
  411. description: '订单类型 1实物订单 2虚拟订单',
  412. example: 1
  413. }),
  414. payType: z.coerce.number().int().min(0, '支付类型最小为0').max(4, '支付类型最大为4').optional().openapi({
  415. description: '支付类型1积分2礼券3额度支付4微信支付',
  416. example: 1
  417. }),
  418. payState: z.coerce.number().int().min(0, '支付状态最小为0').max(5, '支付状态最大为5').optional().openapi({
  419. description: '支付状态 0未支付1支付中2支付成功3已退款4支付失败5订单关闭',
  420. example: 2
  421. }),
  422. state: z.coerce.number().int().min(0, '订单状态最小为0').max(3, '订单状态最大为3').optional().openapi({
  423. description: '订单状态 0未发货1已发货2收货成功3已退货',
  424. example: 0
  425. }),
  426. userPhone: z.string().max(50, '用户手机号最多50个字符').nullable().optional().openapi({
  427. description: '用户手机号',
  428. example: '13800138000'
  429. }),
  430. merchantId: z.coerce.number().int().positive().optional().openapi({
  431. description: '商户id',
  432. example: 1
  433. }),
  434. merchantNo: z.coerce.number().int().min(0, '不能小于0').nullable().optional().openapi({
  435. description: '商户号',
  436. example: 1001
  437. }),
  438. supplierId: z.coerce.number().int().positive().optional().openapi({
  439. description: '供货商id',
  440. example: 1
  441. }),
  442. addressId: z.coerce.number().int().positive().optional().openapi({
  443. description: '地址id',
  444. example: 1
  445. }),
  446. receiverMobile: z.string().max(255, '收货人手机号最多255个字符').nullable().optional().openapi({
  447. description: '收货人手机号',
  448. example: '13800138000'
  449. }),
  450. recevierName: z.string().max(255, '收货人姓名最多255个字符').nullable().optional().openapi({
  451. description: '收货人姓名',
  452. example: '张三'
  453. }),
  454. recevierProvince: z.coerce.number().int().positive().optional().openapi({
  455. description: '收货人所在省',
  456. example: 110000
  457. }),
  458. recevierCity: z.coerce.number().int().positive().optional().openapi({
  459. description: '收货人所在市',
  460. example: 110100
  461. }),
  462. recevierDistrict: z.coerce.number().int().positive().optional().openapi({
  463. description: '收货人所在区',
  464. example: 110105
  465. }),
  466. recevierTown: z.coerce.number().int().positive().optional().openapi({
  467. description: '收货人所在街道',
  468. example: 110105001
  469. }),
  470. refundTime: z.coerce.date().nullable().optional().openapi({
  471. description: '退款时间',
  472. example: '2024-01-01T12:00:00Z'
  473. }),
  474. closeTime: z.coerce.date().nullable().optional().openapi({
  475. description: '订单关闭时间',
  476. example: '2024-01-01T12:00:00Z'
  477. }),
  478. remark: z.string().max(255, '管理员备注信息最多255个字符').nullable().optional().openapi({
  479. description: '管理员备注信息',
  480. example: '请尽快发货'
  481. })
  482. });
  483. // 订单列表响应Schema
  484. export const OrderListResponse = z.object({
  485. data: z.array(OrderSchema),
  486. pagination: z.object({
  487. total: z.number().openapi({ example: 100, description: '总记录数' }),
  488. current: z.number().openapi({ example: 1, description: '当前页码' }),
  489. pageSize: z.number().openapi({ example: 10, description: '每页数量' })
  490. })
  491. });