business_tms_program 0.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 (136) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc-auto-import.json +113 -0
  3. package/.eslintrc.js +121 -0
  4. package/.prettierrc.js +9 -0
  5. package/.stylelintignore +4 -0
  6. package/README.md +43 -0
  7. package/components.d.ts +23 -0
  8. package/index.html +20 -0
  9. package/package.json +70 -0
  10. package/shims-uni.d.ts +10 -0
  11. package/src/App.vue +81 -0
  12. package/src/api/afterSale.ts +184 -0
  13. package/src/api/context.ts +26 -0
  14. package/src/api/device.ts +134 -0
  15. package/src/api/index.ts +80 -0
  16. package/src/api/installtion.ts +155 -0
  17. package/src/api/model/index.ts +15 -0
  18. package/src/api/model/userModel.ts +62 -0
  19. package/src/api/order.ts +49 -0
  20. package/src/api/system.ts +19 -0
  21. package/src/api/user.ts +171 -0
  22. package/src/auto-imports.d.ts +108 -0
  23. package/src/components/ConfirmDialog.vue +101 -0
  24. package/src/components/DaySelect.vue +212 -0
  25. package/src/components/Drawer.vue +104 -0
  26. package/src/components/DrawerSelect.vue +105 -0
  27. package/src/components/DropMenu.vue +144 -0
  28. package/src/components/Empty.vue +49 -0
  29. package/src/components/Loading.vue +41 -0
  30. package/src/components/RippleBtn.vue +159 -0
  31. package/src/components/SinglePick.vue +120 -0
  32. package/src/components/Skeleton.vue +43 -0
  33. package/src/components/Timeline.vue +85 -0
  34. package/src/components/Upload.vue +217 -0
  35. package/src/config/app.ts +32 -0
  36. package/src/config/env.ts +29 -0
  37. package/src/dict/afterSale.ts +161 -0
  38. package/src/dict/device.ts +29 -0
  39. package/src/dict/installtion.ts +141 -0
  40. package/src/dict/systems.ts +4 -0
  41. package/src/env.d.ts +8 -0
  42. package/src/hooks/useForm.ts +222 -0
  43. package/src/hooks/useUpload.ts +80 -0
  44. package/src/main.ts +8 -0
  45. package/src/manifest.json +39 -0
  46. package/src/pages/acceptance/DeviceInfo.vue +132 -0
  47. package/src/pages/acceptance/list.vue +276 -0
  48. package/src/pages/afterSale/DeviceInfo.vue +128 -0
  49. package/src/pages/afterSale/Step.vue +0 -0
  50. package/src/pages/afterSale/faultReport.vue +552 -0
  51. package/src/pages/afterSale/orderDetail.vue +327 -0
  52. package/src/pages/afterSale/orderFinish.vue +517 -0
  53. package/src/pages/afterSale/orderList.vue +305 -0
  54. package/src/pages/afterSale/returnVisit.vue +288 -0
  55. package/src/pages/afterSale/searchDeviceList.vue +148 -0
  56. package/src/pages/device/Search.vue +201 -0
  57. package/src/pages/device/acceptance.vue +270 -0
  58. package/src/pages/device/detail.vue +165 -0
  59. package/src/pages/device/index.vue +322 -0
  60. package/src/pages/device/info.vue +140 -0
  61. package/src/pages/device/list.vue +219 -0
  62. package/src/pages/device/materialTowerCode.vue +589 -0
  63. package/src/pages/device/searchList.vue +224 -0
  64. package/src/pages/installtion/Record.vue +145 -0
  65. package/src/pages/installtion/StatusTimeline.vue +85 -0
  66. package/src/pages/installtion/addAcceptance.vue +409 -0
  67. package/src/pages/installtion/addRecord.vue +338 -0
  68. package/src/pages/installtion/orderDetail.vue +220 -0
  69. package/src/pages/installtion/orderList.vue +100 -0
  70. package/src/pages/user/component/PersonAgree.vue +226 -0
  71. package/src/pages/user/component/PrivayAgree.vue +221 -0
  72. package/src/pages/user/component/SliderCode.vue +173 -0
  73. package/src/pages/user/forgetPassword.vue +249 -0
  74. package/src/pages/user/index.vue +139 -0
  75. package/src/pages/user/login.vue +342 -0
  76. package/src/pages/user/register.vue +348 -0
  77. package/src/pages/user/repassword.vue +329 -0
  78. package/src/pages/user/utils/mcaptcha.js +75 -0
  79. package/src/pages/user/utils/verifyCode.ts +41 -0
  80. package/src/pages/workspace/index.vue +225 -0
  81. package/src/pages.json +203 -0
  82. package/src/shime-uni.d.ts +6 -0
  83. package/src/static/icon/system/breeder_icon.png +0 -0
  84. package/src/static/icon/system/check.png +0 -0
  85. package/src/static/icon/system/factory_icon.png +0 -0
  86. package/src/static/icon/system/plus.png +0 -0
  87. package/src/static/icon/system/right.png +0 -0
  88. package/src/static/icon/system/unCheck.png +0 -0
  89. package/src/static/icon/tab/search.png +0 -0
  90. package/src/static/icon/tab/user.png +0 -0
  91. package/src/static/icon/tab/user_active.png +0 -0
  92. package/src/static/icon/tab/workspace.png +0 -0
  93. package/src/static/icon/tab/workspace_active.png +0 -0
  94. package/src/static/img/active_dot.png +0 -0
  95. package/src/static/img/afterSale_icon.png +0 -0
  96. package/src/static/img/check.png +0 -0
  97. package/src/static/img/close.png +0 -0
  98. package/src/static/img/confirm.png +0 -0
  99. package/src/static/img/empty.png +0 -0
  100. package/src/static/img/equipment_icon.png +0 -0
  101. package/src/static/img/fault_icon.png +0 -0
  102. package/src/static/img/install_icon.png +0 -0
  103. package/src/static/img/login_bg2.png +0 -0
  104. package/src/static/img/movable_right.png +0 -0
  105. package/src/static/img/navigation.png +0 -0
  106. package/src/static/img/psw_off.png +0 -0
  107. package/src/static/img/psw_on.png +0 -0
  108. package/src/static/img/scan.png +0 -0
  109. package/src/static/img/scan_icon.png +0 -0
  110. package/src/static/img/search.png +0 -0
  111. package/src/static/img/turn_right.png +0 -0
  112. package/src/static/img/unActive_dot.png +0 -0
  113. package/src/static/img/verifyBg.png +0 -0
  114. package/src/stores/index.ts +11 -0
  115. package/src/stores/modules/customer.ts +146 -0
  116. package/src/stores/modules/installtion.ts +30 -0
  117. package/src/stores/modules/system.ts +56 -0
  118. package/src/stores/modules/user.ts +133 -0
  119. package/src/stores/types.ts +16 -0
  120. package/src/stores/utils.ts +6 -0
  121. package/src/styles/index.less +63 -0
  122. package/src/types/chengyiApi.d.ts +36 -0
  123. package/src/types/index.d.ts +95 -0
  124. package/src/utils/address.ts +17 -0
  125. package/src/utils/cipher.ts +61 -0
  126. package/src/utils/form.ts +155 -0
  127. package/src/utils/httpEnum.ts +31 -0
  128. package/src/utils/image.ts +21 -0
  129. package/src/utils/index.ts +111 -0
  130. package/src/utils/request.ts +139 -0
  131. package/src/utils/requestCancelHandle.ts +67 -0
  132. package/stylelint.config.js +87 -0
  133. package/tsconfig.docs.json +11 -0
  134. package/tsconfig.json +30 -0
  135. package/typedoc.json +6 -0
  136. package/vite.config.ts +55 -0
