@appthen/cli 1.2.8 → 1.2.11

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/.gitignore +1 -0
  2. package/bin/main.js +45 -0
  3. package/dist/index.js +1277 -909
  4. package/package.json +1 -1
  5. package/tests/test-app/.appthen/shadow-space-100001-test-app-e99876b1.json +1406 -0
  6. package/tests/test-app/.appthen/shadow-space-unknown-user-test-app-e99876b1.json +1060 -0
  7. package/tests/test-app/.appthen/space-config.json +8 -0
  8. package/tests/test-app/docs/AI-Workflow.flow +112 -0
  9. package/tests/test-app/docs/Logic-1.flow +16 -0
  10. package/tests/test-app/docs/Logic.flow +16 -0
  11. package/tests/test-app/docs/Project-Blueprint-1.flow +119 -0
  12. package/tests/test-app/docs/Project-Blueprint.flow +119 -0
  13. package/tests/test-app/docs/README.md +3 -0
  14. package/tests/test-app/docs/claude.md +194 -0
  15. package/tests/test-app/docs/page_requirement_analysis.md +149 -0
  16. package/tests/test-app/docs//345/267/245/345/215/225/347/256/241/347/220/206/347/263/273/347/273/237/350/257/246/347/273/206/350/256/276/350/256/241.md +377 -0
  17. package/tests/test-app/src/apis/AddTodoPost.api.ts +42 -0
  18. package/tests/test-app/src/apis/DeleteTodoPost.api.ts +32 -0
  19. package/tests/test-app/src/apis/GetListPost.api.ts +38 -0
  20. package/tests/test-app/src/apis/TicketAttachmentUploadPost.api.ts +42 -0
  21. package/tests/test-app/src/apis/UpdateTodoPost.api.ts +46 -0
  22. package/tests/test-app/src/app.css +15 -0
  23. package/tests/test-app/src/cloud_functions/ticket|attachment|upload.node.ts +86 -0
  24. package/tests/test-app/src/cloud_functions/ticket|comment|add.node.ts +65 -0
  25. package/tests/test-app/src/cloud_functions/types|entity|Ticket.node.ts +88 -0
  26. package/tests/test-app/src/cloud_functions/types|entity|TicketAttachment.node.ts +70 -0
  27. package/tests/test-app/src/cloud_functions/types|entity|TicketCategory.node.ts +56 -0
  28. package/tests/test-app/src/cloud_functions/types|entity|TicketComment.node.ts +62 -0
  29. package/tests/test-app/src/cloud_functions/types|entity|TicketHistory.node.ts +74 -0
  30. package/tests/test-app/src/cloud_functions/types|entity|TicketPriority.node.ts +68 -0
  31. package/tests/test-app/src/cloud_functions/types|entity|TicketStatus.node.ts +63 -0
  32. package/tests/test-app/src/cloud_functions/types|models|CreateTicketParams.node.ts +20 -0
  33. package/tests/test-app/src/cloud_functions/types|models|TicketListParams.node.ts +30 -0
  34. package/tests/test-app/src/cloud_functions/types|models|UpdateTicketParams.node.ts +22 -0
  35. package/tests/test-app/src/components/Button.js +11 -0
  36. package/tests/test-app/src/components/MouduleDemoNzp.tsx +40 -0
  37. package/tests/test-app/src/components/Timeline.tsx +145 -0
  38. package/tests/test-app/src/index.ts +2 -0
  39. package/tests/test-app/src/modules/work_order_module/apis/TicketCommentAddPost.api.ts +48 -0
  40. package/tests/test-app/src/modules/work_order_module/apis/TicketCreatePost.api.ts +52 -0
  41. package/tests/test-app/src/modules/work_order_module/apis/TicketDeleteDelete.api.ts +39 -0
  42. package/tests/test-app/src/modules/work_order_module/apis/TicketDetailGet.api.ts +39 -0
  43. package/tests/test-app/src/modules/work_order_module/apis/TicketListGet.api.ts +61 -0
  44. package/tests/test-app/src/modules/work_order_module/apis/TicketUpdatePut.api.ts +57 -0
  45. package/tests/test-app/src/modules/work_order_module/apis/TrainDoorFaultListGet.ts +76 -0
  46. package/tests/test-app/src/modules/work_order_module/apis/TrainDoorListGet.ts +76 -0
  47. package/tests/test-app/src/modules/work_order_module/apis/TrainDoorOperationRecordsGet.ts +284 -0
  48. package/tests/test-app/src/modules/work_order_module/apis/TrainDoorStatisticsGet.ts +96 -0
  49. package/tests/test-app/src/modules/work_order_module/cloud_function/category|list.node.ts +40 -0
  50. package/tests/test-app/src/modules/work_order_module/cloud_function/priority|list.node.ts +26 -0
  51. package/tests/test-app/src/modules/work_order_module/cloud_function/status|list.node.ts +26 -0
  52. package/tests/test-app/src/modules/work_order_module/cloud_function/ticket|create.node.ts +54 -0
  53. package/tests/test-app/src/modules/work_order_module/cloud_function/ticket|delete.node.ts +55 -0
  54. package/tests/test-app/src/modules/work_order_module/cloud_function/ticket|detail.node.ts +65 -0
  55. package/tests/test-app/src/modules/work_order_module/cloud_function/ticket|list.node.ts +85 -0
  56. package/tests/test-app/src/modules/work_order_module/cloud_function/ticket|update.node.ts +73 -0
  57. package/tests/test-app/src/modules/work_order_module/data_model/Ticket.m.ts +85 -0
  58. package/tests/test-app/src/modules/work_order_module/data_model/TicketCategory.m.ts +53 -0
  59. package/tests/test-app/src/modules/work_order_module/data_model/TicketStatus.m.ts +60 -0
  60. package/tests/test-app/src/modules/work_order_module//345/267/245/345/215/225/347/263/273/347/273/237/344/272/247/345/223/201/350/256/276/350/256/241/346/226/207/346/241/243.md +301 -0
  61. package/tests/test-app/src/modules/work_order_module//345/267/245/345/215/225/347/263/273/347/273/237/345/274/200/345/217/221/344/273/273/345/212/241/345/210/206/345/267/245/346/226/207/346/241/243.md +345 -0
  62. package/tests/test-app/src/pages/SLAManagement.tsx +668 -0
  63. package/tests/test-app/src/pages/TicketCreate.tsx +27 -0
  64. package/tests/test-app/src/pages/TicketDetail.tsx +27 -0
  65. package/tests/test-app/src/pages/TicketList.tsx +27 -0
  66. package/tests/test-app/src/pages/TicketManagementPage.tsx +1238 -0
  67. package/tests/test-app/src/pages/VisualAIIDEUpgrade.tsx +245 -0
  68. package/tests/test-app/src/pages/appthen_guide/ComponentTreeUnderstanding.tsx +26 -0
  69. package/tests/test-app/src/pages/appthen_guide/DataBindingLearning.tsx +26 -0
  70. package/tests/test-app/src/pages/back-end/adminRootLayout.tsx +155 -0
  71. package/tests/test-app/src/pages/back-end/adminRootLayout10.tsx +157 -0
  72. package/tests/test-app/src/pages/back-end/adminRootLayout2.tsx +156 -0
  73. package/tests/test-app/src/pages/back-end/adminRootLayout3.tsx +156 -0
  74. package/tests/test-app/src/pages/back-end/adminRootLayout4.tsx +157 -0
  75. package/tests/test-app/src/pages/back-end/adminRootLayout5.tsx +157 -0
  76. package/tests/test-app/src/pages/back-end/adminRootLayout6.tsx +157 -0
  77. package/tests/test-app/src/pages/back-end/adminRootLayout7.tsx +157 -0
  78. package/tests/test-app/src/pages/back-end/adminRootLayout8.tsx +157 -0
  79. package/tests/test-app/src/pages/back-end/adminRootLayout9.tsx +157 -0
  80. package/tests/test-app/src/pages/back-end/backgroundManagementSystem.css +5 -0
  81. package/tests/test-app/src/pages/back-end/backgroundManagementSystem.tsx +1745 -0
  82. package/tests/test-app/src/pages/component/WorkOrderCard.tsx +140 -0
  83. package/tests/test-app/src/pages/cover.tsx +42 -0
  84. package/tests/test-app/src/pages/data_dashboard/blueBrightGreenTechnologyWind.css +181 -0
  85. package/tests/test-app/src/pages/data_dashboard/blueBrightGreenTechnologyWind.tsx +225 -0
  86. package/tests/test-app/src/pages/data_dashboard/blueLargeScreen.css +181 -0
  87. package/tests/test-app/src/pages/data_dashboard/blueLargeScreen.tsx +138 -0
  88. package/tests/test-app/src/pages/data_dashboard/component_library/BlueBrightGreenBorder.tsx +47 -0
  89. package/tests/test-app/src/pages/data_dashboard/component_library/FullScreenContainer.tsx +133 -0
  90. package/tests/test-app/src/pages/description_of_mock_interface.md +32 -0
  91. package/tests/test-app/src/pages/digitalLargeScreen.css +181 -0
  92. package/tests/test-app/src/pages/digitalLargeScreen.tsx +1417 -0
  93. package/tests/test-app/src/pages/mobile_terminal/PersonalCenter.css +3 -0
  94. package/tests/test-app/src/pages/mobile_terminal/PersonalCenter.tsx +362 -0
  95. package/tests/test-app/src/pages/mobile_terminal/WorkOrderHomepage.tsx +337 -0
  96. package/tests/test-app/src/pages/mobile_terminal/newWorkOrder.tsx +224 -0
  97. package/tests/test-app/src/pages/mobile_terminal/tabbar.tsx +67 -0
  98. package/tests/test-app/src/pages/mobile_terminal/uiHandsOnPractice.tsx +638 -0
  99. package/tests/test-app/src/pages/mobile_terminal/workOrderDetails.tsx +346 -0
  100. package/tests/test-app/src/pages/mobile_terminal/workOrderPage.tsx +345 -0
  101. package/tests/test-app/src/pages/testPage.css +3 -0
  102. package/tests/test-app/src/pages/testPage.tsx +158 -0
  103. package/tests/test-app/src/pages/web_version/website.css +205 -0
  104. package/tests/test-app/src/pages/web_version/website.tsx +1066 -0
  105. package/tests/test-app/src/pages//345/276/205/345/212/236.apidoc.json +336 -0
  106. package/tests/test-app/src/project.json +1120 -0
  107. package/tests/test-app/src/store/global.store.ts +10 -0
  108. package/tests/test-app/src/types/CreateTicketParams.m.ts +20 -0
  109. package/tests/test-app/src/types/SLAPolicy.ts +50 -0
  110. package/tests/test-app/src/types/Ticket.ts +68 -0
  111. package/tests/test-app/src/types/TicketAttachment.m.ts +67 -0
  112. package/tests/test-app/src/types/TicketComment.m.ts +59 -0
  113. package/tests/test-app/src/types/TicketEvaluation.ts +44 -0
  114. package/tests/test-app/src/types/TicketHistory.m.ts +71 -0
  115. package/tests/test-app/src/types/TicketListParams.m.ts +30 -0
  116. package/tests/test-app/src/types/TicketPriority.m.ts +65 -0
  117. package/tests/test-app/src/types/TicketRecord.ts +47 -0
  118. package/tests/test-app/src/types/TrainDoor.ts +284 -0
  119. package/tests/test-app/src/types/UpdateTicketParams.m.ts +22 -0
  120. package/tests/test-app/src/utils/__afterRequest.util.ts +3 -0
  121. package/tests/test-app/src/utils/__beforeRequest.util.ts +10 -0
  122. package/tests/test-app/src/utils/testGlobalAction.util.ts +7 -0
