mall-components 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +128 -0
  2. package/build/_components-raw.css +791 -0
  3. package/build/_shims/antd.js +1 -0
  4. package/build/_shims/icons.js +1 -0
  5. package/build/_shims/moment.js +1 -0
  6. package/build/_shims/react-dom.js +1 -0
  7. package/build/_shims/react.js +1 -0
  8. package/build/adapters/DataSourceAdapter.d.ts +46 -0
  9. package/build/components/AdminLayout/AdminLayout.d.ts +5 -0
  10. package/build/components/AdminLayout/Breadcrumb.d.ts +8 -0
  11. package/build/components/AdminLayout/MainContent.d.ts +17 -0
  12. package/build/components/AdminLayout/Navbar.d.ts +10 -0
  13. package/build/components/AdminLayout/Sidebar.d.ts +14 -0
  14. package/build/components/AdminLayout/TabBar.d.ts +13 -0
  15. package/build/components/AdminLayout/TabPane.d.ts +4 -0
  16. package/build/components/AdminLayout/index.d.ts +3 -0
  17. package/build/components/AdminLayout/types.d.ts +42 -0
  18. package/build/components/CouponCard/CouponCard.d.ts +20 -0
  19. package/build/components/CouponCard/index.d.ts +1 -0
  20. package/build/components/OrderForm/OrderForm.d.ts +18 -0
  21. package/build/components/OrderForm/index.d.ts +1 -0
  22. package/build/components/OrderList/OrderList.d.ts +29 -0
  23. package/build/components/OrderList/index.d.ts +1 -0
  24. package/build/components/ProductForm/ProductForm.d.ts +18 -0
  25. package/build/components/ProductForm/index.d.ts +3 -0
  26. package/build/components/ProductList/ProductList.d.ts +47 -0
  27. package/build/components/ProductList/index.d.ts +3 -0
  28. package/build/components/PromotionCard/PromotionCard.d.ts +22 -0
  29. package/build/components/PromotionCard/index.d.ts +1 -0
  30. package/build/components/RoleCard/RoleCard.d.ts +18 -0
  31. package/build/components/RoleCard/index.d.ts +1 -0
  32. package/build/components/UserCard/UserCard.d.ts +17 -0
  33. package/build/components/UserCard/index.d.ts +1 -0
  34. package/build/entry-meta.d.ts +603 -0
  35. package/build/index.css +1 -0
  36. package/build/index.js +1 -0
  37. package/build/mall-components-meta.js +2563 -0
  38. package/build/mall-components.cdn.umd.css +1 -0
  39. package/build/mall-components.cdn.umd.js +8 -0
  40. package/build/mall-components.codesandbox.combined.js +1094 -0
  41. package/build/mall-components.codesandbox.css +401 -0
  42. package/build/mall-components.codesandbox.js +1080 -0
  43. package/build/mall-components.umd.css +1 -0
  44. package/build/mall-components.umd.js +8 -0
  45. package/build/meta/adminLayoutMeta.d.ts +3 -0
  46. package/build/meta/couponCardMeta.d.ts +128 -0
  47. package/build/meta/icons.d.ts +10 -0
  48. package/build/meta/orderFormMeta.d.ts +111 -0
  49. package/build/meta/orderListMeta.d.ts +170 -0
  50. package/build/meta/productFormMeta.d.ts +3 -0
  51. package/build/meta/productListMeta.d.ts +200 -0
  52. package/build/meta/promotionCardMeta.d.ts +129 -0
  53. package/build/meta/roleCardMeta.d.ts +3 -0
  54. package/build/meta/tabPaneMeta.d.ts +3 -0
  55. package/build/meta/userCardMeta.d.ts +3 -0
  56. package/build/meta.d.ts +605 -0
  57. package/build/setters/RestApiTester.d.ts +11 -0
  58. package/build/types/common.d.ts +17 -0
  59. package/build/types/marketing.d.ts +128 -0
  60. package/build/types/order.d.ts +174 -0
  61. package/build/types/permission.d.ts +101 -0
  62. package/build/types/product.d.ts +47 -0
  63. package/package.json +1 -0
  64. package/src/adapters/DataSourceAdapter.ts +445 -0
  65. package/src/components/AdminLayout/AdminLayout.scss +447 -0
  66. package/src/components/AdminLayout/AdminLayout.tsx +681 -0
  67. package/src/components/AdminLayout/Breadcrumb.tsx +60 -0
  68. package/src/components/AdminLayout/MainContent.tsx +54 -0
  69. package/src/components/AdminLayout/Navbar.tsx +76 -0
  70. package/src/components/AdminLayout/Sidebar.tsx +256 -0
  71. package/src/components/AdminLayout/TabBar.tsx +177 -0
  72. package/src/components/AdminLayout/TabPane.tsx +29 -0
  73. package/src/components/AdminLayout/index.ts +3 -0
  74. package/src/components/AdminLayout/types.ts +46 -0
  75. package/src/components/CouponCard/CouponCard.scss +55 -0
  76. package/src/components/CouponCard/CouponCard.tsx +687 -0
  77. package/src/components/CouponCard/index.ts +1 -0
  78. package/src/components/OrderForm/OrderForm.scss +148 -0
  79. package/src/components/OrderForm/OrderForm.tsx +503 -0
  80. package/src/components/OrderForm/index.ts +1 -0
  81. package/src/components/OrderList/OrderList.scss +160 -0
  82. package/src/components/OrderList/OrderList.tsx +885 -0
  83. package/src/components/OrderList/index.ts +1 -0
  84. package/src/components/ProductForm/ProductForm.scss +23 -0
  85. package/src/components/ProductForm/ProductForm.tsx +442 -0
  86. package/src/components/ProductForm/index.ts +3 -0
  87. package/src/components/ProductList/ProductList.scss +293 -0
  88. package/src/components/ProductList/ProductList.tsx +454 -0
  89. package/src/components/ProductList/index.ts +3 -0
  90. package/src/components/PromotionCard/PromotionCard.scss +71 -0
  91. package/src/components/PromotionCard/PromotionCard.tsx +579 -0
  92. package/src/components/PromotionCard/index.ts +1 -0
  93. package/src/components/RoleCard/RoleCard.scss +77 -0
  94. package/src/components/RoleCard/RoleCard.tsx +463 -0
  95. package/src/components/RoleCard/index.ts +1 -0
  96. package/src/components/UserCard/UserCard.scss +51 -0
  97. package/src/components/UserCard/UserCard.tsx +432 -0
  98. package/src/components/UserCard/index.ts +1 -0
  99. package/src/entry-components.ts +39 -0
  100. package/src/entry-meta.ts +23 -0
  101. package/src/index.scss +4 -0
  102. package/src/index.ts +36 -0
  103. package/src/index.tsx +17 -0
  104. package/src/meta/adminLayoutMeta.ts +154 -0
  105. package/src/meta/couponCardMeta.ts +287 -0
  106. package/src/meta/icons.ts +41 -0
  107. package/src/meta/orderFormMeta.ts +279 -0
  108. package/src/meta/orderListMeta.ts +443 -0
  109. package/src/meta/productFormMeta.ts +253 -0
  110. package/src/meta/productListMeta.ts +434 -0
  111. package/src/meta/promotionCardMeta.ts +276 -0
  112. package/src/meta/roleCardMeta.ts +142 -0
  113. package/src/meta/tabPaneMeta.ts +69 -0
  114. package/src/meta/userCardMeta.ts +128 -0
  115. package/src/meta.ts +25 -0
  116. package/src/setters/RestApiTester.tsx +219 -0
  117. package/src/shims/require.js +8 -0
  118. package/src/types/common.ts +19 -0
  119. package/src/types/marketing.ts +124 -0
  120. package/src/types/order.ts +169 -0
  121. package/src/types/permission.ts +102 -0
  122. package/src/types/product.ts +49 -0