@@ -0,0 +1,327 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { getOrderDetail, handleOrder } from '@/api/afterSale'
4
+ import { orderStatus, workNodeEnum,
5
+ SERVICETYPE,
6
+ WORKORDER_PROBLEM_CLASSIFICATION,
7
+ workFormMap,
8
+ isSolveOnceMap,
9
+ isOverdueMap
10
+ } from '@/dict/afterSale'
11
+ import { UPLOAD_HOST } from '@/config/app'
12
+ import { formatDateTime } from '@/utils/index'
13
+ import RippleBtn from '@/components/RippleBtn.vue';
14
+ import Timeline from '@/components/Timeline.vue';
15
+ import { useSystemStoreHook } from "@/stores/modules/system";
16
+ import DeviceInfo from './DeviceInfo.vue';
17
+ defineOptions({
18
+ name: "orderDetail"
19
+ });
20
+ interface TimelineItem {
21
+ content: string;
22
+ type: workNodeEnum;
23
+ time?: string; // 可选属性
24
+ }
25
+ const receiveItem = { content: '售后接单', type: workNodeEnum.AFTER_SALES_RECEIVE }
26
+ const finishItem = { content: '工单完结', type: workNodeEnum.FINISH }
27
+ const returnItem = { content: '客户回访', type: workNodeEnum.RETURN_VISIT }
28
+ const state = reactive({
29
+ id: '',
30
+ info: {
31
+ imageList: [] as any[],
32
+ orderStatus: undefined,
33
+ executionMemberList: [],
34
+ workNodeStatus: undefined,
35
+ statusDescription: '',
36
+ responsiblePersonInfo: {
37
+ nickname: ''
38
+ }
39
+ },
40
+ orderNodeVO: {} as any,
41
+ finishNodeVO: {} as any,
42
+ returnNodeVO: {} as any,
43
+ itemData: [] as TimelineItem[],
44
+ })
45
+ const dict = ref(useSystemStoreHook()?.dict);
46
+ const submitText = computed(() => {
47
+ if (state.info.orderStatus === orderStatus.unStart) {
48
+ return '接单'
49
+ }
50
+ return '新增工作记录'
51
+ })
52
+ const executionMemberLabel = computed(() => {
53
+ return state.info?.executionMemberList?.map((item: any) => {
54
+ return item.nickname;
55
+ }).join(', ') || '';
56
+ })
57
+ const formatDictLabel = (value: any, key: any) => {
58
+ const item = dict.value[key]?.find((i: any) => i.dictLabelValue === value);
59
+ return item ? item.dictLabelName : '';
60
+ }
61
+ const formatAryDictLabel = (value: any[], key: any) => {
62
+ return value?.map((item: any) => formatDictLabel(item, key)).join(', ')
63
+ }
64
+ const fetchData = async (id: string) => {
65
+ const res = await getOrderDetail({ id })
66
+ const { imageList, orderNodeVO, finishNodeVO, returnNodeVO, ...other } = res;
67
+ state.info = {
68
+ ...other,
69
+ imageList: (imageList || [])?.map((item: any) => {
70
+ return `${UPLOAD_HOST}${item.attachmentUrl}`;
71
+ }),
72
+ }
73
+ if (orderNodeVO && orderNodeVO !== null) {
74
+ state.orderNodeVO = {
75
+ ...orderNodeVO,
76
+ acceptDate: formatDateTime(orderNodeVO?.acceptDate)
77
+ }
78
+ state.itemData.unshift(receiveItem)
79
+ }
80
+ if (finishNodeVO && finishNodeVO!== null) {
81
+ state.finishNodeVO = {
82
+ ...finishNodeVO,
83
+ workForm: workFormMap[finishNodeVO.workForm],
84
+ arrivalTime: formatDateTime(finishNodeVO?.arrivalTime),
85
+ completionTime: formatDateTime(finishNodeVO?.completionTime),
86
+ materialImageUrlVO: (finishNodeVO.materialImageUrlVO || [])?.map((item: any) => {
87
+ return `${UPLOAD_HOST}${item.attachmentUrl}`;
88
+ }),
89
+ arrivalWatermarkPhotoVO: (finishNodeVO.arrivalWatermarkPhotoVO || [])?.map((item: any) => {
90
+ return `${UPLOAD_HOST}${item.attachmentUrl}`;
91
+ }),
92
+ completionWatermarkPhotoVO: (finishNodeVO.completionWatermarkPhotoVO || [])?.map((item: any) => {
93
+ return `${UPLOAD_HOST}${item.attachmentUrl}`;
94
+ })
95
+ }
96
+ state.itemData.unshift(finishItem)
97
+ }
98
+ if (returnNodeVO && returnNodeVO !== null) {
99
+ state.returnNodeVO = {
100
+ ...returnNodeVO,
101
+ imageListVO: (returnNodeVO?.imageListVO || [])?.map((item: any) => {
102
+ return `${UPLOAD_HOST}${item.attachmentUrl}`;
103
+ }),
104
+ isResolveText: isSolveOnceMap[returnNodeVO?.isResolve],
105
+ isSatisfiedText: isSolveOnceMap[returnNodeVO?.isSatisfied],
106
+ isOverdueText: isOverdueMap[returnNodeVO?.isOverdue],
107
+ }
108
+ state.itemData.unshift(returnItem)
109
+ }
110
+ }
111
+ onLoad((event: any) => {
112
+ const { orderId } = event;
113
+ if (orderId) {
114
+ state.id = orderId;
115
+ fetchData(orderId)
116
+ uni.$on('orderDetail-updated', () => {
117
+ fetchData(orderId); // 刷新数据
118
+ });
119
+ }
120
+ useSystemStoreHook().getDictList(SERVICETYPE);
121
+ useSystemStoreHook().getDictList(WORKORDER_PROBLEM_CLASSIFICATION);
122
+ });
123
+ const toHandleOrder = () => {
124
+ const { orderStatus: status, workNodeStatus } = state.info;
125
+ if (status === orderStatus.unStart) {
126
+ handleOrder({ id: state.id }).then((res: boolean) => {
127
+ if (res) {
128
+ uni.showToast({ title: '接单成功' })
129
+ fetchData(state.id)
130
+ }
131
+ })
132
+ return;
133
+ }
134
+ if (workNodeStatus === workNodeEnum.AFTER_SALES_RECEIVE) {
135
+ uni.redirectTo({ url: `/pages/afterSale/orderFinish?orderId=${state.id}&workNodeStatus=${workNodeStatus + 1}` })
136
+ }
137
+ if (workNodeStatus === workNodeEnum.FINISH) {
138
+ uni.redirectTo({ url: `/pages/afterSale/returnVisit?orderId=${state.id}&workNodeStatus=${workNodeStatus + 1}` })
139
+ }
140
+ }
141
+ const handlePreview = (list: [], index: number) => {
142
+ if (!list || list.length === 0) {
143
+ return;
144
+ }
145
+ uni.previewImage({
146
+ current: index, // 当前显示图片的索引
147
+ urls: list, // 需要预览的图片链接列表
148
+ indicator: 'number', // 显示页码指示器
149
+ loop: false // 不循环预览
150
+ })
151
+ }
152
+ </script>
153
+
154
+ <template>
155
+ <view class="content">
156
+ <view class="info-box">
157
+ <DeviceInfo :data="state.info" />
158
+ <view class="des">现状描述:{{ state.info?.statusDescription }}</view>
159
+ <view class="text">故障图片:</view>
160
+ <view class="img-box">
161
+ <img v-for="(item, index) in state.info.imageList" :key="item" class="img" :src="item"
162
+ @click="handlePreview(state.info.imageList, index)"/>
163
+ </view>
164
+ <view class="label">执行负责人:{{ state.info?.responsiblePersonInfo?.nickname }}</view>
165
+ <view class="label">执行成员:{{ executionMemberLabel }}</view>
166
+ </view>
167
+ <view class="record-box" v-if="state.itemData?.length > 0">
168
+ <Timeline :items="state.itemData">
169
+ <template #content="{ item, index }">
170
+ <view class="title">{{ item.content }}</view>
171
+ <view v-if="item.type === workNodeEnum.FINISH" class="finish-box">
172
+ <view class="text">服务类型:{{ formatDictLabel(state.finishNodeVO?.serviceType, SERVICETYPE) }}</view>
173
+ <view class="text">工作形式:{{ state.finishNodeVO?.workForm }}</view>
174
+ <view class="text">到场时间:{{ state.finishNodeVO?.arrivalTime }}</view>
175
+ <view class="text">故障问题分析:{{ state.finishNodeVO?.problemsAnalysis }}</view>
176
+ <view class="text">工单问题归类:
177
+ {{ formatAryDictLabel(state.finishNodeVO?.workOrderProblemClassification, WORKORDER_PROBLEM_CLASSIFICATION) }}</view>
178
+ <view class="text">领用物料:</view>
179
+ <view class="img-box" v-if="state.finishNodeVO?.materialImageUrlVO">
180
+ <img v-for="(img, index) in state.finishNodeVO.materialImageUrlVO"
181
+ :key="img"
182
+ class="img" :src="img"
183
+ @click="handlePreview(state.finishNodeVO.materialImageUrlVO?.map(i => ({attachmentUrl: i})), index)"
184
+ />
185
+ </view>
186
+ <view class="text">领用物料备注:{{ state.finishNodeVO?.materialsReceived }}</view>
187
+ <view class="text">处理完结时间:{{ state.finishNodeVO?.completionTime }}</view>
188
+ <view class="text">一次性解决:{{ isSolveOnceMap[state.finishNodeVO?.isSolveOnce] }}</view>
189
+ <view class="text">到场水印照片:</view>
190
+ <view class="img-box" v-if="state.finishNodeVO?.arrivalWatermarkPhotoVO">
191
+ <img v-for="(img, index) in state.finishNodeVO.arrivalWatermarkPhotoVO"
192
+ :key="img" class="img" :src="img"
193
+ @click="handlePreview(state.finishNodeVO.arrivalWatermarkPhotoVO, index)"
194
+ />
195
+ </view>
196
+ <view class="text">处理完结水印照片:</view>
197
+ <view class="img-box" v-if="state.finishNodeVO?.completionWatermarkPhotoVO">
198
+ <img v-for="(img, index) in state.finishNodeVO.completionWatermarkPhotoVO"
199
+ :key="img" class="img" :src="img"
200
+ @click="handlePreview(state.finishNodeVO.completionWatermarkPhotoVO, index)"
201
+ />
202
+ </view>
203
+ <view class="text">提交时间:{{ state.finishNodeVO?.createTime }}</view>
204
+ </view>
205
+ <view v-if="item.type === workNodeEnum.RETURN_VISIT" class="finish-box">
206
+ <view class="text">问题解决:{{ state.returnNodeVO?.isResolveText }}</view>
207
+ <view class="text">客户满意:{{ state.returnNodeVO?.isSatisfiedText }}</view>
208
+ <view class="text">是否超期:{{ state.returnNodeVO?.isOverdueText }}</view>
209
+ <view class="text">备注:{{ state.returnNodeVO?.remark }}</view>
210
+ <view class="text">附件图片:</view>
211
+ <view class="img-box" v-if="state.returnNodeVO?.imageListVO">
212
+ <img v-for="(img, index) in state.returnNodeVO?.imageListVO"
213
+ :key="img" class="img" :src="img"
214
+ @click="handlePreview(state.returnNodeVO?.imageListVO, index)"
215
+ />
216
+ </view>
217
+ <view class="text">提交时间:{{ state.returnNodeVO?.createTime }}</view>
218
+ </view>
219
+ <view v-if="item.type === workNodeEnum.AFTER_SALES_RECEIVE" class="finish-box">
220
+ <view class="text">时间:{{ state.orderNodeVO?.acceptDate }}</view>
221
+ </view>
222
+ </template>
223
+ </Timeline>
224
+ </view>
225
+ <view class="footer" v-if="state.info.workNodeStatus !== workNodeEnum.RETURN_VISIT">
226
+ <RippleBtn @click="toHandleOrder" :customStyle="'padding-bottom: 10rpx'">
227
+ <view class="submit-btn">{{submitText}}</view>
228
+ </RippleBtn>
229
+ </view>
230
+ </view>
231
+ </template>
232
+ <style scoped lang="less">
233
+ .content {
234
+ padding-bottom: 120rpx;
235
+ background-color: #F5F5F5;
236
+ min-height: 100vh;
237
+
238
+ .info-box {
239
+ margin-bottom: 32rpx;
240
+ padding: 48rpx;
241
+ background-color: #fff;
242
+ }
243
+
244
+ .des {
245
+ margin-top: 48rpx;
246
+ margin-bottom: 16rpx;
247
+ font-size: 28rpx;
248
+ line-height: 40rpx;
249
+ }
250
+
251
+ .label {
252
+ margin-top: 16rpx;
253
+ font-size: 28rpx;
254
+ line-height: 40rpx;
255
+ }
256
+
257
+ .img-box {
258
+ display: flex;
259
+ flex-wrap: wrap;
260
+ padding-left: 48rpx;
261
+ padding-bottom: 16rpx;
262
+ .img {
263
+ margin-right: 16rpx;
264
+ margin-bottom: 16rpx;
265
+ width: 176rpx;
266
+ height: 176rpx;
267
+ background: #f1f1f1;
268
+ border-radius: 8rpx;
269
+ }
270
+ }
271
+ .title {
272
+ margin-bottom: 16rpx;
273
+ font-weight: bold;
274
+ font-size: 28rpx;
275
+ color: #000000;
276
+ line-height: 40rpx;
277
+ }
278
+ .text {
279
+ margin-bottom: 16rpx;
280
+ font-size: 28rpx;
281
+ color: #000000;
282
+ line-height: 40rpx;
283
+ }
284
+
285
+ .time-desc {
286
+ margin-top: 16rpx;
287
+ margin-left: 36rpx;
288
+ font-size: 28rpx;
289
+ color: rgba(0, 0, 0, 0.4);
290
+ line-height: 40rpx;
291
+ }
292
+ .record-box {
293
+ padding: 48rpx;
294
+ background-color: #fff;
295
+ }
296
+ }
297
+
298
+ .ripple {
299
+ margin-top: 10rpx;
300
+ margin-right: 16rpx;
301
+ width: 20rpx;
302
+ height: 20rpx;
303
+ background: #1D6FE9;
304
+ opacity: 0.9;
305
+ border-radius: 50%;
306
+ }
307
+
308
+ .footer {
309
+ display: flex;
310
+ justify-content: center;
311
+ margin-top: 334rpx;
312
+ }
313
+
314
+ .submit-btn {
315
+ box-sizing: border-box;
316
+ width: 686rpx;
317
+ padding: 24rpx 0 26rpx 0;
318
+ line-height: 58rpx;
319
+ font-family: Source Han Sans SC, Source Han Sans SC;
320
+ font-weight: 600;
321
+ font-size: 40rpx;
322
+ color: rgba(255, 255, 255, 0.9);
323
+ background: linear-gradient(270deg, #1D9DE9 0%, #1D6FE9 100%);
324
+ box-shadow: 0px 16rpx 16rpx 2rpx rgba(29, 157, 233, 0.1);
325
+ border-radius: 52rpx;
326
+ }
327
+ </style>