@@ -0,0 +1,1238 @@
1
+ /**
2
+ * 工单管理页面 - 复杂表格界面
3
+ * @type Page
4
+ * @route /ticket-management
5
+ * @screen 1920x1080 #f5f5f5
6
+ * @frames web
7
+ */
8
+ import React from 'react';
9
+ import { Page, Text, View } from '@appthen/react';
10
+ import XMarkdown from '@ant-design/x-markdown';
11
+
12
+
13
+ class IProps {
14
+ /* 部门ID - 可选的路由参数 */
15
+ departmentId: string;
16
+ }
17
+
18
+ /*
19
+ * 数据与接口请求定义
20
+ */
21
+ class IState {
22
+ /* 表格加载状态 */
23
+ loading: boolean;
24
+ /* 选中的工单 */
25
+ @Form({
26
+ setter: "JsonSetter"
27
+ })
28
+ selectedRowKeys: string[];
29
+ /* 搜索关键词 */
30
+ searchKeyword: string;
31
+ /* 筛选条件 */
32
+ filters: {
33
+ status: string,
34
+ priority: string,
35
+ department: string,
36
+ assignee: string,
37
+ dateRange: string,
38
+ };
39
+ /* 排序信息 */
40
+ sorter: {
41
+ field: string,
42
+ order: string,
43
+ };
44
+ /* 分页信息 */
45
+ pagination: {
46
+ current: number,
47
+ pageSize: number,
48
+ total: number,
49
+ };
50
+ /* 表格列配置 */
51
+ columns: {
52
+ /* @example 工单编号 */title?: string,
53
+ /* @example id */dataIndex?: string,
54
+ /* @example id */key?: string,
55
+ /* @example 120 */width?: number,
56
+ /* @example left */fixed: string,
57
+ /* @example true */sorter: boolean,
58
+ /* @example true */filterable: boolean,
59
+ /* @example true */ellipsis: boolean,
60
+ filters: string,
61
+ }[];
62
+ /* 高级搜索展开状态 */
63
+ advancedSearchExpanded: boolean;
64
+ /* 统计数据 */
65
+ statistics: {
66
+ total: number,
67
+ pending: number,
68
+ processing: number,
69
+ resolved: number,
70
+ escalated: number,
71
+ overdue: number,
72
+ todayCreated: number,
73
+ avgResponseTime: number,
74
+ satisfactionRate: number,
75
+ };
76
+ /* 导出加载状态 */
77
+ exportLoading: boolean;
78
+ /* 批量操作下拉框可见性 */
79
+ batchActionsVisible: boolean;
80
+ /* 详情抽屉可见性 */
81
+ detailDrawerVisible: boolean;
82
+ /* 工单列表数据 */
83
+ tickets: {
84
+ /* @example TK-2024001 */id?: string,
85
+ /* @example 系统登录失败无法访问 */title?: string,
86
+ /* @example 用户反映无法正常登录系统,提示密码错误但密码确认无误 */description?: string,
87
+ /* @example 技术支持 */type?: string,
88
+ /* @example high */priority?: string,
89
+ /* @example processing */status?: string,
90
+ /* @example 张三 */assignee?: string,
91
+ /* @example 李四 */reporter?: string,
92
+ /* @example IT支持部 */department?: string,
93
+ /* @example 2024-01-15 09:30:00 */createdAt?: string,
94
+ /* @example 2024-01-15 14:20:00 */updatedAt?: string,
95
+ /* @example 2024-01-17 */dueDate?: string,
96
+ /* @example 65 */progress?: number,
97
+ tags?: string,
98
+ /* @example 3 */attachments?: number,
99
+ /* @example 12 */comments?: number,
100
+ /* @example 5 */watchers?: number,
101
+ satisfaction?: any,
102
+ /* @example 30 */responseTime?: any,
103
+ resolveTime?: any,
104
+ /* @example normal */slaStatus?: string,
105
+ /* @example 系统故障 */category?: string,
106
+ /* @example 登录问题 */subcategory?: string,
107
+ /* @example high */impact?: string,
108
+ /* @example high */urgency?: string,
109
+ /* @example web */source?: string,
110
+ /* @example 总部大楼 */location?: string,
111
+ /* @example Windows PC */device?: any,
112
+ /* @example Chrome 120 */browser?: any,
113
+ }[];
114
+ /* 当前查看的工单详情 */
115
+ currentTicket: any;
116
+ }
117
+
118
+ class Document extends React.Component<IProps, IState> {
119
+ state = {
120
+ loading: false,
121
+ selectedRowKeys: [],
122
+ searchKeyword: '',
123
+ filters: {},
124
+ sorter: {},
125
+ pagination: { current: 1, pageSize: 20, total: 100 },
126
+ columns: [
127
+ {
128
+ title: '工单编号',
129
+ dataIndex: 'id',
130
+ key: 'id',
131
+ width: 120,
132
+ fixed: 'left',
133
+ sorter: true,
134
+ filterable: true,
135
+ },
136
+ {
137
+ title: '标题',
138
+ dataIndex: 'title',
139
+ key: 'title',
140
+ width: 250,
141
+ ellipsis: true,
142
+ sorter: true,
143
+ },
144
+ {
145
+ title: '类型',
146
+ dataIndex: 'type',
147
+ key: 'type',
148
+ width: 100,
149
+ filters: [
150
+ { text: '技术支持', value: '技术支持' },
151
+ { text: '硬件支持', value: '硬件支持' },
152
+ { text: '账号管理', value: '账号管理' },
153
+ { text: '网络支持', value: '网络支持' },
154
+ { text: '系统支持', value: '系统支持' },
155
+ ],
156
+ },
157
+ {
158
+ title: '优先级',
159
+ dataIndex: 'priority',
160
+ key: 'priority',
161
+ width: 90,
162
+ sorter: true,
163
+ filters: [
164
+ { text: '低', value: 'low' },
165
+ { text: '中', value: 'medium' },
166
+ { text: '高', value: 'high' },
167
+ { text: '紧急', value: 'urgent' },
168
+ ],
169
+ },
170
+ {
171
+ title: '状态',
172
+ dataIndex: 'status',
173
+ key: 'status',
174
+ width: 100,
175
+ sorter: true,
176
+ filters: [
177
+ { text: '待处理', value: 'pending' },
178
+ { text: '处理中', value: 'processing' },
179
+ { text: '已解决', value: 'resolved' },
180
+ { text: '已升级', value: 'escalated' },
181
+ ],
182
+ },
183
+ {
184
+ title: '处理人',
185
+ dataIndex: 'assignee',
186
+ key: 'assignee',
187
+ width: 100,
188
+ filterable: true,
189
+ },
190
+ {
191
+ title: '部门',
192
+ dataIndex: 'department',
193
+ key: 'department',
194
+ width: 120,
195
+ filters: [
196
+ { text: 'IT支持部', value: 'IT支持部' },
197
+ { text: '行政部', value: '行政部' },
198
+ { text: '人力资源部', value: '人力资源部' },
199
+ { text: '销售部', value: '销售部' },
200
+ { text: '财务部', value: '财务部' },
201
+ ],
202
+ },
203
+ {
204
+ title: '创建时间',
205
+ dataIndex: 'createdAt',
206
+ key: 'createdAt',
207
+ width: 150,
208
+ sorter: true,
209
+ },
210
+ {
211
+ title: '截止时间',
212
+ dataIndex: 'dueDate',
213
+ key: 'dueDate',
214
+ width: 110,
215
+ sorter: true,
216
+ },
217
+ { title: '进度', dataIndex: 'progress', key: 'progress', width: 120 },
218
+ {
219
+ title: 'SLA状态',
220
+ dataIndex: 'slaStatus',
221
+ key: 'slaStatus',
222
+ width: 100,
223
+ filters: [
224
+ { text: '正常', value: 'normal' },
225
+ { text: '预警', value: 'warning' },
226
+ { text: '危险', value: 'danger' },
227
+ { text: '超时', value: 'breached' },
228
+ { text: '成功', value: 'success' },
229
+ ],
230
+ },
231
+ {
232
+ title: '满意度',
233
+ dataIndex: 'satisfaction',
234
+ key: 'satisfaction',
235
+ width: 100,
236
+ sorter: true,
237
+ },
238
+ { title: '操作', key: 'actions', width: 150, fixed: 'right' },
239
+ ],
240
+ advancedSearchExpanded: false,
241
+ statistics: {
242
+ total: 325,
243
+ pending: 42,
244
+ processing: 128,
245
+ resolved: 155,
246
+ escalated: 18,
247
+ overdue: 25,
248
+ todayCreated: 38,
249
+ avgResponseTime: 45,
250
+ satisfactionRate: 4.6,
251
+ },
252
+ exportLoading: false,
253
+ batchActionsVisible: false,
254
+ detailDrawerVisible: false,
255
+ tickets: [
256
+ {
257
+ id: 'TK-2024001',
258
+ title: '系统登录失败无法访问',
259
+ description: '用户反映无法正常登录系统,提示密码错误但密码确认无误',
260
+ type: '技术支持',
261
+ priority: 'high',
262
+ status: 'processing',
263
+ assignee: '张三',
264
+ reporter: '李四',
265
+ department: 'IT支持部',
266
+ createdAt: '2024-01-15 09:30:00',
267
+ updatedAt: '2024-01-15 14:20:00',
268
+ dueDate: '2024-01-17',
269
+ progress: 65,
270
+ tags: ['紧急', '系统问题'],
271
+ attachments: 3,
272
+ comments: 12,
273
+ watchers: 5,
274
+ responseTime: 30,
275
+ slaStatus: 'normal',
276
+ category: '系统故障',
277
+ subcategory: '登录问题',
278
+ impact: 'high',
279
+ urgency: 'high',
280
+ source: 'web',
281
+ location: '总部大楼',
282
+ device: 'Windows PC',
283
+ browser: 'Chrome 120',
284
+ },
285
+ {
286
+ id: 'TK-2024002',
287
+ title: '打印机无法连接网络',
288
+ description: '3楼打印机突然无法连接网络,已尝试重启但问题依旧',
289
+ type: '硬件支持',
290
+ priority: 'medium',
291
+ status: 'pending',
292
+ assignee: '王五',
293
+ reporter: '赵六',
294
+ department: '行政部',
295
+ createdAt: '2024-01-15 10:15:00',
296
+ updatedAt: '2024-01-15 10:15:00',
297
+ dueDate: '2024-01-16',
298
+ progress: 0,
299
+ tags: ['硬件'],
300
+ attachments: 2,
301
+ comments: 5,
302
+ watchers: 3,
303
+ slaStatus: 'warning',
304
+ category: '办公设备',
305
+ subcategory: '打印机',
306
+ impact: 'medium',
307
+ urgency: 'medium',
308
+ source: 'email',
309
+ location: '3楼办公区',
310
+ device: 'HP LaserJet',
311
+ },
312
+ {
313
+ id: 'TK-2024003',
314
+ title: '需要开通新员工系统账号',
315
+ description: '新入职员工需要开通ERP、CRM、OA系统账号',
316
+ type: '账号管理',
317
+ priority: 'low',
318
+ status: 'resolved',
319
+ assignee: '孙七',
320
+ reporter: '周八',
321
+ department: '人力资源部',
322
+ createdAt: '2024-01-14 14:20:00',
323
+ updatedAt: '2024-01-15 11:00:00',
324
+ dueDate: '2024-01-15',
325
+ progress: 100,
326
+ tags: ['新员工', '账号开通'],
327
+ attachments: 4,
328
+ comments: 8,
329
+ watchers: 4,
330
+ satisfaction: 5,
331
+ responseTime: 120,
332
+ resolveTime: 1440,
333
+ slaStatus: 'success',
334
+ category: '权限管理',
335
+ subcategory: '账号开通',
336
+ impact: 'low',
337
+ urgency: 'low',
338
+ source: 'phone',
339
+ location: '2楼人力资源部',
340
+ },
341
+ {
342
+ id: 'TK-2024004',
343
+ title: 'VPN连接不稳定频繁断线',
344
+ description: '居家办公时VPN连接经常断线,影响正常工作',
345
+ type: '网络支持',
346
+ priority: 'high',
347
+ status: 'processing',
348
+ assignee: '吴九',
349
+ reporter: '郑十',
350
+ department: '销售部',
351
+ createdAt: '2024-01-15 08:45:00',
352
+ updatedAt: '2024-01-15 15:30:00',
353
+ dueDate: '2024-01-16',
354
+ progress: 40,
355
+ tags: ['VPN', '远程办公', '网络'],
356
+ attachments: 1,
357
+ comments: 15,
358
+ watchers: 6,
359
+ responseTime: 15,
360
+ slaStatus: 'danger',
361
+ category: '网络问题',
362
+ subcategory: 'VPN',
363
+ impact: 'high',
364
+ urgency: 'high',
365
+ source: 'mobile',
366
+ location: '远程',
367
+ device: 'MacBook Pro',
368
+ browser: 'Safari',
369
+ },
370
+ {
371
+ id: 'TK-2024005',
372
+ title: '数据报表导出功能异常',
373
+ description: '月度销售报表无法导出,点击导出按钮无响应',
374
+ type: '系统支持',
375
+ priority: 'urgent',
376
+ status: 'escalated',
377
+ assignee: '陈一',
378
+ reporter: '林二',
379
+ department: '财务部',
380
+ createdAt: '2024-01-15 11:00:00',
381
+ updatedAt: '2024-01-15 16:00:00',
382
+ dueDate: '2024-01-15',
383
+ progress: 20,
384
+ tags: ['报表', '数据导出', '紧急'],
385
+ attachments: 5,
386
+ comments: 20,
387
+ watchers: 8,
388
+ responseTime: 60,
389
+ slaStatus: 'breached',
390
+ category: '系统功能',
391
+ subcategory: '报表功能',
392
+ impact: 'critical',
393
+ urgency: 'urgent',
394
+ source: 'web',
395
+ location: '4楼财务部',
396
+ device: 'Windows PC',
397
+ browser: 'Firefox',
398
+ },
399
+ ],
400
+ currentTicket: {},
401
+ };
402
+
403
+ /**
404
+ * 切换高级搜索展开状态
405
+ */
406
+ toggleAdvancedSearch() {
407
+ this.setState({
408
+ advancedSearchExpanded: !this.state.advancedSearchExpanded,
409
+ });
410
+ }
411
+
412
+ /**
413
+ * 处理搜索
414
+ */
415
+ handleSearch() {
416
+ this.setState({
417
+ loading: true,
418
+ });
419
+ setTimeout(() => {
420
+ this.setState({
421
+ loading: false,
422
+ });
423
+ }, 1000);
424
+ }
425
+
426
+ /**
427
+ * 重置搜索条件
428
+ */
429
+ handleReset() {
430
+ this.setState({
431
+ searchKeyword: '',
432
+ filters: {},
433
+ sorter: {},
434
+ pagination: {
435
+ ...this.state.pagination,
436
+ current: 1,
437
+ },
438
+ });
439
+ }
440
+
441
+ /**
442
+ * 处理表格变化
443
+ */
444
+ handleTableChange(pagination, filters, sorter) {
445
+ this.setState({
446
+ pagination,
447
+ filters,
448
+ sorter,
449
+ });
450
+ }
451
+
452
+ /**
453
+ * 处理行选择
454
+ */
455
+ handleRowSelect(selectedRowKeys) {
456
+ this.setState({
457
+ selectedRowKeys,
458
+ });
459
+ }
460
+
461
+ /**
462
+ * 查看工单详情
463
+ */
464
+ viewTicketDetail(ticket) {
465
+ this.setState({
466
+ currentTicket: ticket,
467
+ detailDrawerVisible: true,
468
+ });
469
+ }
470
+
471
+ /**
472
+ * 关闭详情抽屉
473
+ */
474
+ closeDetailDrawer() {
475
+ this.setState({
476
+ detailDrawerVisible: false,
477
+ currentTicket: null,
478
+ });
479
+ }
480
+
481
+ /**
482
+ * 导出数据
483
+ */
484
+ handleExport() {
485
+ this.setState({
486
+ exportLoading: true,
487
+ });
488
+ setTimeout(() => {
489
+ this.setState({
490
+ exportLoading: false,
491
+ });
492
+ }, 2000);
493
+ }
494
+
495
+ /**
496
+ * 批量分配
497
+ */
498
+ handleBatchAssign() {
499
+ this.setState({
500
+ batchActionsVisible: false,
501
+ });
502
+ }
503
+
504
+ /**
505
+ * 批量更新状态
506
+ */
507
+ handleBatchUpdateStatus(status) {
508
+ this.setState({
509
+ batchActionsVisible: false,
510
+ });
511
+ }
512
+
513
+ /**
514
+ * 批量删除
515
+ */
516
+ handleBatchDelete() {
517
+ this.setState({
518
+ selectedRowKeys: [],
519
+ batchActionsVisible: false,
520
+ });
521
+ }
522
+
523
+ /**
524
+ * 刷新数据
525
+ */
526
+ handleRefresh() {
527
+ this.setState({
528
+ loading: true,
529
+ });
530
+ setTimeout(() => {
531
+ this.setState({
532
+ loading: false,
533
+ });
534
+ }, 1000);
535
+ }
536
+
537
+ /**
538
+ * 创建新工单
539
+ */
540
+ handleCreateTicket() {
541
+ console.log('Create new ticket');
542
+ }
543
+
544
+ /**
545
+ * 获取优先级颜色
546
+ */
547
+ getPriorityColor(priority) {
548
+ const colorMap = {
549
+ low: '#52c41a',
550
+ medium: '#faad14',
551
+ high: '#fa8c16',
552
+ urgent: '#f5222d',
553
+ };
554
+ return colorMap[priority] || '#d9d9d9';
555
+ }
556
+
557
+ /**
558
+ * 获取状态颜色
559
+ */
560
+ getStatusColor(status) {
561
+ const colorMap = {
562
+ pending: '#faad14',
563
+ processing: '#1890ff',
564
+ resolved: '#52c41a',
565
+ escalated: '#f5222d',
566
+ };
567
+ return colorMap[status] || '#d9d9d9';
568
+ }
569
+
570
+ /**
571
+ * 获取SLA状态颜色
572
+ */
573
+ getSLAStatusColor(slaStatus) {
574
+ const colorMap = {
575
+ normal: '#52c41a',
576
+ warning: '#faad14',
577
+ danger: '#fa8c16',
578
+ breached: '#f5222d',
579
+ success: '#1890ff',
580
+ };
581
+ return colorMap[slaStatus] || '#d9d9d9';
582
+ }
583
+
584
+ /**
585
+ * 获取满意度星级
586
+ */
587
+ getSatisfactionStars(satisfaction) {
588
+ if (!satisfaction) return '未评价';
589
+ const stars =
590
+ '★'.repeat(Math.floor(satisfaction)) +
591
+ '☆'.repeat(5 - Math.floor(satisfaction));
592
+ return `${stars} (${satisfaction})`;
593
+ }
594
+
595
+ render() {
596
+ const content = `
597
+ # Hello World
598
+
599
+ ### Welcome to XMarkdown!
600
+
601
+ - Item 1
602
+ - Item 2
603
+ - Item 3
604
+ `;
605
+ return (
606
+ <Page className="min-h-screen bg-[var(--gray-50)]">
607
+ <View className="p-[24px]">
608
+ <View className="mb-[24px] flex justify-between items-center">
609
+ <View>
610
+ <h1 className="text-2xl font-bold text-[#111827]">工单管理</h1>
611
+ <p className="text-[#6b7280] mt-[4px]">
612
+ 全面管理和跟踪所有工单信息
613
+ </p>
614
+ </View>
615
+ <View className="gap-3 flex">
616
+ <button
617
+ onClick={() => this.handleExport()}
618
+ className="border-gray-300 hover:bg-gray-50 border-solid flex items-center pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
619
+ >
620
+ <Text>导出数据</Text>
621
+ </button>
622
+ <button
623
+ onClick={() => this.handleRefresh()}
624
+ className="border-gray-300 hover:bg-gray-50 border-solid flex items-center pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
625
+ >
626
+ <Text>刷新</Text>
627
+ </button>
628
+ <button
629
+ onClick={() => this.handleCreateTicket()}
630
+ className="bg-blue-600 hover:bg-blue-700 flex items-center pl-[16px] pr-[16px] pt-[8px] pb-[8px] text-[#ffffff] rounded-lg"
631
+ >
632
+ <Text>创建工单</Text>
633
+ </button>
634
+ </View>
635
+ </View>
636
+ <View className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-[24px]">
637
+ <View className="bg-[#ffffff] p-[16px] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)]">
638
+ <View className="flex items-center justify-between">
639
+ <View>
640
+ <p className="text-[#6b7280] text-sm">总工单数</p>
641
+ <p className="text-2xl font-bold text-[#111827]">
642
+ {this.state.statistics?.total}
643
+ </p>
644
+ </View>
645
+ <View className="bg-[var(--blue-100)] p-[12px] rounded-full">
646
+ <Text className="text-xl">📋</Text>
647
+ </View>
648
+ </View>
649
+ </View>
650
+ <View className="bg-[#ffffff] p-[16px] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)]">
651
+ <View className="flex items-center justify-between">
652
+ <View>
653
+ <p className="text-[#6b7280] text-sm">处理中</p>
654
+ <p className="text-2xl font-bold">
655
+ {this.state.statistics?.processing}
656
+ </p>
657
+ </View>
658
+ <View className="bg-[var(--blue-100)] p-[12px] rounded-full">
659
+ <Text className="text-xl">⏳</Text>
660
+ </View>
661
+ </View>
662
+ </View>
663
+ <View className="bg-[#ffffff] p-[16px] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)]">
664
+ <View className="flex items-center justify-between">
665
+ <View>
666
+ <p className="text-[#6b7280] text-sm">已解决</p>
667
+ <p className="text-2xl font-bold">
668
+ {this.state.statistics?.resolved}
669
+ </p>
670
+ </View>
671
+ <View className="bg-[var(--green-100)] p-[12px] rounded-full">
672
+ <Text className="text-xl">✓</Text>
673
+ </View>
674
+ </View>
675
+ </View>
676
+ <View className="bg-[#ffffff] p-[16px] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)]">
677
+ <View className="flex items-center justify-between">
678
+ <View>
679
+ <p className="text-[#6b7280] text-sm">超时工单</p>
680
+ <p className="text-2xl font-bold">
681
+ {this.state.statistics?.overdue}
682
+ </p>
683
+ </View>
684
+ <View className="bg-[var(--red-100)] p-[12px] rounded-full">
685
+ <Text className="text-xl">⚠</Text>
686
+ </View>
687
+ </View>
688
+ </View>
689
+ </View>
690
+ <View className="bg-[#ffffff] p-[16px] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)] mb-[24px]">
691
+ <View className="gap-3 flex mb-[16px]">
692
+ <input
693
+ type="text"
694
+ placeholder="搜索工单编号、标题、描述..."
695
+ value={this.state.searchKeyword}
696
+ onChange={e =>
697
+ this.setState({
698
+ searchKeyword: e.target.value,
699
+ })
700
+ }
701
+ className="border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 border-solid flex-1 pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
702
+ onKeyPress={e => e.key === 'Enter' && this.handleSearch()}
703
+ />
704
+ <button
705
+ onClick={() => this.handleSearch()}
706
+ className="bg-blue-600 hover:bg-blue-700 pl-[24px] pr-[24px] pt-[8px] pb-[8px] text-[#ffffff] rounded-lg"
707
+ >
708
+ 搜索
709
+ </button>
710
+ <button
711
+ onClick={() => this.toggleAdvancedSearch()}
712
+ className="border-gray-300 hover:bg-gray-50 border-solid pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
713
+ >
714
+ {this.state.advancedSearchExpanded ? '收起筛选' : '高级筛选'}
715
+ </button>
716
+ </View>
717
+ {!!this.state.advancedSearchExpanded && (
718
+ <View className="border-t border-t-solid pt-[16px]">
719
+ <View className="grid grid-cols-1 md:grid-cols-3 gap-4">
720
+ <View>
721
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
722
+ 状态
723
+ </label>
724
+ <select className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg">
725
+ <option value="">全部状态</option>
726
+ <option value="pending">待处理</option>
727
+ <option value="processing">处理中</option>
728
+ <option value="resolved">已解决</option>
729
+ <option value="escalated">已升级</option>
730
+ </select>
731
+ </View>
732
+ <View>
733
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
734
+ 优先级
735
+ </label>
736
+ <select className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg">
737
+ <option value="">全部优先级</option>
738
+ <option value="low">低</option>
739
+ <option value="medium">中</option>
740
+ <option value="high">高</option>
741
+ <option value="urgent">紧急</option>
742
+ </select>
743
+ </View>
744
+ <View>
745
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
746
+ 部门
747
+ </label>
748
+ <select className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg">
749
+ <option value="">全部部门</option>
750
+ <option value="IT支持部">IT支持部</option>
751
+ <option value="行政部">行政部</option>
752
+ <option value="人力资源部">人力资源部</option>
753
+ <option value="销售部">销售部</option>
754
+ <option value="财务部">财务部</option>
755
+ </select>
756
+ </View>
757
+ <View>
758
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
759
+ 处理人
760
+ </label>
761
+ <input
762
+ type="text"
763
+ placeholder="输入处理人姓名"
764
+ className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
765
+ />
766
+ </View>
767
+ <View>
768
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
769
+ 创建时间
770
+ </label>
771
+ <input
772
+ type="date"
773
+ className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
774
+ />
775
+ </View>
776
+ <View>
777
+ <label className="block text-sm font-medium text-[#374151] mb-[4px]">
778
+ 截止时间
779
+ </label>
780
+ <input
781
+ type="date"
782
+ className="border-gray-300 border-solid w-full pl-[12px] pr-[12px] pt-[8px] pb-[8px] border border-solid rounded-lg"
783
+ />
784
+ </View>
785
+ </View>
786
+ <View className="gap-3 flex justify-end mt-[16px]">
787
+ <button
788
+ onClick={() => this.handleReset()}
789
+ className="border-gray-300 hover:bg-gray-50 border-solid pl-[16px] pr-[16px] pt-[8px] pb-[8px] border border-solid rounded-lg"
790
+ >
791
+ 重置
792
+ </button>
793
+ <button
794
+ onClick={() => this.handleSearch()}
795
+ className="bg-blue-600 hover:bg-blue-700 pl-[24px] pr-[24px] pt-[8px] pb-[8px] text-[#ffffff] rounded-lg"
796
+ >
797
+ 应用筛选
798
+ </button>
799
+ </View>
800
+ </View>
801
+ )}
802
+ </View>
803
+ {!!this.state.selectedRowKeys?.length && (
804
+ <View className="bg-[var(--blue-50)] p-[12px] rounded-lg mb-[16px] flex justify-between items-center">
805
+ <Text className="">
806
+ 已选择{this.state.selectedRowKeys?.length}项
807
+ </Text>
808
+ <View className="gap-2 flex">
809
+ <button
810
+ onClick={() => this.handleBatchAssign()}
811
+ className="bg-white border-gray-300 hover:bg-gray-50 border-solid pl-[12px] pr-[12px] pt-[4px] pb-[4px] text-sm border border-solid rounded"
812
+ >
813
+ 批量分配
814
+ </button>
815
+ <button
816
+ onClick={() => this.handleBatchUpdateStatus('resolved')}
817
+ className="bg-white border-gray-300 hover:bg-gray-50 border-solid pl-[12px] pr-[12px] pt-[4px] pb-[4px] text-sm border border-solid rounded"
818
+ >
819
+ 批量解决
820
+ </button>
821
+ <button
822
+ onClick={() => this.handleBatchDelete()}
823
+ className="bg-white border-red-300 hover:bg-red-50 border-solid pl-[12px] pr-[12px] pt-[4px] pb-[4px] text-sm border border-solid rounded"
824
+ >
825
+ 批量删除
826
+ </button>
827
+ </View>
828
+ </View>
829
+ )}
830
+ <View className="bg-[#ffffff] rounded-lg shadow-[0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)]">
831
+ <View className="overflow-x-auto">
832
+ <table className="min-w-full">
833
+ <thead className="bg-[var(--gray-50)] border-b-[1px] border-b-solid">
834
+ <tr>
835
+ <th className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
836
+ <input
837
+ type="checkbox"
838
+ checked={
839
+ this.state.selectedRowKeys?.length ===
840
+ this.state.tickets?.length
841
+ }
842
+ onChange={e => {
843
+ if (e.target.checked) {
844
+ this.setState({
845
+ selectedRowKeys: this.state.tickets?.map(
846
+ t => t.id
847
+ ),
848
+ });
849
+ } else {
850
+ this.setState({
851
+ selectedRowKeys: [],
852
+ });
853
+ }
854
+ }}
855
+ />
856
+ </th>
857
+ {this.state.columns.map((col, index) => (
858
+ <th
859
+ key={col.key}
860
+ className="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
861
+ style={{ width: col.width }}
862
+ >
863
+ <Text>{col.title}</Text>
864
+ </th>
865
+ ))}
866
+ </tr>
867
+ </thead>
868
+ <tbody className="divide-y divide-gray-200">
869
+ {this.state.tickets.map((ticket, index) => (
870
+ <tr key={ticket.id} className="hover:bg-gray-50">
871
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
872
+ <input
873
+ type="checkbox"
874
+ checked={this.state.selectedRowKeys?.includes(
875
+ ticket.id
876
+ )}
877
+ onChange={e => {
878
+ if (e.target.checked) {
879
+ this.setState({
880
+ selectedRowKeys: [
881
+ ...(this.state.selectedRowKeys || []),
882
+ ticket.id,
883
+ ],
884
+ });
885
+ } else {
886
+ this.setState({
887
+ selectedRowKeys:
888
+ this.state.selectedRowKeys?.filter(
889
+ id => id !== ticket.id
890
+ ),
891
+ });
892
+ }
893
+ }}
894
+ />
895
+ </td>
896
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
897
+ <button
898
+ onClick={() => this.viewTicketDetail(ticket)}
899
+ className="text-blue-600 hover:text-blue-800 font-medium"
900
+ >
901
+ <Text>{ticket.id}</Text>
902
+ </button>
903
+ </td>
904
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
905
+ <View
906
+ title={ticket.title}
907
+ className="overflow-hidden [textOverflow:ellipsis] [whiteSpace:nowrap]"
908
+ >
909
+ <Text>{ticket.title}</Text>
910
+ </View>
911
+ </td>
912
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
913
+ <Text className="inline-flex pl-[8px] pr-[8px] pt-[4px] pb-[4px] text-xs font-semibold rounded-full bg-[#f3f4f6] text-[#1f2937]">
914
+ {ticket.type}
915
+ </Text>
916
+ </td>
917
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
918
+ <Text
919
+ className="inline-flex px-2 py-1 text-xs font-semibold rounded-full text-white"
920
+ style={{
921
+ backgroundColor: this.getPriorityColor(
922
+ ticket.priority
923
+ ),
924
+ }}
925
+ >
926
+ {ticket.priority === 'low'
927
+ ? '低'
928
+ : ticket.priority === 'medium'
929
+ ? '中'
930
+ : ticket.priority === 'high'
931
+ ? '高'
932
+ : '紧急'}
933
+ </Text>
934
+ </td>
935
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
936
+ <Text
937
+ className="inline-flex px-2 py-1 text-xs font-semibold rounded-full text-white"
938
+ style={{
939
+ backgroundColor: this.getStatusColor(ticket.status),
940
+ }}
941
+ >
942
+ {ticket.status === 'pending'
943
+ ? '待处理'
944
+ : ticket.status === 'processing'
945
+ ? '处理中'
946
+ : ticket.status === 'resolved'
947
+ ? '已解决'
948
+ : '已升级'}
949
+ </Text>
950
+ </td>
951
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
952
+ <Text>{ticket.assignee}</Text>
953
+ </td>
954
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
955
+ <Text>{ticket.department}</Text>
956
+ </td>
957
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
958
+ <Text className="text-sm text-[#4b5563]">
959
+ {ticket.createdAt}
960
+ </Text>
961
+ </td>
962
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
963
+ <Text className="text-sm">{ticket.dueDate}</Text>
964
+ </td>
965
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
966
+ <View className="gap-2 flex items-center">
967
+ <View className="flex-1 bg-[#e5e7eb] rounded-full h-[8px]">
968
+ <View
969
+ className="bg-blue-600 h-2 rounded-full"
970
+ style={{ width: `${ticket.progress}%` }}
971
+ />
972
+ </View>
973
+ <Text className="text-xs text-[#4b5563]">
974
+ {ticket.progress}%
975
+ </Text>
976
+ </View>
977
+ </td>
978
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
979
+ <Text
980
+ className="inline-flex px-2 py-1 text-xs font-semibold rounded-full text-white"
981
+ style={{
982
+ backgroundColor: this.getSLAStatusColor(
983
+ ticket.slaStatus
984
+ ),
985
+ }}
986
+ >
987
+ {ticket.slaStatus === 'normal'
988
+ ? '正常'
989
+ : ticket.slaStatus === 'warning'
990
+ ? '预警'
991
+ : ticket.slaStatus === 'danger'
992
+ ? '危险'
993
+ : ticket.slaStatus === 'breached'
994
+ ? '超时'
995
+ : '成功'}
996
+ </Text>
997
+ </td>
998
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
999
+ <Text className="text-sm">
1000
+ {ticket.satisfaction
1001
+ ? this.getSatisfactionStars(ticket.satisfaction)
1002
+ : '-'}
1003
+ </Text>
1004
+ </td>
1005
+ <td className="pl-[16px] pr-[16px] pt-[12px] pb-[12px]">
1006
+ <View className="gap-2 flex">
1007
+ <button
1008
+ onClick={() => this.viewTicketDetail(ticket)}
1009
+ className="text-blue-600 hover:text-blue-800 text-sm"
1010
+ >
1011
+ 详情
1012
+ </button>
1013
+ <button className="text-gray-600 hover:text-gray-800 text-sm">
1014
+ 编辑
1015
+ </button>
1016
+ <button className="text-red-600 hover:text-red-800 text-sm">
1017
+ 删除
1018
+ </button>
1019
+ </View>
1020
+ </td>
1021
+ </tr>
1022
+ ))}
1023
+ </tbody>
1024
+ </table>
1025
+ </View>
1026
+ <View className="p-[16px] border-t border-t-solid flex justify-between items-center">
1027
+ <Text className="text-sm text-[#4b5563]">
1028
+ 共{this.state.pagination?.total}条记录,第
1029
+ {this.state.pagination?.current}/
1030
+ {Math.ceil(
1031
+ (this.state.pagination?.total || 0) /
1032
+ (this.state.pagination?.pageSize || 1)
1033
+ )}
1034
+
1035
+ </Text>
1036
+ <View className="gap-2 flex">
1037
+ <button
1038
+ onClick={() =>
1039
+ this.setState({
1040
+ pagination: {
1041
+ ...this.state.pagination,
1042
+ current: Math.max(
1043
+ 1,
1044
+ (this.state.pagination?.current || 1) - 1
1045
+ ),
1046
+ },
1047
+ })
1048
+ }
1049
+ disabled={this.state.pagination?.current || 1 === 1}
1050
+ className="border-gray-300 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed border-solid pl-[12px] pr-[12px] pt-[4px] pb-[4px] border border-solid rounded"
1051
+ >
1052
+ 上一页
1053
+ </button>
1054
+ <button
1055
+ onClick={() =>
1056
+ this.setState({
1057
+ pagination: {
1058
+ ...this.state.pagination,
1059
+ current: (this.state.pagination?.current || 1) + 1,
1060
+ },
1061
+ })
1062
+ }
1063
+ disabled={
1064
+ this.state.pagination?.current ||
1065
+ 1 >=
1066
+ Math.ceil(
1067
+ this.state.pagination?.total ||
1068
+ 0 / this.state.pagination?.pageSize ||
1069
+ 1
1070
+ )
1071
+ }
1072
+ className="border-gray-300 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed border-solid pl-[12px] pr-[12px] pt-[4px] pb-[4px] border border-solid rounded"
1073
+ >
1074
+ 下一页
1075
+ </button>
1076
+ </View>
1077
+ </View>
1078
+ </View>
1079
+ {!!this.state.detailDrawerVisible && (
1080
+ <View className="inset-0 fixed z-50 overflow-hidden">
1081
+ <View className="inset-0 absolute overflow-hidden">
1082
+ <View
1083
+ className="inset-0 transition-opacity absolute bg-[var(--opacity-50)]"
1084
+ onClick={() => this.closeDetailDrawer()}
1085
+ />
1086
+ <View className="inset-y-0 md:max-w-2xl absolute right-[0px] max-w-full w-full">
1087
+ <View className="h-full flex flex-col bg-[#ffffff] shadow-[0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)]">
1088
+ <View className="px-4 py-6 sm:px-6 bg-[var(--gray-50)]">
1089
+ <View className="flex items-start justify-between">
1090
+ <h2 className="text-lg font-medium text-[#111827]">
1091
+ 工单详情
1092
+ </h2>
1093
+ <button
1094
+ onClick={() => this.closeDetailDrawer()}
1095
+ className="text-gray-400 hover:text-gray-500 focus:outline-none ml-[12px] h-[28px] w-[28px] flex items-center justify-center rounded-full bg-[#ffffff]"
1096
+ >
1097
+ <Text>{``}</Text>
1098
+ </button>
1099
+ </View>
1100
+ </View>
1101
+ <View className="flex-1 relative overflow-y-auto">
1102
+ <View className="pt-[24px] pb-[24px]">
1103
+ <View className="px-4 sm:px-6">
1104
+ <View className="mb-[24px]">
1105
+ <h3 className="text-lg font-medium text-[#111827] mb-[8px]">
1106
+ {this.state.currentTicket?.title}
1107
+ </h3>
1108
+ <p className="text-[#4b5563]">
1109
+ {this.state.currentTicket?.description}
1110
+ </p>
1111
+ </View>
1112
+ <View className="gap-4 grid grid-cols-2 mb-[24px]">
1113
+ <View>
1114
+ <p className="text-sm text-[#6b7280]">工单编号</p>
1115
+ <p className="font-medium">
1116
+ {this.state.currentTicket?.id}
1117
+ </p>
1118
+ </View>
1119
+ <View>
1120
+ <p className="text-sm text-[#6b7280]">状态</p>
1121
+ <Text
1122
+ className="inline-flex px-2 py-1 text-xs font-semibold rounded-full text-white"
1123
+ style={{
1124
+ backgroundColor: this.getStatusColor(
1125
+ this.state.currentTicket?.status
1126
+ ),
1127
+ }}
1128
+ >
1129
+ {this.state.currentTicket?.status === 'pending'
1130
+ ? '待处理'
1131
+ : this.state.currentTicket?.status ===
1132
+ 'processing'
1133
+ ? '处理中'
1134
+ : this.state.currentTicket?.status ===
1135
+ 'resolved'
1136
+ ? '已解决'
1137
+ : '已升级'}
1138
+ </Text>
1139
+ </View>
1140
+ <View>
1141
+ <p className="text-sm text-[#6b7280]">优先级</p>
1142
+ <Text
1143
+ className="inline-flex px-2 py-1 text-xs font-semibold rounded-full text-white"
1144
+ style={{
1145
+ backgroundColor: this.getPriorityColor(
1146
+ this.state.currentTicket?.priority
1147
+ ),
1148
+ }}
1149
+ >
1150
+ {this.state.currentTicket?.priority === 'low'
1151
+ ? '低'
1152
+ : this.state.currentTicket?.priority ===
1153
+ 'medium'
1154
+ ? '中'
1155
+ : this.state.currentTicket?.priority ===
1156
+ 'high'
1157
+ ? '高'
1158
+ : '紧急'}
1159
+ </Text>
1160
+ </View>
1161
+ <View>
1162
+ <p className="text-sm text-[#6b7280]">类型</p>
1163
+ <p className="font-medium">
1164
+ {this.state.currentTicket?.type}
1165
+ </p>
1166
+ </View>
1167
+ <View>
1168
+ <p className="text-sm text-[#6b7280]">处理人</p>
1169
+ <p className="font-medium">
1170
+ {this.state.currentTicket?.assignee}
1171
+ </p>
1172
+ </View>
1173
+ <View>
1174
+ <p className="text-sm text-[#6b7280]">部门</p>
1175
+ <p className="font-medium">
1176
+ {this.state.currentTicket?.department}
1177
+ </p>
1178
+ </View>
1179
+ <View>
1180
+ <p className="text-sm text-[#6b7280]">创建时间</p>
1181
+ <p className="font-medium">
1182
+ {this.state.currentTicket?.createdAt}
1183
+ </p>
1184
+ </View>
1185
+ <View>
1186
+ <p className="text-sm text-[#6b7280]">截止时间</p>
1187
+ <p className="font-medium">
1188
+ {this.state.currentTicket?.dueDate}
1189
+ </p>
1190
+ </View>
1191
+ </View>
1192
+ <View className="border-t border-t-solid pt-[16px]">
1193
+ <h4 className="font-medium mb-[8px]">进度</h4>
1194
+ <View className="gap-2 flex items-center">
1195
+ <View className="flex-1 bg-[#e5e7eb] rounded-full h-[8px]">
1196
+ <View
1197
+ className="bg-blue-600 h-2 rounded-full"
1198
+ style={{
1199
+ width: `${this.state.currentTicket?.progress}%`,
1200
+ }}
1201
+ />
1202
+ </View>
1203
+ <Text className="text-sm text-[#4b5563]">
1204
+ {this.state.currentTicket?.progress}%
1205
+ </Text>
1206
+ </View>
1207
+ </View>
1208
+ <View className="border-t border-t-solid pt-[16px] mt-[16px]">
1209
+ <h4 className="font-medium mb-[8px]">标签</h4>
1210
+ <View className="gap-2 flex flex-wrap">
1211
+ {(this.state.currentTicket?.tags).map(
1212
+ (tag, idx) => (
1213
+ <Text
1214
+ key={idx}
1215
+ className="pl-[8px] pr-[8px] pt-[4px] pb-[4px] text-xs bg-[#f3f4f6] text-[#374151] rounded"
1216
+ >
1217
+ {tag}
1218
+ </Text>
1219
+ )
1220
+ )}
1221
+ </View>
1222
+ </View>
1223
+ </View>
1224
+ </View>
1225
+ </View>
1226
+ </View>
1227
+ </View>
1228
+ </View>
1229
+ </View>
1230
+ )}
1231
+ </View>
1232
+ <XMarkdown content={content} />
1233
+ </Page>
1234
+ );
1235
+ }
1236
+ }
1237
+
1238
+ export default Document;