@appthen/cli 1.2.11 → 1.2.12

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 (59) hide show
  1. package/bin/main.js +47 -0
  2. package/dist/index.js +6165 -14980
  3. package/package.json +8 -1
  4. package/tests/test-app/.appthen/shadow-space-100001-test-app-e99876b1.json +1197 -741
  5. package/tests/test-app/.appthen/space-config.json +2 -2
  6. package/tests/test-app/src/components/MessageCenter.tsx +506 -0
  7. package/tests/test-app/src/pages/CustomerManagement.tsx +535 -0
  8. package/tests/test-app/src/pages/CyberpunkDashboard.tsx +348 -0
  9. package/tests/test-app/src/pages/CyberpunkProductManagement.tsx +637 -0
  10. package/tests/test-app/src/pages/CyberpunkUserList.tsx +316 -0
  11. package/tests/test-app/src/pages/DashboardV2.tsx +334 -0
  12. package/tests/test-app/src/pages/DataReport.tsx +298 -0
  13. package/tests/test-app/src/pages/DataStatistics.tsx +317 -0
  14. package/tests/test-app/src/pages/DepartmentManagement.tsx +503 -0
  15. package/tests/test-app/src/pages/FileExplorer.tsx +441 -0
  16. package/tests/test-app/src/pages/OrderDetail.tsx +393 -0
  17. package/tests/test-app/src/pages/ProductManagement.tsx +521 -0
  18. package/tests/test-app/src/pages/ProjectTimeline.tsx +395 -0
  19. package/tests/test-app/src/pages/RoleManagement.tsx +523 -0
  20. package/tests/test-app/src/pages/StaticCyberpunkDashboard.tsx +462 -0
  21. package/tests/test-app/src/pages/StaticCyberpunkUserList.tsx +567 -0
  22. package/tests/test-app/src/pages/StudentWeaknessList.tsx +547 -0
  23. package/tests/test-app/src/pages/SystemSettings.tsx +422 -0
  24. package/tests/test-app/src/pages/TaskManagement.tsx +467 -0
  25. package/tests/test-app/src/pages/TicketManagement.tsx +402 -0
  26. package/tests/test-app/src/pages/UserProfile.tsx +404 -0
  27. package/tests/test-app/src/pages/WorkflowDesigner.tsx +434 -0
  28. package/tests/test-app/src/pages/admin/dashboard.tsx +591 -0
  29. package/tests/test-app/src/pages/article-list.tsx +222 -0
  30. package/tests/test-app/src/pages/babyProductRecommendationPage.tsx +168 -0
  31. package/tests/test-app/src/pages/category-list.tsx +179 -0
  32. package/tests/test-app/src/pages/comment-list.tsx +194 -0
  33. package/tests/test-app/src/pages/cyberpunk/cyberpunkCRMPage.tsx +1299 -0
  34. package/tests/test-app/src/pages/data-analytics.tsx +1872 -0
  35. package/tests/test-app/src/pages/data-overview.tsx +600 -0
  36. package/tests/test-app/src/pages/demo-error-page.tsx +119 -0
  37. package/tests/test-app/src/pages/department-list.tsx +183 -0
  38. package/tests/test-app/src/pages/goods-list.tsx +233 -0
  39. package/tests/test-app/src/pages/housekeeping/adminDashboardPage.tsx +880 -0
  40. package/tests/test-app/src/pages/mobile_terminal/uiHandsOnPractice.tsx +1 -1
  41. package/tests/test-app/src/pages/notice-list.tsx +217 -0
  42. package/tests/test-app/src/pages/order-detail.tsx +330 -0
  43. package/tests/test-app/src/pages/order-list.tsx +195 -0
  44. package/tests/test-app/src/pages/order-management.tsx +563 -0
  45. package/tests/test-app/src/pages/page/OrderList.tsx +230 -0
  46. package/tests/test-app/src/pages/role-list.tsx +184 -0
  47. package/tests/test-app/src/pages/simple/simplePage.tsx +92 -0
  48. package/tests/test-app/src/pages/simple-page.tsx +43 -0
  49. package/tests/test-app/src/pages/test-destructure.tsx +44 -0
  50. package/tests/test-app/src/pages/test-error-page.tsx +75 -0
  51. package/tests/test-app/src/pages/test-page-with-errors.tsx +51 -0
  52. package/tests/test-app/src/pages/test-page.tsx +101 -0
  53. package/tests/test-app/src/pages/test-render.tsx +52 -0
  54. package/tests/test-app/src/pages/test-return-type.tsx +41 -0
  55. package/tests/test-app/src/pages/test-type-assertion.tsx +37 -0
  56. package/tests/test-app/src/pages/ui/styleSelectorPage.tsx +1554 -0
  57. package/tests/test-app/src/pages/user-list.tsx +212 -0
  58. package/tests/test-app/src/pages/wrong-page.tsx +50 -0
  59. package/tests/test-app/.appthen/shadow-space-unknown-user-test-app-e99876b1.json +0 -1060