@@ -0,0 +1,885 @@
1
+ import React, { useEffect, useState, useMemo } from 'react'
2
+ import {
3
+ Table,
4
+ Card,
5
+ Button,
6
+ Input,
7
+ Select,
8
+ Space,
9
+ Tag,
10
+ DatePicker,
11
+ Modal,
12
+ Descriptions,
13
+ message,
14
+ Dropdown,
15
+ Menu,
16
+ Tooltip,
17
+ Row,
18
+ Col,
19
+ Form,
20
+ } from 'antd'
21
+ import type { ColumnsType } from 'antd/es/table'
22
+ import {
23
+ SearchOutlined,
24
+ ReloadOutlined,
25
+ ExportOutlined,
26
+ EyeOutlined,
27
+ CloseCircleOutlined,
28
+ DeleteOutlined,
29
+ MoreOutlined,
30
+ CarOutlined,
31
+ } from '@ant-design/icons'
32
+ import type {
33
+ OmsOrder,
34
+ OmsOrderDetail,
35
+ OrderQueryParam,
36
+ OmsOrderDeliveryParam,
37
+ } from '../../types/order'
38
+ import {
39
+ ORDER_STATUS_OPTIONS,
40
+ PAY_TYPE_OPTIONS,
41
+ SOURCE_TYPE_OPTIONS,
42
+ ORDER_TYPE_OPTIONS,
43
+ ORDER_STATUS,
44
+ PAY_TYPE,
45
+ SOURCE_TYPE,
46
+ ORDER_TYPE,
47
+ } from '../../types/order'
48
+ import { DataSourceAdapterFactory, DataSourceConfig } from '../../adapters/DataSourceAdapter'
49
+ import './OrderList.scss'
50
+
51
+ const { RangePicker } = DatePicker
52
+
53
+ interface OrderListProps {
54
+ dataSourceType?: 'rest' | 'mock' | 'variable'
55
+ api?: string
56
+ method?: 'GET' | 'POST'
57
+ mockData?: string
58
+ variableName?: string
59
+ dataSource?: any
60
+ showFilter?: boolean
61
+ showStatusFilter?: boolean
62
+ showSearch?: boolean
63
+ showDatePicker?: boolean
64
+ showActions?: boolean
65
+ showBatchOperations?: boolean
66
+ showExport?: boolean
67
+ showPagination?: boolean
68
+ defaultPageSize?: number
69
+ onRowClick?: (record: OmsOrder) => void
70
+ onSearch?: (params: OrderQueryParam) => void
71
+ onPageChange?: (page: number, pageSize: number) => void
72
+ onActionClick?: (action: string, record: OmsOrder) => void
73
+ onBatchOperation?: (operation: string, orderIds: number[]) => void
74
+ style?: React.CSSProperties
75
+ className?: string
76
+ }
77
+
78
+ const defaultMockDataObj = {
79
+ code: 200,
80
+ message: 'success',
81
+ data: {
82
+ pageNum: 1,
83
+ pageSize: 10,
84
+ total: 50,
85
+ list: [
86
+ {
87
+ id: 1,
88
+ orderSn: '202401010001',
89
+ memberUsername: 'user001',
90
+ totalAmount: 599.00,
91
+ payAmount: 569.00,
92
+ freightAmount: 0,
93
+ discountAmount: 30.00,
94
+ payType: PAY_TYPE.ALIPAY,
95
+ sourceType: SOURCE_TYPE.PC,
96
+ status: ORDER_STATUS.PENDING_DELIVERY,
97
+ orderType: ORDER_TYPE.NORMAL,
98
+ receiverName: '张三',
99
+ receiverPhone: '13800138000',
100
+ receiverProvince: '北京市',
101
+ receiverCity: '北京市',
102
+ receiverRegion: '朝阳区',
103
+ receiverDetailAddress: '某某街道某某小区1号楼',
104
+ createTime: '2024-01-01 10:00:00',
105
+ paymentTime: '2024-01-01 10:05:00',
106
+ deliveryTime: '',
107
+ receiveTime: '',
108
+ commentTime: '',
109
+ promotionInfo: '满减优惠',
110
+ },
111
+ {
112
+ id: 2,
113
+ orderSn: '202401010002',
114
+ memberUsername: 'user002',
115
+ totalAmount: 1299.00,
116
+ payAmount: 1299.00,
117
+ freightAmount: 0,
118
+ discountAmount: 0,
119
+ payType: PAY_TYPE.WECHAT,
120
+ sourceType: SOURCE_TYPE.APP,
121
+ status: ORDER_STATUS.DELIVERED,
122
+ orderType: ORDER_TYPE.NORMAL,
123
+ receiverName: '李四',
124
+ receiverPhone: '13900139000',
125
+ receiverProvince: '上海市',
126
+ receiverCity: '上海市',
127
+ receiverRegion: '浦东新区',
128
+ receiverDetailAddress: '某某路某某号',
129
+ createTime: '2024-01-01 11:00:00',
130
+ paymentTime: '2024-01-01 11:10:00',
131
+ deliveryTime: '2024-01-02 09:00:00',
132
+ receiveTime: '',
133
+ commentTime: '',
134
+ promotionInfo: '',
135
+ },
136
+ {
137
+ id: 3,
138
+ orderSn: '202401010003',
139
+ memberUsername: 'user003',
140
+ totalAmount: 299.00,
141
+ payAmount: 299.00,
142
+ freightAmount: 10.00,
143
+ discountAmount: 0,
144
+ payType: PAY_TYPE.ALIPAY,
145
+ sourceType: SOURCE_TYPE.PC,
146
+ status: ORDER_STATUS.COMPLETED,
147
+ orderType: ORDER_TYPE.NORMAL,
148
+ receiverName: '王五',
149
+ receiverPhone: '13700137000',
150
+ receiverProvince: '广东省',
151
+ receiverCity: '深圳市',
152
+ receiverRegion: '南山区',
153
+ receiverDetailAddress: '某某大厦A座',
154
+ createTime: '2024-01-01 12:00:00',
155
+ paymentTime: '2024-01-01 12:05:00',
156
+ deliveryTime: '2024-01-02 10:00:00',
157
+ receiveTime: '2024-01-05 15:00:00',
158
+ commentTime: '',
159
+ promotionInfo: '',
160
+ },
161
+ {
162
+ id: 4,
163
+ orderSn: '202401010004',
164
+ memberUsername: 'user004',
165
+ totalAmount: 899.00,
166
+ payAmount: 0,
167
+ freightAmount: 0,
168
+ discountAmount: 0,
169
+ payType: PAY_TYPE.UNPAID,
170
+ sourceType: SOURCE_TYPE.APP,
171
+ status: ORDER_STATUS.PENDING_PAYMENT,
172
+ orderType: ORDER_TYPE.SECKILL,
173
+ receiverName: '赵六',
174
+ receiverPhone: '13600136000',
175
+ receiverProvince: '浙江省',
176
+ receiverCity: '杭州市',
177
+ receiverRegion: '西湖区',
178
+ receiverDetailAddress: '某某花园小区',
179
+ createTime: '2024-01-01 13:00:00',
180
+ paymentTime: '',
181
+ deliveryTime: '',
182
+ receiveTime: '',
183
+ commentTime: '',
184
+ promotionInfo: '秒杀活动',
185
+ },
186
+ {
187
+ id: 5,
188
+ orderSn: '202401010005',
189
+ memberUsername: 'user005',
190
+ totalAmount: 4599.00,
191
+ payAmount: 4599.00,
192
+ freightAmount: 0,
193
+ discountAmount: 0,
194
+ payType: PAY_TYPE.WECHAT,
195
+ sourceType: SOURCE_TYPE.PC,
196
+ status: ORDER_STATUS.CLOSED,
197
+ orderType: ORDER_TYPE.NORMAL,
198
+ receiverName: '孙七',
199
+ receiverPhone: '13500135000',
200
+ receiverProvince: '江苏省',
201
+ receiverCity: '南京市',
202
+ receiverRegion: '鼓楼区',
203
+ receiverDetailAddress: '某某广场B座',
204
+ createTime: '2024-01-01 14:00:00',
205
+ paymentTime: '2024-01-01 14:10:00',
206
+ deliveryTime: '',
207
+ receiveTime: '',
208
+ commentTime: '',
209
+ promotionInfo: '',
210
+ },
211
+ ],
212
+ },
213
+ }
214
+
215
+ const OrderList: React.FC<OrderListProps> = ({
216
+ dataSourceType = 'mock',
217
+ api,
218
+ method = 'GET',
219
+ mockData,
220
+ variableName,
221
+ dataSource,
222
+ showFilter = true,
223
+ showStatusFilter = true,
224
+ showSearch = true,
225
+ showDatePicker = true,
226
+ showActions = true,
227
+ showBatchOperations = true,
228
+ showExport = true,
229
+ showPagination = true,
230
+ defaultPageSize = 10,
231
+ onRowClick,
232
+ onSearch,
233
+ onPageChange,
234
+ onActionClick,
235
+ onBatchOperation,
236
+ style,
237
+ className,
238
+ }) => {
239
+ const [loading, setLoading] = useState(false)
240
+ const [data, setData] = useState<OmsOrder[]>([])
241
+ const [total, setTotal] = useState(0)
242
+ const [currentPage, setCurrentPage] = useState(1)
243
+ const [pageSize, setPageSize] = useState(defaultPageSize)
244
+ const [searchText, setSearchText] = useState('')
245
+ const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
246
+ const [selectedRows, setSelectedRows] = useState<OmsOrder[]>([])
247
+ const [batchOperation, setBatchOperation] = useState<string>()
248
+ const [filterStatus, setFilterStatus] = useState<number>()
249
+ const [filterOrderType, setFilterOrderType] = useState<number>()
250
+ const [filterSourceType, setFilterSourceType] = useState<number>()
251
+ const [dateRange, setDateRange] = useState<[any, any]>()
252
+ const [detailVisible, setDetailVisible] = useState(false)
253
+ const [currentOrder, setCurrentOrder] = useState<OmsOrderDetail>()
254
+ const [deliveryVisible, setDeliveryVisible] = useState(false)
255
+ const [deliveryOrder, setDeliveryOrder] = useState<OmsOrder>()
256
+ const [deliveryCompany, setDeliveryCompany] = useState('')
257
+ const [deliverySn, setDeliverySn] = useState('')
258
+
259
+ const dataSourceConfig: DataSourceConfig = useMemo(() => ({
260
+ type: dataSourceType,
261
+ api,
262
+ method,
263
+ mockData: mockData ? (() => {
264
+ try {
265
+ return typeof mockData === 'string' ? JSON.parse(mockData) : mockData
266
+ } catch {
267
+ return defaultMockDataObj
268
+ }
269
+ })() : defaultMockDataObj,
270
+ variableName,
271
+ dataSource,
272
+ }), [dataSourceType, api, method, mockData, variableName, dataSource])
273
+
274
+ const adapter = useMemo(() => {
275
+ return DataSourceAdapterFactory.create(dataSourceConfig)
276
+ }, [dataSourceConfig])
277
+
278
+ useEffect(() => {
279
+ fetchData()
280
+ }, [currentPage, pageSize, adapter])
281
+
282
+ const fetchData = async () => {
283
+ setLoading(true)
284
+ try {
285
+ const params: OrderQueryParam = {
286
+ pageNum: currentPage,
287
+ pageSize,
288
+ orderSn: searchText || undefined,
289
+ status: filterStatus,
290
+ orderType: filterOrderType,
291
+ sourceType: filterSourceType,
292
+ createTime: dateRange
293
+ ? `${dateRange[0]?.format('YYYY-MM-DD')},${dateRange[1]?.format('YYYY-MM-DD')}`
294
+ : undefined,
295
+ }
296
+
297
+ const result = await adapter.fetch(params)
298
+
299
+ let list: OmsOrder[] = []
300
+ let totalCount = 0
301
+
302
+ if (result?.data?.list) {
303
+ list = result.data.list
304
+ totalCount = result.data.total || list.length
305
+ } else if (Array.isArray(result?.data)) {
306
+ list = result.data
307
+ totalCount = list.length
308
+ } else if (Array.isArray(result)) {
309
+ list = result
310
+ totalCount = list.length
311
+ }
312
+
313
+ setData(list)
314
+ setTotal(totalCount)
315
+ } catch (error) {
316
+ console.error('Failed to fetch order list:', error)
317
+ message.error('获取订单列表失败')
318
+ setData(defaultMockDataObj.data.list)
319
+ setTotal(defaultMockDataObj.data.total)
320
+ } finally {
321
+ setLoading(false)
322
+ }
323
+ }
324
+
325
+ const handleSearch = () => {
326
+ setCurrentPage(1)
327
+ fetchData()
328
+ onSearch?.({
329
+ orderSn: searchText || undefined,
330
+ status: filterStatus,
331
+ orderType: filterOrderType,
332
+ sourceType: filterSourceType,
333
+ createTime: dateRange
334
+ ? `${dateRange[0]?.format('YYYY-MM-DD')},${dateRange[1]?.format('YYYY-MM-DD')}`
335
+ : undefined,
336
+ })
337
+ }
338
+
339
+ const handleReset = () => {
340
+ setSearchText('')
341
+ setFilterStatus(undefined)
342
+ setFilterOrderType(undefined)
343
+ setFilterSourceType(undefined)
344
+ setDateRange(undefined)
345
+ setCurrentPage(1)
346
+ fetchData()
347
+ }
348
+
349
+ const handleExport = () => {
350
+ message.success('导出功能开发中...')
351
+ }
352
+
353
+ const handleRefresh = () => {
354
+ fetchData()
355
+ }
356
+
357
+ const handleBatchOperation = () => {
358
+ if (!batchOperation) {
359
+ message.warning('请选择批量操作类型')
360
+ return
361
+ }
362
+ if (selectedRowKeys.length === 0) {
363
+ message.warning('请选择要操作的订单')
364
+ return
365
+ }
366
+ onBatchOperation?.(batchOperation, selectedRowKeys as number[])
367
+ message.success(`批量${batchOperation}成功`)
368
+ setSelectedRowKeys([])
369
+ setSelectedRows([])
370
+ setBatchOperation(undefined)
371
+ fetchData()
372
+ }
373
+
374
+ const handleViewDetail = (record: OmsOrder) => {
375
+ setCurrentOrder(record as OmsOrderDetail)
376
+ setDetailVisible(true)
377
+ onActionClick?.('view', record)
378
+ }
379
+
380
+ const handleDeliver = (record: OmsOrder) => {
381
+ setDeliveryOrder(record)
382
+ setDeliveryVisible(true)
383
+ onActionClick?.('deliver', record)
384
+ }
385
+
386
+ const handleCloseOrder = (record: OmsOrder) => {
387
+ Modal.confirm({
388
+ title: '确认关闭订单',
389
+ content: `确定要关闭订单 ${record.orderSn} 吗?`,
390
+ onOk: () => {
391
+ onActionClick?.('close', record)
392
+ message.success('订单已关闭')
393
+ fetchData()
394
+ },
395
+ })
396
+ }
397
+
398
+ const handleDeleteOrder = (record: OmsOrder) => {
399
+ Modal.confirm({
400
+ title: '确认删除订单',
401
+ content: `确定要删除订单 ${record.orderSn} 吗?`,
402
+ onOk: () => {
403
+ onActionClick?.('delete', record)
404
+ message.success('订单已删除')
405
+ fetchData()
406
+ },
407
+ })
408
+ }
409
+
410
+ const handleDeliverySubmit = () => {
411
+ if (!deliveryCompany || !deliverySn) {
412
+ message.warning('请填写物流公司和物流单号')
413
+ return
414
+ }
415
+ const params: OmsOrderDeliveryParam = {
416
+ orderId: deliveryOrder!.id,
417
+ deliveryCompany,
418
+ deliverySn,
419
+ }
420
+ onActionClick?.('deliverSubmit', deliveryOrder!)
421
+ message.success('发货成功')
422
+ setDeliveryVisible(false)
423
+ setDeliveryCompany('')
424
+ setDeliverySn('')
425
+ fetchData()
426
+ }
427
+
428
+ const getStatusTag = (status: number) => {
429
+ const statusMap: Record<number, { color: string; text: string }> = {
430
+ [ORDER_STATUS.PENDING_PAYMENT]: { color: 'orange', text: '待付款' },
431
+ [ORDER_STATUS.PENDING_DELIVERY]: { color: 'blue', text: '待发货' },
432
+ [ORDER_STATUS.DELIVERED]: { color: 'cyan', text: '已发货' },
433
+ [ORDER_STATUS.COMPLETED]: { color: 'green', text: '已完成' },
434
+ [ORDER_STATUS.CLOSED]: { color: 'default', text: '已关闭' },
435
+ [ORDER_STATUS.INVALID]: { color: 'red', text: '无效订单' },
436
+ }
437
+ const { color, text } = statusMap[status] || { color: 'default', text: '未知' }
438
+ return <Tag color={color}>{text}</Tag>
439
+ }
440
+
441
+ const getPayTypeTag = (payType: number) => {
442
+ const payTypeMap: Record<number, { color: string; text: string }> = {
443
+ [PAY_TYPE.UNPAID]: { color: 'default', text: '未支付' },
444
+ [PAY_TYPE.ALIPAY]: { color: 'blue', text: '支付宝' },
445
+ [PAY_TYPE.WECHAT]: { color: 'green', text: '微信' },
446
+ }
447
+ const { color, text } = payTypeMap[payType] || { color: 'default', text: '未知' }
448
+ return <Tag color={color}>{text}</Tag>
449
+ }
450
+
451
+ const getSourceTypeTag = (sourceType: number) => {
452
+ return sourceType === SOURCE_TYPE.APP ? (
453
+ <Tag color="purple">APP</Tag>
454
+ ) : (
455
+ <Tag color="geekblue">PC</Tag>
456
+ )
457
+ }
458
+
459
+ const getOrderTypeTag = (orderType: number) => {
460
+ return orderType === ORDER_TYPE.SECKILL ? (
461
+ <Tag color="red">秒杀</Tag>
462
+ ) : (
463
+ <Tag>正常</Tag>
464
+ )
465
+ }
466
+
467
+ const columns: ColumnsType<OmsOrder> = [
468
+ {
469
+ title: '订单编号',
470
+ dataIndex: 'orderSn',
471
+ key: 'orderSn',
472
+ width: 180,
473
+ fixed: 'left',
474
+ render: (text: string) => (
475
+ <Tooltip title={text}>
476
+ <span className="order-sn">{text}</span>
477
+ </Tooltip>
478
+ ),
479
+ },
480
+ {
481
+ title: '用户账号',
482
+ dataIndex: 'memberUsername',
483
+ key: 'memberUsername',
484
+ width: 120,
485
+ },
486
+ {
487
+ title: '订单金额',
488
+ dataIndex: 'totalAmount',
489
+ key: 'totalAmount',
490
+ width: 120,
491
+ render: (amount: number) => (
492
+ <span className="order-amount">¥{amount.toFixed(2)}</span>
493
+ ),
494
+ },
495
+ {
496
+ title: '实付金额',
497
+ dataIndex: 'payAmount',
498
+ key: 'payAmount',
499
+ width: 120,
500
+ render: (amount: number) => (
501
+ <span className="pay-amount">¥{amount.toFixed(2)}</span>
502
+ ),
503
+ },
504
+ {
505
+ title: '支付方式',
506
+ dataIndex: 'payType',
507
+ key: 'payType',
508
+ width: 100,
509
+ render: (payType: number) => getPayTypeTag(payType),
510
+ },
511
+ {
512
+ title: '订单来源',
513
+ dataIndex: 'sourceType',
514
+ key: 'sourceType',
515
+ width: 100,
516
+ render: (sourceType: number) => getSourceTypeTag(sourceType),
517
+ },
518
+ {
519
+ title: '订单类型',
520
+ dataIndex: 'orderType',
521
+ key: 'orderType',
522
+ width: 100,
523
+ render: (orderType: number) => getOrderTypeTag(orderType),
524
+ },
525
+ {
526
+ title: '订单状态',
527
+ dataIndex: 'status',
528
+ key: 'status',
529
+ width: 100,
530
+ render: (status: number) => getStatusTag(status),
531
+ },
532
+ {
533
+ title: '收货人',
534
+ dataIndex: 'receiverName',
535
+ key: 'receiverName',
536
+ width: 100,
537
+ },
538
+ {
539
+ title: '收货电话',
540
+ dataIndex: 'receiverPhone',
541
+ key: 'receiverPhone',
542
+ width: 130,
543
+ },
544
+ {
545
+ title: '下单时间',
546
+ dataIndex: 'createTime',
547
+ key: 'createTime',
548
+ width: 180,
549
+ sorter: true,
550
+ },
551
+ {
552
+ title: '操作',
553
+ key: 'action',
554
+ width: 200,
555
+ fixed: 'right',
556
+ render: (_, record) => {
557
+ const menu = (
558
+ <Menu>
559
+ <Menu.Item
560
+ key="view"
561
+ icon={<EyeOutlined />}
562
+ onClick={() => handleViewDetail(record)}
563
+ >
564
+ 查看详情
565
+ </Menu.Item>
566
+ {record.status === ORDER_STATUS.PENDING_DELIVERY && (
567
+ <Menu.Item
568
+ key="deliver"
569
+ icon={<CarOutlined />}
570
+ onClick={() => handleDeliver(record)}
571
+ >
572
+ 发货
573
+ </Menu.Item>
574
+ )}
575
+ {record.status !== ORDER_STATUS.CLOSED && (
576
+ <Menu.Item
577
+ key="close"
578
+ icon={<CloseCircleOutlined />}
579
+ onClick={() => handleCloseOrder(record)}
580
+ >
581
+ 关闭订单
582
+ </Menu.Item>
583
+ )}
584
+ <Menu.Divider />
585
+ <Menu.Item
586
+ key="delete"
587
+ icon={<DeleteOutlined />}
588
+ danger
589
+ onClick={() => handleDeleteOrder(record)}
590
+ >
591
+ 删除订单
592
+ </Menu.Item>
593
+ </Menu>
594
+ )
595
+
596
+ return (
597
+ <Space size="small">
598
+ <Button
599
+ type="link"
600
+ size="small"
601
+ onClick={() => handleViewDetail(record)}
602
+ >
603
+ 详情
604
+ </Button>
605
+ {record.status === ORDER_STATUS.PENDING_DELIVERY && (
606
+ <Button
607
+ type="link"
608
+ size="small"
609
+ onClick={() => handleDeliver(record)}
610
+ >
611
+ 发货
612
+ </Button>
613
+ )}
614
+ <Dropdown overlay={menu} trigger={['click']}>
615
+ <Button type="link" size="small" icon={<MoreOutlined />} />
616
+ </Dropdown>
617
+ </Space>
618
+ )
619
+ },
620
+ },
621
+ ]
622
+
623
+ const rowSelection = {
624
+ selectedRowKeys,
625
+ onChange: (selectedKeys: React.Key[], selectedRows: OmsOrder[]) => {
626
+ setSelectedRowKeys(selectedKeys)
627
+ setSelectedRows(selectedRows)
628
+ },
629
+ }
630
+
631
+ return (
632
+ <div className={`mall-order-list ${className || ''}`} style={style}>
633
+ <Card>
634
+ {showFilter && (
635
+ <div className="filter-section">
636
+ <Row gutter={[16, 16]}>
637
+ {showSearch && (
638
+ <Col span={6}>
639
+ <Input
640
+ placeholder="订单编号"
641
+ value={searchText}
642
+ onChange={(e) => setSearchText(e.target.value)}
643
+ onPressEnter={handleSearch}
644
+ prefix={<SearchOutlined />}
645
+ />
646
+ </Col>
647
+ )}
648
+ {showStatusFilter && (
649
+ <Col span={4}>
650
+ <Select
651
+ placeholder="订单状态"
652
+ value={filterStatus}
653
+ onChange={setFilterStatus}
654
+ style={{ width: '100%' }}
655
+ allowClear
656
+ >
657
+ {ORDER_STATUS_OPTIONS.map((option) => (
658
+ <Select.Option key={option.value} value={option.value}>
659
+ {option.label}
660
+ </Select.Option>
661
+ ))}
662
+ </Select>
663
+ </Col>
664
+ )}
665
+ <Col span={4}>
666
+ <Select
667
+ placeholder="订单类型"
668
+ value={filterOrderType}
669
+ onChange={setFilterOrderType}
670
+ style={{ width: '100%' }}
671
+ allowClear
672
+ >
673
+ {ORDER_TYPE_OPTIONS.map((option) => (
674
+ <Select.Option key={option.value} value={option.value}>
675
+ {option.label}
676
+ </Select.Option>
677
+ ))}
678
+ </Select>
679
+ </Col>
680
+ <Col span={4}>
681
+ <Select
682
+ placeholder="订单来源"
683
+ value={filterSourceType}
684
+ onChange={setFilterSourceType}
685
+ style={{ width: '100%' }}
686
+ allowClear
687
+ >
688
+ {SOURCE_TYPE_OPTIONS.map((option) => (
689
+ <Select.Option key={option.value} value={option.value}>
690
+ {option.label}
691
+ </Select.Option>
692
+ ))}
693
+ </Select>
694
+ </Col>
695
+ {showDatePicker && (
696
+ <Col span={6}>
697
+ <RangePicker
698
+ value={dateRange}
699
+ onChange={setDateRange}
700
+ style={{ width: '100%' }}
701
+ />
702
+ </Col>
703
+ )}
704
+ </Row>
705
+ <Row gutter={[16, 16]} style={{ marginTop: 16 }}>
706
+ <Col>
707
+ <Space>
708
+ <Button type="primary" onClick={handleSearch}>
709
+ 查询
710
+ </Button>
711
+ <Button onClick={handleReset}>重置</Button>
712
+ </Space>
713
+ </Col>
714
+ </Row>
715
+ </div>
716
+ )}
717
+
718
+ {showBatchOperations && (
719
+ <div className="batch-operation-section">
720
+ <Space>
721
+ <Select
722
+ placeholder="批量操作"
723
+ value={batchOperation}
724
+ onChange={setBatchOperation}
725
+ style={{ width: 150 }}
726
+ allowClear
727
+ >
728
+ <Select.Option value="deliver">批量发货</Select.Option>
729
+ <Select.Option value="close">关闭订单</Select.Option>
730
+ <Select.Option value="delete">删除订单</Select.Option>
731
+ </Select>
732
+ <Button onClick={handleBatchOperation}>确定</Button>
733
+ </Space>
734
+ {selectedRowKeys.length > 0 && (
735
+ <span className="selected-info">
736
+ 已选择 <strong>{selectedRowKeys.length}</strong> 项
737
+ </span>
738
+ )}
739
+ </div>
740
+ )}
741
+
742
+ {showActions && (
743
+ <div className="action-section">
744
+ <Space>
745
+ <Button icon={<ReloadOutlined />} onClick={handleRefresh}>
746
+ 刷新
747
+ </Button>
748
+ {showExport && (
749
+ <Button icon={<ExportOutlined />} onClick={handleExport}>
750
+ 导出
751
+ </Button>
752
+ )}
753
+ </Space>
754
+ </div>
755
+ )}
756
+
757
+ <Table
758
+ columns={columns}
759
+ dataSource={data}
760
+ rowKey="id"
761
+ loading={loading}
762
+ pagination={
763
+ showPagination
764
+ ? {
765
+ current: currentPage,
766
+ pageSize,
767
+ total,
768
+ showSizeChanger: true,
769
+ showQuickJumper: true,
770
+ showTotal: (total) => `共 ${total} 条`,
771
+ onChange: (page, pageSize) => {
772
+ setCurrentPage(page)
773
+ setPageSize(pageSize)
774
+ onPageChange?.(page, pageSize)
775
+ },
776
+ }
777
+ : false
778
+ }
779
+ rowSelection={rowSelection}
780
+ scroll={{ x: 1500 }}
781
+ onRow={(record) => ({
782
+ onClick: () => onRowClick?.(record),
783
+ })}
784
+ />
785
+ </Card>
786
+
787
+ <Modal
788
+ title="订单详情"
789
+ visible={detailVisible}
790
+ onCancel={() => setDetailVisible(false)}
791
+ footer={null}
792
+ width={800}
793
+ >
794
+ {currentOrder && (
795
+ <Descriptions bordered column={2}>
796
+ <Descriptions.Item label="订单编号">
797
+ {currentOrder.orderSn}
798
+ </Descriptions.Item>
799
+ <Descriptions.Item label="用户账号">
800
+ {currentOrder.memberUsername}
801
+ </Descriptions.Item>
802
+ <Descriptions.Item label="订单金额">
803
+ ¥{currentOrder.totalAmount.toFixed(2)}
804
+ </Descriptions.Item>
805
+ <Descriptions.Item label="实付金额">
806
+ ¥{currentOrder.payAmount.toFixed(2)}
807
+ </Descriptions.Item>
808
+ <Descriptions.Item label="运费">
809
+ ¥{currentOrder.freightAmount.toFixed(2)}
810
+ </Descriptions.Item>
811
+ <Descriptions.Item label="优惠金额">
812
+ ¥{currentOrder.discountAmount.toFixed(2)}
813
+ </Descriptions.Item>
814
+ <Descriptions.Item label="支付方式">
815
+ {getPayTypeTag(currentOrder.payType)}
816
+ </Descriptions.Item>
817
+ <Descriptions.Item label="订单状态">
818
+ {getStatusTag(currentOrder.status)}
819
+ </Descriptions.Item>
820
+ <Descriptions.Item label="收货人">
821
+ {currentOrder.receiverName}
822
+ </Descriptions.Item>
823
+ <Descriptions.Item label="收货电话">
824
+ {currentOrder.receiverPhone}
825
+ </Descriptions.Item>
826
+ <Descriptions.Item label="收货地址" span={2}>
827
+ {currentOrder.receiverProvince}
828
+ {currentOrder.receiverCity}
829
+ {currentOrder.receiverRegion}
830
+ {currentOrder.receiverDetailAddress}
831
+ </Descriptions.Item>
832
+ <Descriptions.Item label="下单时间">
833
+ {currentOrder.createTime}
834
+ </Descriptions.Item>
835
+ <Descriptions.Item label="支付时间">
836
+ {currentOrder.paymentTime || '-'}
837
+ </Descriptions.Item>
838
+ <Descriptions.Item label="发货时间">
839
+ {currentOrder.deliveryTime || '-'}
840
+ </Descriptions.Item>
841
+ <Descriptions.Item label="完成时间">
842
+ {currentOrder.receiveTime || '-'}
843
+ </Descriptions.Item>
844
+ <Descriptions.Item label="订单备注" span={2}>
845
+ {currentOrder.note || '-'}
846
+ </Descriptions.Item>
847
+ </Descriptions>
848
+ )}
849
+ </Modal>
850
+
851
+ <Modal
852
+ title="订单发货"
853
+ visible={deliveryVisible}
854
+ onOk={handleDeliverySubmit}
855
+ onCancel={() => setDeliveryVisible(false)}
856
+ >
857
+ <Form layout="vertical">
858
+ <Form.Item label="物流公司" required>
859
+ <Select
860
+ value={deliveryCompany}
861
+ onChange={setDeliveryCompany}
862
+ placeholder="请选择物流公司"
863
+ >
864
+ <Select.Option value="顺丰速运">顺丰速运</Select.Option>
865
+ <Select.Option value="圆通快递">圆通快递</Select.Option>
866
+ <Select.Option value="中通快递">中通快递</Select.Option>
867
+ <Select.Option value="韵达快递">韵达快递</Select.Option>
868
+ <Select.Option value="申通快递">申通快递</Select.Option>
869
+ <Select.Option value="邮政EMS">邮政EMS</Select.Option>
870
+ </Select>
871
+ </Form.Item>
872
+ <Form.Item label="物流单号" required>
873
+ <Input
874
+ value={deliverySn}
875
+ onChange={(e) => setDeliverySn(e.target.value)}
876
+ placeholder="请输入物流单号"
877
+ />
878
+ </Form.Item>
879
+ </Form>
880
+ </Modal>
881
+ </div>
882
+ )
883
+ }
884
+
885
+ export default OrderList