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,409 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { type addAcceptanceParams, addRecord } from '@/api/installtion';
4
+ import { type ValidationRules } from '@/utils/form';
5
+ import { acceptanceStatusEnum, installWorkNodeEnum, installWorkNodeMap } from '@/dict/installtion';
6
+ import { useForm } from '@/hooks/useForm';
7
+ import SinglePick from '@/components/SinglePick.vue';
8
+ import Upload from '@/components/Upload.vue';
9
+ import { isArray } from 'lodash-es';
10
+ import RippleBtn from '@/components/RippleBtn.vue';
11
+ import { FILE_UPLOAD_CONFIG, scrollIdPrefix } from '@/config/app';
12
+ import { queryDeviceDetail } from '@/api/device';
13
+ import { DeviceMesStatusEnum } from '@/dict/device';
14
+ defineOptions({
15
+ name: "addAcceptance"
16
+ });
17
+ // 定义校验规则
18
+ const validationRules: ValidationRules<Partial<addAcceptanceParams>> = {
19
+ description: {
20
+ required: true,
21
+ message: '请填写记录说明',
22
+ },
23
+ status: {
24
+ required: true,
25
+ message: '请选择状态',
26
+ },
27
+ imageList: { required: false, validatFunc: (d): any => {
28
+ return new Promise((resolve, reject) => {
29
+ if(isArray(d) && d.length > 0) {
30
+ resolve(true)
31
+ } else {
32
+ reject('请上传至少一张图片')
33
+ }
34
+ })
35
+ }, message: '请上传至少一张图片' },
36
+ }
37
+
38
+ const initialData = {
39
+ status: acceptanceStatusEnum.YES
40
+ };
41
+ let timer: number | null = null
42
+ const focusState = reactive({
43
+ description: false,
44
+ })
45
+ const state = reactive({
46
+ deviceId: '',
47
+ workOrderCode: '',
48
+ deviceCode: '',
49
+ location: {
50
+ latitude: 0,
51
+ longitude: 0,
52
+ address: '',
53
+ name: ''
54
+ },
55
+ showLocationTips: false,
56
+ showSiloCodeTips: false, // 料塔编码错误提示
57
+ deviceInfo: {} as any, // 设备详情信息
58
+ })
59
+ const { formData, errState, setFormItem, validateForm } = useForm<Omit<addAcceptanceParams, 'id'>>(
60
+ initialData as Omit<addAcceptanceParams, 'id'>,
61
+ validationRules,
62
+ false,
63
+ )
64
+ const changeValue = (key: keyof Omit<addAcceptanceParams, 'id'>, detail: any) => {
65
+ setFormItem(key, detail.value);
66
+ }
67
+ const getLocation = () => {
68
+ uni.chooseLocation({
69
+ success: (res) => {
70
+ state.location = {
71
+ latitude: res.latitude,
72
+ longitude: res.longitude,
73
+ address: res.address,
74
+ name: res.name
75
+ }
76
+ state.showLocationTips = false;
77
+ },
78
+ fail: (err) => {
79
+ console.log(err);
80
+ uni.showToast({ title: '获取位置失败', icon: 'error' })
81
+ }
82
+ })
83
+ }
84
+
85
+ // 跳转到编辑料塔编码页面
86
+ const toMaterialTowerCode = () => {
87
+ uni.navigateTo({
88
+ url: `/pages/device/materialTowerCode?deviceCode=${state.deviceCode}`
89
+ })
90
+ // 清除错误提示
91
+ state.showSiloCodeTips = false;
92
+ }
93
+
94
+ // 获取设备详情
95
+ const fetchDeviceDetail = async () => {
96
+ if (!state.deviceCode) return;
97
+ try {
98
+ const res = await queryDeviceDetail({ deviceCode: state.deviceCode });
99
+ if (res) {
100
+ state.deviceInfo = res;
101
+ }
102
+ } catch (error) {
103
+ console.error('获取设备详情失败', error);
104
+ }
105
+ }
106
+
107
+ const submitForm = async () => {
108
+ // 先清除所有错误提示
109
+ state.showLocationTips = false;
110
+ state.showSiloCodeTips = false;
111
+
112
+ // 校验设备信息状态
113
+ if (state.deviceInfo?.deviceMesStatus === DeviceMesStatusEnum.PENDING) {
114
+ uni.showToast({
115
+ title: '设备信息未完善,请先完善设备信息后再提交',
116
+ icon: 'none',
117
+ duration: 2000
118
+ })
119
+ return;
120
+ }
121
+
122
+ // 校验表单字段
123
+ const validateResult = await validateForm();
124
+
125
+ // 校验设备定位
126
+ if (!state.location.address) {
127
+ state.showLocationTips = true;
128
+ }
129
+
130
+ // 校验料塔编码必填
131
+ if (!state.deviceInfo?.siloCode) {
132
+ state.showSiloCodeTips = true;
133
+ }
134
+
135
+ // 如果有任何校验失败,直接返回
136
+ if (!validateResult || !state.location.address || !state.deviceInfo?.siloCode) {
137
+ return;
138
+ }
139
+ const res = await addRecord({
140
+ ...formData, planDeviceId: state.deviceId,
141
+ workNodeFlag: installWorkNodeEnum.ACCEPT,
142
+ imageList: formData.imageList?.map((item: any) => item.id) || [],
143
+ deviceLocation: JSON.stringify(state.location),
144
+ workOrderCode: state.workOrderCode,
145
+ deviceCode: state.deviceCode,
146
+ }, {
147
+ permActionName: 'installWorkAcceptance'
148
+ })
149
+ if (res) {
150
+ uni.showToast({ title: '提交成功', icon: 'success' })
151
+ timer = setTimeout(() => {
152
+ uni.navigateBack()
153
+ }, 2000)
154
+ uni.$emit('installtionOrderDetail-updated');
155
+ uni.$emit('orderList-updated');
156
+ }
157
+ }
158
+ onLoad(async (event: any) => {
159
+ const { deviceId, workOrderCode, deviceCode } = event
160
+ state.deviceId = deviceId;
161
+ state.workOrderCode = workOrderCode;
162
+ state.deviceCode = deviceCode;
163
+ // 获取设备详情
164
+ await fetchDeviceDetail();
165
+ })
166
+
167
+ // 监听页面显示,刷新设备信息
168
+ onShow(() => {
169
+ if (state.deviceCode) {
170
+ fetchDeviceDetail();
171
+ // 清除料塔编码错误提示
172
+ state.showSiloCodeTips = false;
173
+ }
174
+ })
175
+ onUnmounted(() => {
176
+ if (timer) {
177
+ clearInterval(timer);
178
+ timer = null;
179
+ }
180
+ })
181
+ </script>
182
+
183
+ <template>
184
+ <view class="content">
185
+ <view class="form-content">
186
+ <view class="uni-form-item flex-space">
187
+ <view class="l-label">
188
+ 工作节点
189
+ </view>
190
+ <view class="form-value">安装验收</view>
191
+ </view>
192
+ <view class="uni-form-item flex-space">
193
+ <view class="l-label">
194
+ 状态
195
+ </view>
196
+ <SinglePick class="select-box" :value="formData.status" :range="[{ label: '正常', value: acceptanceStatusEnum.YES }]"
197
+ disabled value-key="value"
198
+ label-key="label" showRightIcon placeholder="请选择" @change="(v: any) => changeValue('status', { value: v })" />
199
+ </view>
200
+ <view class="err-text" v-if="errState.status">{{ errState.status }}</view>
201
+ </view>
202
+ <view class="form-content" :id="`${scrollIdPrefix}description`">
203
+ <view class="l-label">
204
+ <view class="flag">*</view>记录说明
205
+ </view>
206
+ <textarea class="uni-textarea" placeholder="请填写" :value="formData.description" maxlength="1000"
207
+ @input="(e: any) => changeValue('description', e.detail)" @focus="focusState.description = true"
208
+ @blur="focusState.description = false" placeholder-class="holderClass" />
209
+ <view class="annotation">{{ formData.description?.length || 0 }}/1000</view>
210
+ <view class="err-text" v-if="errState.description">{{ errState.description }}</view>
211
+ </view>
212
+ <view class="form-content">
213
+ <view class="uni-form-item flex-space flex-col">
214
+ <view class="l-label"><view class="flag">*</view>照片上传</view>
215
+ <upload class="upload-box" :files="formData.imageList" :maxCount="6" :showUpload="true" :size="176"
216
+ :moduleName="FILE_UPLOAD_CONFIG.after_order.moduleName"
217
+ @change="(files: any) => changeValue('imageList', { value: files })" />
218
+ <view class="err-text" v-if="errState.imageList">{{ errState.imageList }}</view>
219
+ </view>
220
+ </view>
221
+ <view class="form-content">
222
+ <view class="uni-form-item flex-space">
223
+ <view class="l-label">
224
+ <view class="flag">*</view>设备定位
225
+ </view>
226
+ <view class="form-value" @click="getLocation">
227
+ {{ state.location.address ? `${state.location.address}${state.location.name}` : '点击上传设备位置'}}
228
+ </view>
229
+ </view>
230
+ <view class="err-text" v-if="state.showLocationTips">请定位设备位置</view>
231
+ </view>
232
+ <view class="form-content">
233
+ <view class="section-title">设备信息</view>
234
+ <view class="uni-form-item flex-space" @click="toMaterialTowerCode">
235
+ <view class="l-label">
236
+ <view class="flag">*</view>料塔编码
237
+ </view>
238
+ <view class="form-value-box">
239
+ <view class="form-value">{{ state.deviceInfo?.siloCode || '请选择' }}</view>
240
+ <image class="right-icon" src="/static/img/turn_right.png" />
241
+ </view>
242
+ </view>
243
+ <view class="err-text" v-if="state.showSiloCodeTips">请选择料塔编码</view>
244
+ </view>
245
+ <RippleBtn @click="submitForm" :customStyle="'margin-top: 48rpx;padding-bottom: 10rpx'">
246
+ <view class="submit-btn">保存</view>
247
+ </RippleBtn>
248
+ </view>
249
+ </template>
250
+ <style scoped>
251
+ .content {
252
+ background-color: #F5F5F5;
253
+ min-height: 100vh;
254
+ padding: 32rpx;
255
+
256
+ .form-content {
257
+ margin-bottom: 32rpx;
258
+ background-color: #fff;
259
+ border-radius: 16rpx;
260
+ padding: 0 32rpx;
261
+ position: relative;
262
+ }
263
+
264
+ .form-value {
265
+ margin-right: 24rpx;
266
+ flex: 1;
267
+ text-align: right;
268
+ color: rgba(0, 0, 0, 0.4);
269
+ }
270
+
271
+ .form-value-box {
272
+ display: flex;
273
+ align-items: center;
274
+ flex: 1;
275
+ justify-content: flex-end;
276
+ }
277
+
278
+ .section-title {
279
+ padding: 32rpx 0 24rpx 0;
280
+ font-size: 32rpx;
281
+ font-weight: 500;
282
+ color: #000000;
283
+ line-height: 48rpx;
284
+ }
285
+
286
+ .device-info-link {
287
+ padding: 16rpx 0 32rpx 0;
288
+ font-size: 28rpx;
289
+ color: #1D6FE9;
290
+ line-height: 40rpx;
291
+ text-align: center;
292
+ }
293
+
294
+ .uni-form-item {
295
+ display: flex;
296
+ }
297
+
298
+ .flex-space {
299
+ display: flex;
300
+ justify-content: space-between;
301
+ align-items: center;
302
+ color: rgba(0, 0, 0, 0.6);
303
+
304
+ &:not(:last-child) {
305
+ border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
306
+ }
307
+ }
308
+
309
+ .l-label {
310
+ display: flex;
311
+ align-items: center;
312
+ padding: 32rpx 0;
313
+ font-size: 32rpx;
314
+ color: rgba(0, 0, 0, 0.6);
315
+ line-height: 48rpx;
316
+
317
+ .flag {
318
+ font-size: 32rpx;
319
+ color: #E34D59;
320
+ line-height: 38rpx;
321
+ }
322
+ }
323
+
324
+ .annotation {
325
+ position: absolute;
326
+ bottom: 32rpx;
327
+ right: 32rpx;
328
+ font-weight: 400;
329
+ font-size: 24rpx;
330
+ color: rgba(0, 0, 0, 0.26);
331
+ line-height: 28rpx;
332
+ text-align: right;
333
+ }
334
+
335
+ .flex-col {
336
+ flex-direction: column;
337
+ align-items: flex-start;
338
+ }
339
+
340
+ .uni-textarea {
341
+ width: 100%;
342
+ line-height: 48rpx;
343
+ height: 288rpx;
344
+ font-size: 28rpx;
345
+ }
346
+
347
+ .select-box {
348
+ /* 确保SinglePick组件内的容器占满剩余空间 */
349
+ flex: 1;
350
+ min-width: 0;
351
+ /* 防止内容溢出 */
352
+ }
353
+
354
+ .upload-box {
355
+ display: flex;
356
+ flex-wrap: wrap;
357
+ gap: 20rpx;
358
+ padding-bottom: 32rpx;
359
+
360
+ .view-img {
361
+ width: 176rpx;
362
+ height: 176rpx;
363
+ }
364
+ }
365
+
366
+ .common-picker {
367
+ flex: 1;
368
+ text-align: right;
369
+ }
370
+
371
+ .dateSelect-box {
372
+ display: flex;
373
+ align-items: center;
374
+ flex-direction: row-reverse;
375
+ }
376
+
377
+ .right-icon {
378
+ margin-left: 16rpx;
379
+ width: 32rpx;
380
+ height: 32rpx;
381
+ text-align: right;
382
+ }
383
+
384
+ .err-text {
385
+ padding: 16rpx;
386
+ font-size: 24rpx;
387
+ color: rgb(250, 100, 100);
388
+ }
389
+
390
+ .submit-btn {
391
+ box-sizing: border-box;
392
+ width: 686rpx;
393
+ padding: 24rpx 0 26rpx 0;
394
+ line-height: 58rpx;
395
+ font-family: Source Han Sans SC, Source Han Sans SC;
396
+ font-weight: 400;
397
+ font-size: 40rpx;
398
+ color: rgba(255, 255, 255, 0.9);
399
+ background: linear-gradient(270deg, #1D9DE9 0%, #1D6FE9 100%);
400
+ box-shadow: 0px 16rpx 16rpx 2rpx rgba(29, 157, 233, 0.1);
401
+ border-radius: 52rpx;
402
+ }
403
+ }
404
+
405
+ .holderClass {
406
+ font-size: 28rpx;
407
+ color: rgba(0, 0, 0, 0.25);
408
+ }
409
+ </style>