@@ -0,0 +1,880 @@
1
+ /**
2
+ * 家政管理后台
3
+ * @type Page
4
+ * @route /housekeeping/admin
5
+ * @screen 1400x900 #f5f5f5
6
+ * @frames web
7
+ */
8
+ import React from 'react';
9
+ import { Button, Form, Input, Menu, Modal, Select, Space, Table, Tag } from '@appthen/antd';
10
+
11
+
12
+ class IProps {
13
+ /* 页面标题 */
14
+ title?: string;
15
+ }
16
+
17
+ /*
18
+ * 数据与接口请求定义
19
+ */
20
+ class IState {
21
+ /* 当前激活的标签页 */
22
+ activeTab?: string;
23
+ /* 服务人员列表 */
24
+ staff?: {
25
+ /* @example 1 */id?: number,
26
+ /* @example 张阿姨 */name?: string,
27
+ /* @example 138****1234 */phone?: string,
28
+ /* @example 保洁、做饭 */skill?: string,
29
+ /* @example 4.8 */rating?: number,
30
+ /* @example 156 */orders?: number,
31
+ /* @example available */status?: string,
32
+ }[];
33
+ /* 订单列表 */
34
+ orders?: {
35
+ /* @example 1001 */id?: number,
36
+ /* @example 陈先生 */customer?: string,
37
+ /* @example 家庭保洁 */service?: string,
38
+ /* @example 张阿姨 */staff?: string,
39
+ /* @example 2025-01-15 */date?: string,
40
+ /* @example 200 */amount?: number,
41
+ /* @example completed */status?: string,
42
+ }[];
43
+ /* 统计数据 */
44
+ stats?: {
45
+ /* @example 128 */totalStaff?: number,
46
+ /* @example 2456 */totalOrders?: number,
47
+ /* @example 42 */todayOrders?: number,
48
+ /* @example 386500 */revenue?: number,
49
+ };
50
+ /* 搜索关键词 */
51
+ searchKeyword?: string;
52
+ /* 模态框显示状态 */
53
+ modalVisible?: boolean;
54
+ /* 当前编辑项 */
55
+ currentItem?: any;
56
+ /* 模态框类型 */
57
+ modalType?: string;
58
+ }
59
+
60
+ class Document extends React.Component<IProps, IState> {
61
+ state = {
62
+ activeTab: 'overview',
63
+ staff: [
64
+ {
65
+ id: 1,
66
+ name: '张阿姨',
67
+ phone: '138****1234',
68
+ skill: '保洁、做饭',
69
+ rating: 4.8,
70
+ orders: 156,
71
+ status: 'available',
72
+ },
73
+ {
74
+ id: 2,
75
+ name: '李阿姨',
76
+ phone: '139****5678',
77
+ skill: '保洁、收纳',
78
+ rating: 4.9,
79
+ orders: 203,
80
+ status: 'busy',
81
+ },
82
+ {
83
+ id: 3,
84
+ name: '王阿姨',
85
+ phone: '137****9012',
86
+ skill: '做饭、月嫂',
87
+ rating: 4.7,
88
+ orders: 89,
89
+ status: 'available',
90
+ },
91
+ {
92
+ id: 4,
93
+ name: '赵阿姨',
94
+ phone: '136****3456',
95
+ skill: '保洁、护工',
96
+ rating: 4.6,
97
+ orders: 124,
98
+ status: 'off',
99
+ },
100
+ {
101
+ id: 5,
102
+ name: '孙阿姨',
103
+ phone: '135****7890',
104
+ skill: '做饭、保洁',
105
+ rating: 4.8,
106
+ orders: 178,
107
+ status: 'available',
108
+ },
109
+ ],
110
+ orders: [
111
+ {
112
+ id: 1001,
113
+ customer: '陈先生',
114
+ service: '家庭保洁',
115
+ staff: '张阿姨',
116
+ date: '2025-01-15',
117
+ amount: 200,
118
+ status: 'completed',
119
+ },
120
+ {
121
+ id: 1002,
122
+ customer: '林女士',
123
+ service: '月嫂服务',
124
+ staff: '王阿姨',
125
+ date: '2025-01-15',
126
+ amount: 8000,
127
+ status: 'ongoing',
128
+ },
129
+ {
130
+ id: 1003,
131
+ customer: '周先生',
132
+ service: '做饭服务',
133
+ staff: '孙阿姨',
134
+ date: '2025-01-16',
135
+ amount: 150,
136
+ status: 'pending',
137
+ },
138
+ {
139
+ id: 1004,
140
+ customer: '吴女士',
141
+ service: '收纳整理',
142
+ staff: '李阿姨',
143
+ date: '2025-01-16',
144
+ amount: 300,
145
+ status: 'confirmed',
146
+ },
147
+ {
148
+ id: 1005,
149
+ customer: '郑先生',
150
+ service: '老人陪护',
151
+ staff: '赵阿姨',
152
+ date: '2025-01-17',
153
+ amount: 400,
154
+ status: 'pending',
155
+ },
156
+ ],
157
+ stats: {
158
+ totalStaff: 128,
159
+ totalOrders: 2456,
160
+ todayOrders: 42,
161
+ revenue: 386500,
162
+ },
163
+ searchKeyword: '',
164
+ modalVisible: false,
165
+ currentItem: null,
166
+ modalType: '',
167
+ };
168
+
169
+ handleTabChange(tab) {
170
+ this.setState({
171
+ activeTab: tab,
172
+ });
173
+ }
174
+
175
+ handleSearch(keyword) {
176
+ this.setState({
177
+ searchKeyword: keyword,
178
+ });
179
+ }
180
+
181
+ handleAddStaff() {
182
+ this.setState({
183
+ modalVisible: true,
184
+ modalType: 'staff',
185
+ currentItem: null,
186
+ });
187
+ }
188
+
189
+ handleEditStaff(item) {
190
+ this.setState({
191
+ modalVisible: true,
192
+ modalType: 'staff',
193
+ currentItem: item,
194
+ });
195
+ }
196
+
197
+ handleDeleteStaff(item) {
198
+ this.utils.confirm('确认删除该服务人员吗?', () => {
199
+ const staff = this.state.staff.filter(s => s.id !== item.id);
200
+ this.setState({
201
+ staff,
202
+ });
203
+ this.utils.toast('删除成功');
204
+ });
205
+ }
206
+
207
+ handleUpdateOrderStatus(order, status) {
208
+ const orders = this.state.orders.map(o =>
209
+ o.id === order.id
210
+ ? {
211
+ ...o,
212
+ status,
213
+ }
214
+ : o
215
+ );
216
+ this.setState({
217
+ orders,
218
+ });
219
+ this.utils.toast('状态更新成功');
220
+ }
221
+
222
+ handleModalClose() {
223
+ this.setState({
224
+ modalVisible: false,
225
+ });
226
+ }
227
+
228
+ handleSubmit(values) {
229
+ if (this.state.modalType === 'staff') {
230
+ if (this.state.currentItem) {
231
+ const staff = this.state.staff.map(item =>
232
+ item.id === this.state.currentItem.id
233
+ ? {
234
+ ...item,
235
+ ...values,
236
+ }
237
+ : item
238
+ );
239
+ this.setState({
240
+ staff,
241
+ });
242
+ } else {
243
+ const staff = [
244
+ ...this.state.staff,
245
+ {
246
+ id: Date.now(),
247
+ ...values,
248
+ orders: 0,
249
+ rating: 0,
250
+ status: 'available',
251
+ },
252
+ ];
253
+ this.setState({
254
+ staff,
255
+ });
256
+ }
257
+ }
258
+ this.setState({
259
+ modalVisible: false,
260
+ });
261
+ this.utils.toast('保存成功');
262
+ }
263
+
264
+ getFilteredStaff() {
265
+ const keyword = this.state.searchKeyword?.toLowerCase();
266
+ if (!keyword) return this.state.staff;
267
+ return this.state.staff.filter(
268
+ s =>
269
+ s.name?.toLowerCase().includes(keyword) ||
270
+ s.phone?.includes(keyword) ||
271
+ s.skill?.toLowerCase().includes(keyword)
272
+ );
273
+ }
274
+
275
+ getFilteredOrders() {
276
+ const keyword = this.state.searchKeyword?.toLowerCase();
277
+ if (!keyword) return this.state.orders;
278
+ return this.state.orders.filter(
279
+ o =>
280
+ o.customer?.toLowerCase().includes(keyword) ||
281
+ o.service?.toLowerCase().includes(keyword) ||
282
+ o.staff?.toLowerCase().includes(keyword)
283
+ );
284
+ }
285
+
286
+ render() {
287
+ return (
288
+ <Page className="min-h-screen bg-[#f3f4f6] flex">
289
+ <View className="bg-gradient-to-b from-indigo-900 to-indigo-800 w-[288px] shadow-[0 25px 50px -12px rgb(0 0 0 / 0.25)]">
290
+ <View className="border-indigo-700 p-[32px] border-b-[1px] border-b-solid">
291
+ <View className="space-x-3 flex items-center">
292
+ <View className="w-[40px] h-[40px] bg-[#ffffff] rounded-xl flex items-center justify-center shadow-[0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)]">
293
+ <Text className="text-2xl">🏠</Text>
294
+ </View>
295
+ <h1 className="text-xl font-bold text-[#ffffff] tracking-[0.025em]">
296
+ 家政管家
297
+ </h1>
298
+ </View>
299
+ </View>
300
+ <nav className="p-[24px]">
301
+ <Menu
302
+ selectedKeys={[this.state.activeTab]}
303
+ mode="inline"
304
+ theme="dark"
305
+ className="border-none bg-[var(--transparent)]"
306
+ items={[
307
+ {
308
+ key: 'overview',
309
+ icon: <Text>📊</Text>,
310
+ label: <Text>数据概览</Text>,
311
+ onClick: function () {
312
+ return this.handleTabChange('overview');
313
+ },
314
+ },
315
+ {
316
+ key: 'staff',
317
+ icon: <Text>👥</Text>,
318
+ label: <Text>服务人员</Text>,
319
+ onClick: function () {
320
+ return this.handleTabChange('staff');
321
+ },
322
+ },
323
+ {
324
+ key: 'orders',
325
+ icon: <Text>📋</Text>,
326
+ label: <Text>订单管理</Text>,
327
+ onClick: function () {
328
+ return this.handleTabChange('orders');
329
+ },
330
+ },
331
+ ]}
332
+ />
333
+ </nav>
334
+ </View>
335
+ <View className="flex-1 p-[32px]">
336
+ {!!(this.state.activeTab === 'overview') && (
337
+ <View>
338
+ <h2 className="text-2xl font-bold text-[#1f2937] mb-[24px]">
339
+ 数据概览
340
+ </h2>
341
+ <View className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-[32px]">
342
+ <View className="transform hover:scale-105 transition-all duration-300 bg-gradient-to-br from-blue-500 to-blue-600 rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] p-[24px]">
343
+ <View className="flex items-center justify-between">
344
+ <View>
345
+ <p className="text-[var(--blue-100)] text-sm font-medium">
346
+ 服务人员总数
347
+ </p>
348
+ <p className="text-4xl font-bold text-[#ffffff] mt-[8px]">
349
+ <Text>{this.state.stats?.totalStaff}</Text>
350
+ </p>
351
+ <p className="text-[var(--blue-200)] text-xs mt-[8px]">
352
+ ↑ 12% 较上月
353
+ </p>
354
+ </View>
355
+ <View className="bg-white/20 backdrop-blur w-[64px] h-[64px] rounded-2xl flex items-center justify-center">
356
+ <Text className="text-3xl">👥</Text>
357
+ </View>
358
+ </View>
359
+ </View>
360
+ <View className="transform hover:scale-105 transition-all duration-300 bg-gradient-to-br from-[var(--emerald-500)] to-[var(--emerald-600)] rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] p-[24px]">
361
+ <View className="flex items-center justify-between">
362
+ <View>
363
+ <p className="text-[var(--emerald-100)] text-sm font-medium">
364
+ 订单总数
365
+ </p>
366
+ <p className="text-4xl font-bold text-[#ffffff] mt-[8px]">
367
+ <Text>{this.state.stats?.totalOrders}</Text>
368
+ </p>
369
+ <p className="text-[var(--emerald-200)] text-xs mt-[8px]">
370
+ ↑ 8% 较上月
371
+ </p>
372
+ </View>
373
+ <View className="bg-white/20 backdrop-blur w-[64px] h-[64px] rounded-2xl flex items-center justify-center">
374
+ <Text className="text-3xl">📋</Text>
375
+ </View>
376
+ </View>
377
+ </View>
378
+ <View className="transform hover:scale-105 transition-all duration-300 bg-gradient-to-br from-[var(--amber-500)] to-[#f97316] rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] p-[24px]">
379
+ <View className="flex items-center justify-between">
380
+ <View>
381
+ <p className="text-[var(--amber-100)] text-sm font-medium">
382
+ 今日订单
383
+ </p>
384
+ <p className="text-4xl font-bold text-[#ffffff] mt-[8px]">
385
+ <Text>{this.state.stats?.todayOrders}</Text>
386
+ </p>
387
+ <p className="text-[var(--amber-200)] text-xs mt-[8px]">
388
+ ↑ 5% 较昨日
389
+ </p>
390
+ </View>
391
+ <View className="bg-white/20 backdrop-blur w-[64px] h-[64px] rounded-2xl flex items-center justify-center">
392
+ <Text className="text-3xl">📅</Text>
393
+ </View>
394
+ </View>
395
+ </View>
396
+ <View className="transform hover:scale-105 transition-all duration-300 bg-gradient-to-br from-purple-500 to-purple-600 rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] p-[24px]">
397
+ <View className="flex items-center justify-between">
398
+ <View>
399
+ <p className="text-[var(--purple-100)] text-sm font-medium">
400
+ 总收入
401
+ </p>
402
+ <p className="text-4xl font-bold text-[#ffffff] mt-[8px]">
403
+ <Text>
404
+ ¥{this.state.stats?.revenue?.toLocaleString()}
405
+ </Text>
406
+ </p>
407
+ <p className="text-[var(--purple-200)] text-xs mt-[8px]">
408
+ ↑ 15% 较上月
409
+ </p>
410
+ </View>
411
+ <View className="bg-white/20 backdrop-blur w-[64px] h-[64px] rounded-2xl flex items-center justify-center">
412
+ <Text className="text-3xl">💰</Text>
413
+ </View>
414
+ </View>
415
+ </View>
416
+ </View>
417
+ <View className="bg-[#ffffff] rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] overflow-hidden">
418
+ <View className="border-gray-100 bg-gradient-to-r from-[#f9fafb] to-white p-[24px] border-b-[1px] border-b-solid">
419
+ <h3 className="text-lg font-bold text-[#1f2937]">最近订单</h3>
420
+ </View>
421
+ <Table
422
+ dataSource={this.state.orders?.slice(0, 5)}
423
+ rowKey="id"
424
+ pagination={false}
425
+ columns={[
426
+ {
427
+ title: <Text>订单号</Text>,
428
+ dataIndex: 'id',
429
+ key: 'id',
430
+ render: id => (
431
+ <Text className="font-bold text-[var(--indigo-600)]">
432
+ #{id}
433
+ </Text>
434
+ ),
435
+ },
436
+ {
437
+ title: <Text>客户</Text>,
438
+ dataIndex: 'customer',
439
+ key: 'customer',
440
+ },
441
+ {
442
+ title: <Text>服务类型</Text>,
443
+ dataIndex: 'service',
444
+ key: 'service',
445
+ render: service => (
446
+ <Tag color="blue">
447
+ <Text>{service}</Text>
448
+ </Tag>
449
+ ),
450
+ },
451
+ {
452
+ title: <Text>服务人员</Text>,
453
+ dataIndex: 'staff',
454
+ key: 'staff',
455
+ },
456
+ {
457
+ title: <Text>金额</Text>,
458
+ dataIndex: 'amount',
459
+ key: 'amount',
460
+ render: amount => (
461
+ <Text className="font-bold">¥{amount}</Text>
462
+ ),
463
+ },
464
+ {
465
+ title: <Text>状态</Text>,
466
+ dataIndex: 'status',
467
+ key: 'status',
468
+ render: status =>
469
+ (() => {
470
+ const statusConfig = {
471
+ completed: {
472
+ color: 'success',
473
+ text: '已完成',
474
+ },
475
+ ongoing: {
476
+ color: 'processing',
477
+ text: '进行中',
478
+ },
479
+ confirmed: {
480
+ color: 'warning',
481
+ text: '已确认',
482
+ },
483
+ pending: {
484
+ color: 'default',
485
+ text: '待处理',
486
+ },
487
+ };
488
+ const config =
489
+ statusConfig[status] || statusConfig.pending;
490
+ return (
491
+ <Tag color={config.color}>
492
+ <Text>{config.text}</Text>
493
+ </Tag>
494
+ );
495
+ })(),
496
+ },
497
+ ]}
498
+ />
499
+ </View>
500
+ </View>
501
+ )}
502
+ {!!(this.state.activeTab === 'staff') && (
503
+ <View>
504
+ <View className="flex items-center justify-between mb-[32px]">
505
+ <h2 className="text-2xl font-bold text-[#1f2937]">
506
+ 服务人员管理
507
+ </h2>
508
+ <Button
509
+ type="primary"
510
+ size="large"
511
+ onClick={() => this.handleAddStaff()}
512
+ className="border-none hover:from-indigo-600 hover:to-indigo-700 bg-gradient-to-r from-indigo-500 to-indigo-600"
513
+ >
514
+ <Text>➕ 新增服务人员</Text>
515
+ </Button>
516
+ </View>
517
+ <View className="mb-[24px]">
518
+ <Input
519
+ placeholder="搜索姓名、电话或技能..."
520
+ prefix={<Text>🔍</Text>}
521
+ value={this.state.searchKeyword}
522
+ onChange={e => this.handleSearch(e.target.value)}
523
+ size="large"
524
+ allowClear={true}
525
+ className=""
526
+ />
527
+ </View>
528
+ <View className="bg-[#ffffff] rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] overflow-hidden">
529
+ <Table
530
+ dataSource={this.getFilteredStaff()}
531
+ rowKey="id"
532
+ pagination={{ pageSize: 10 }}
533
+ columns={[
534
+ {
535
+ title: <Text>姓名</Text>,
536
+ dataIndex: 'name',
537
+ key: 'name',
538
+ render: name => (
539
+ <Space>
540
+ <View className="bg-gradient-to-br from-indigo-400 to-indigo-500 w-[40px] h-[40px] rounded-full flex items-center justify-center text-[#ffffff] font-bold text-sm">
541
+ <Text>{name?.charAt(0)}</Text>
542
+ </View>
543
+ <Text className="font-bold">{name}</Text>
544
+ </Space>
545
+ ),
546
+ },
547
+ {
548
+ title: <Text>电话</Text>,
549
+ dataIndex: 'phone',
550
+ key: 'phone',
551
+ },
552
+ {
553
+ title: <Text>技能</Text>,
554
+ dataIndex: 'skill',
555
+ key: 'skill',
556
+ render: skill => (
557
+ <Tag color="indigo">
558
+ <Text>{skill}</Text>
559
+ </Tag>
560
+ ),
561
+ },
562
+ {
563
+ title: <Text>评分</Text>,
564
+ dataIndex: 'rating',
565
+ key: 'rating',
566
+ render: rating => (
567
+ <Space>
568
+ <Text>⭐</Text>
569
+ <Text className="font-bold">{rating}</Text>
570
+ </Space>
571
+ ),
572
+ },
573
+ {
574
+ title: <Text>订单数</Text>,
575
+ dataIndex: 'orders',
576
+ key: 'orders',
577
+ },
578
+ {
579
+ title: <Text>状态</Text>,
580
+ dataIndex: 'status',
581
+ key: 'status',
582
+ render: status =>
583
+ (() => {
584
+ const statusConfig = {
585
+ available: {
586
+ color: 'success',
587
+ text: '空闲',
588
+ },
589
+ busy: {
590
+ color: 'error',
591
+ text: '忙碌',
592
+ },
593
+ off: {
594
+ color: 'default',
595
+ text: '休息',
596
+ },
597
+ };
598
+ const config =
599
+ statusConfig[status] || statusConfig.off;
600
+ return (
601
+ <Tag color={config.color}>
602
+ <Text>{config.text}</Text>
603
+ </Tag>
604
+ );
605
+ })(),
606
+ },
607
+ {
608
+ title: <Text>操作</Text>,
609
+ key: 'action',
610
+ render: (_, record) => (
611
+ <Space>
612
+ <Button
613
+ type="link"
614
+ size="small"
615
+ onClick={() => this.handleEditStaff(record)}
616
+ >
617
+ <Text>✏️ 编辑</Text>
618
+ </Button>
619
+ <Button
620
+ type="link"
621
+ danger={true}
622
+ size="small"
623
+ onClick={() => this.handleDeleteStaff(record)}
624
+ >
625
+ <Text>🗑️ 删除</Text>
626
+ </Button>
627
+ </Space>
628
+ ),
629
+ },
630
+ ]}
631
+ />
632
+ </View>
633
+ </View>
634
+ )}
635
+ {!!(this.state.activeTab === 'orders') && (
636
+ <View>
637
+ <h2 className="text-2xl font-bold text-[#1f2937] mb-[32px]">
638
+ 订单管理
639
+ </h2>
640
+ <View className="mb-[24px]">
641
+ <Input
642
+ placeholder="搜索客户、服务类型或服务人员..."
643
+ prefix={<Text>🔍</Text>}
644
+ value={this.state.searchKeyword}
645
+ onChange={e => this.handleSearch(e.target.value)}
646
+ size="large"
647
+ allowClear={true}
648
+ className=""
649
+ />
650
+ </View>
651
+ <View className="bg-[#ffffff] rounded-2xl shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] overflow-hidden">
652
+ <Table
653
+ dataSource={this.getFilteredOrders()}
654
+ rowKey="id"
655
+ pagination={{ pageSize: 10 }}
656
+ columns={[
657
+ {
658
+ title: <Text>订单号</Text>,
659
+ dataIndex: 'id',
660
+ key: 'id',
661
+ render: id => (
662
+ <Text className="font-bold text-[var(--indigo-600)]">
663
+ #{id}
664
+ </Text>
665
+ ),
666
+ },
667
+ {
668
+ title: <Text>客户</Text>,
669
+ dataIndex: 'customer',
670
+ key: 'customer',
671
+ render: customer => (
672
+ <Space>
673
+ <View className="bg-gradient-to-br from-[var(--amber-400)] to-[#f97316] w-[32px] h-[32px] rounded-full flex items-center justify-center text-[#ffffff] font-bold text-xs">
674
+ <Text>{customer?.charAt(0)}</Text>
675
+ </View>
676
+ <Text className="font-medium">{customer}</Text>
677
+ </Space>
678
+ ),
679
+ },
680
+ {
681
+ title: <Text>服务类型</Text>,
682
+ dataIndex: 'service',
683
+ key: 'service',
684
+ render: service => (
685
+ <Tag color="blue">
686
+ <Text>{service}</Text>
687
+ </Tag>
688
+ ),
689
+ },
690
+ {
691
+ title: <Text>服务人员</Text>,
692
+ dataIndex: 'staff',
693
+ key: 'staff',
694
+ },
695
+ {
696
+ title: <Text>日期</Text>,
697
+ dataIndex: 'date',
698
+ key: 'date',
699
+ },
700
+ {
701
+ title: <Text>金额</Text>,
702
+ dataIndex: 'amount',
703
+ key: 'amount',
704
+ render: amount => (
705
+ <Text className="font-bold">¥{amount}</Text>
706
+ ),
707
+ },
708
+ {
709
+ title: <Text>状态</Text>,
710
+ dataIndex: 'status',
711
+ key: 'status',
712
+ render: status =>
713
+ (() => {
714
+ const statusConfig = {
715
+ completed: {
716
+ color: 'success',
717
+ text: '已完成',
718
+ },
719
+ ongoing: {
720
+ color: 'processing',
721
+ text: '进行中',
722
+ },
723
+ confirmed: {
724
+ color: 'warning',
725
+ text: '已确认',
726
+ },
727
+ pending: {
728
+ color: 'default',
729
+ text: '待处理',
730
+ },
731
+ };
732
+ const config =
733
+ statusConfig[status] || statusConfig.pending;
734
+ return (
735
+ <Tag color={config.color}>
736
+ <Text>{config.text}</Text>
737
+ </Tag>
738
+ );
739
+ })(),
740
+ },
741
+ {
742
+ title: <Text>操作</Text>,
743
+ key: 'action',
744
+ render: (_, record) => (
745
+ <Space>
746
+ {!!(record.status === 'pending') && (
747
+ <Button
748
+ type="link"
749
+ size="small"
750
+ onClick={() =>
751
+ this.handleUpdateOrderStatus(
752
+ record,
753
+ 'confirmed'
754
+ )
755
+ }
756
+ >
757
+ <Text>✓ 确认</Text>
758
+ </Button>
759
+ )}
760
+ {!!(record.status === 'confirmed') && (
761
+ <Button
762
+ type="link"
763
+ size="small"
764
+ onClick={() =>
765
+ this.handleUpdateOrderStatus(record, 'ongoing')
766
+ }
767
+ >
768
+ <Text>▶ 开始</Text>
769
+ </Button>
770
+ )}
771
+ {!!(record.status === 'ongoing') && (
772
+ <Button
773
+ type="link"
774
+ size="small"
775
+ onClick={() =>
776
+ this.handleUpdateOrderStatus(
777
+ record,
778
+ 'completed'
779
+ )
780
+ }
781
+ >
782
+ <Text>✓ 完成</Text>
783
+ </Button>
784
+ )}
785
+ </Space>
786
+ ),
787
+ },
788
+ ]}
789
+ />
790
+ </View>
791
+ </View>
792
+ )}
793
+ </View>
794
+ {!!this.state.modalVisible && (
795
+ <View className="inset-0 fixed bg-[var(--opacity-50)] flex items-center justify-center z-50">
796
+ <View className="bg-[#ffffff] rounded-lg shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)] w-full p-[24px]">
797
+ <h2 className="text-xl font-bold mb-[16px]">
798
+ <Text>{this.state.currentItem ? '编辑' : '新增'}服务人员</Text>
799
+ </h2>
800
+ <form
801
+ onSubmit={e => {
802
+ e.preventDefault();
803
+ const formData = new FormData(e.target);
804
+ const values = Object.fromEntries(formData);
805
+ this.handleSubmit(values);
806
+ }}
807
+ >
808
+ <View className="mb-[16px]">
809
+ <label className="block text-sm font-medium text-[#374151] mb-[8px]">
810
+ <Text>姓名</Text>
811
+ </label>
812
+ <input
813
+ name="name"
814
+ defaultValue={this.state.currentItem?.name}
815
+ className="border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
816
+ required={true}
817
+ />
818
+ </View>
819
+ <View className="mb-[16px]">
820
+ <label className="block text-sm font-medium text-[#374151] mb-[8px]">
821
+ <Text>电话</Text>
822
+ </label>
823
+ <input
824
+ name="phone"
825
+ defaultValue={this.state.currentItem?.phone}
826
+ className="border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
827
+ required={true}
828
+ />
829
+ </View>
830
+ <View className="mb-[16px]">
831
+ <label className="block text-sm font-medium text-[#374151] mb-[8px]">
832
+ <Text>技能</Text>
833
+ </label>
834
+ <input
835
+ name="skill"
836
+ defaultValue={this.state.currentItem?.skill}
837
+ placeholder="例如:保洁、做饭、收纳"
838
+ className="border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
839
+ required={true}
840
+ />
841
+ </View>
842
+ <View className="mb-[16px]">
843
+ <label className="block text-sm font-medium text-[#374151] mb-[8px]">
844
+ <Text>状态</Text>
845
+ </label>
846
+ <select
847
+ name="status"
848
+ defaultValue={this.state.currentItem?.status || 'available'}
849
+ className="border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
850
+ >
851
+ <option value="available">空闲</option>
852
+ <option value="busy">忙碌</option>
853
+ <option value="off">休息</option>
854
+ </select>
855
+ </View>
856
+ <View className="space-x-3 flex justify-end">
857
+ <button
858
+ type="button"
859
+ onClick={() => this.handleModalClose()}
860
+ className="border-gray-300 hover:bg-gray-50 transition-colors pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
861
+ >
862
+ <Text>取消</Text>
863
+ </button>
864
+ <button
865
+ type="submit"
866
+ className="bg-blue-500 hover:bg-blue-600 transition-colors pl-[16px] pr-[16px] pt-[8px] pb-[8px] text-[#ffffff] rounded-lg"
867
+ >
868
+ <Text>保存</Text>
869
+ </button>
870
+ </View>
871
+ </form>
872
+ </View>
873
+ </View>
874
+ )}
875
+ </Page>
876
+ );
877
+ }
878
+ }
879
+
880
+ export default Document;