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,305 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { workStatus, workStatus as workStatusEnum } from '@/dict/afterSale'
4
+ import { getOrderList } from '@/api/afterSale'
5
+ import { throttle } from 'lodash-es';
6
+ import DeviceInfo from './DeviceInfo.vue';
7
+ import Skeleton from '@/components/Skeleton.vue';
8
+ import LoadingView from '@/components/Loading.vue';
9
+ import Empty from '@/components/Empty.vue';
10
+ defineOptions({
11
+ name: "orderList"
12
+ });
13
+ const acticveTab = ref(workStatusEnum.uncomplete)
14
+ const orderTabList = [
15
+ {
16
+ name: '工单未完结',
17
+ value: workStatusEnum.uncomplete,
18
+ num: 10
19
+ },
20
+ {
21
+ name: '工单已完结',
22
+ value: workStatusEnum.complete,
23
+ num: 100
24
+ }
25
+ ]
26
+ const currentIndex = ref(0);
27
+ const state = reactive({
28
+ itemDatas: [],
29
+ current: 1,
30
+ size: 5,
31
+ loadMore: false,
32
+ hasMore: true,
33
+ screenHeight: uni.getSystemInfoSync().windowHeight,
34
+ triggerRatio: 0.3, // 设置触发比例为屏幕高度的30%
35
+ total: 0,
36
+ hasSearch: false, // 是否有搜索过
37
+ scrollTop: 0, // 滚动距离
38
+ oldScrollTop: 0, // 上一次滚动距离
39
+ });
40
+ const completeState = reactive({
41
+ itemDatas: [],
42
+ current: 1,
43
+ size: 5,
44
+ loadMore: false,
45
+ screenHeight: uni.getSystemInfoSync().windowHeight,
46
+ triggerRatio: 0.3, // 设置触发比例为屏幕高度的30%
47
+ hasMore: true,
48
+ total: 0,
49
+ hasSearch: false, // 是否有搜索过
50
+ scrollTop: 0, // 滚动距离
51
+ oldScrollTop: 0, // 上一次滚动距离
52
+ });
53
+ const handleSwiperChange = (value: {
54
+ detail: {
55
+ current: number;
56
+ source: string;
57
+ }
58
+ }) => {
59
+ const { detail } = value;
60
+ acticveTab.value = detail.current + 1;
61
+ }
62
+ const handleTabChange = (value: number) => {
63
+ acticveTab.value = value;
64
+ currentIndex.value = value - 1;
65
+ }
66
+ const loadData = async (page?: number) => {
67
+ if (state.loadMore) return;
68
+ state.loadMore = true;
69
+ const { records, current, total } = await getOrderList({
70
+ size: state.size,
71
+ current: page || state.current,
72
+ status: workStatusEnum.uncomplete,
73
+ });
74
+ state.loadMore = false;
75
+ if (!records) {
76
+ return
77
+ }
78
+ const newData = records.map((item) => {
79
+ return { ...item, show: true };
80
+ });
81
+ if (page === 1) {
82
+ state.itemDatas = newData;
83
+ } else {
84
+ state.itemDatas = [...state.itemDatas,...newData];
85
+ }
86
+ state.current = current;
87
+ state.hasMore = records.length > 0;
88
+ state.total = total;
89
+ if (!state.hasSearch) {
90
+ state.hasSearch = true;
91
+ }
92
+ }
93
+ const loadCompleteData = async (page?: number) => {
94
+ if (completeState.loadMore) return;
95
+ completeState.loadMore = true;
96
+ try {
97
+ const { records, current, total } = await getOrderList({
98
+ size: completeState.size,
99
+ current: page || completeState.current,
100
+ status: workStatusEnum.complete,
101
+ });
102
+ const newData = records.map((item) => {
103
+ return { ...item, show: true };
104
+ });
105
+ if (page === 1) {
106
+ completeState.itemDatas = newData;
107
+ } else {
108
+ completeState.itemDatas = [...completeState.itemDatas,...newData];
109
+ }
110
+ completeState.current = current;
111
+ completeState.hasMore = records.length > 0;
112
+ completeState.total = total;
113
+ if (!completeState.hasSearch) {
114
+ completeState.hasSearch = true;
115
+ }
116
+ } catch (error) {
117
+ console.error('获取数据失败', error);
118
+ }
119
+ completeState.loadMore = false;
120
+ }
121
+ // 滚动到底部加载更多
122
+ const onScrollToLower = throttle(() => {
123
+ if (!state.loadMore && state.hasMore) {
124
+ state.current++;
125
+ nextTick(() => {
126
+ loadData(state.current);
127
+ })
128
+ }
129
+ }, 500);
130
+ const onCompleteScrollToLower = throttle(() => {
131
+ if (!completeState.loadMore && completeState.hasMore) {
132
+ completeState.current++;
133
+ nextTick(() => {
134
+ loadCompleteData(completeState.current);
135
+ })
136
+ }
137
+ }, 500);
138
+ const scroll = (e: any) => {
139
+ state.oldScrollTop = e.detail.scrollTop; // 更新滚动距离
140
+ }
141
+ onShow(() => {
142
+ loadData(1); // 刷新数据
143
+ loadCompleteData(1); // 刷新数据
144
+ state.scrollTop = state.oldScrollTop; // 恢复滚动距离
145
+ completeState.scrollTop = completeState.oldScrollTop; // 恢复滚动距离
146
+ nextTick(() => {
147
+ state.scrollTop = 0;
148
+ completeState.scrollTop = 0;
149
+ })
150
+ })
151
+ </script>
152
+
153
+ <template>
154
+ <view class="content">
155
+ <view class="header">
156
+ <view class="tabList">
157
+ <view v-for="item in orderTabList" :key="item.value" class="tabItem" @click="handleTabChange(item.value)"
158
+ :class="{ 'active': item.value === acticveTab }">
159
+ {{ `${item.name}(${item.value === workStatusEnum.uncomplete ? state.total : completeState.total})` }}
160
+ </view>
161
+ </view>
162
+ </view>
163
+ <swiper
164
+ :current="currentIndex"
165
+ @change="handleSwiperChange"
166
+ class="swiper"
167
+ >
168
+ <swiper-item v-for="(oitem) in orderTabList" :key="oitem.value">
169
+ <view class="container">
170
+ <scroll-view v-if="oitem.value === workStatusEnum.uncomplete" class="scroll-view"
171
+ scroll-y style="height: 100vh;"
172
+ :scroll-top="state.scrollTop" @scroll="scroll"
173
+ bounces show-scrollbar scroll-with-animation @scrolltolower="onScrollToLower"
174
+ :lower-threshold="`${state.screenHeight * state.triggerRatio}`">
175
+ <view class="scroll-box">
176
+ <view class="skeleton-box" v-if="!state.hasSearch">
177
+ <Skeleton class="skeleton-container"></Skeleton>
178
+ <Skeleton class="skeleton-container"></Skeleton>
179
+ <Skeleton class="skeleton-container"></Skeleton>
180
+ </view>
181
+ <view class="record-box" v-for="item in state.itemDatas" :key="item.id">
182
+ <DeviceInfo :data="item" />
183
+ </view>
184
+ <Empty v-if="state.itemDatas.length === 0 && state.hasSearch" />
185
+ <LoadingView v-if="state.loadMore" class="loading-indicator" :size="50"></LoadingView>
186
+ <view v-if="state.itemDatas.length > 0 && !state.hasMore" class="noMore">没有更多数据了</view>
187
+ </view>
188
+ </scroll-view>
189
+ <scroll-view v-else scroll-y style="height: 100vh;" bounces show-scrollbar scroll-with-animation
190
+ @scrolltolower="onCompleteScrollToLower" :scroll-top="completeState.scrollTop"
191
+ :lower-threshold="`${completeState.screenHeight * completeState.triggerRatio}`"
192
+ @scroll="(e) => completeState.oldScrollTop = e.detail.scrollTop"
193
+ >
194
+ <view class="scroll-box">
195
+ <view class="skeleton-box" v-if="!completeState.hasSearch">
196
+ <Skeleton class="skeleton-container"></Skeleton>
197
+ <Skeleton class="skeleton-container"></Skeleton>
198
+ <Skeleton class="skeleton-container"></Skeleton>
199
+ </view>
200
+ <view class="record-box" v-for="item in completeState.itemDatas" :key="item.id">
201
+ <DeviceInfo :data="item" />
202
+ </view>
203
+ <Empty v-if="completeState.itemDatas.length === 0 && completeState.hasSearch" />
204
+ <LoadingView v-if="completeState.loadMore" class="loading-indicator" :size="50"></LoadingView>
205
+ <view v-if="completeState.itemDatas.length > 0 && !completeState.hasMore" class="noMore">没有更多数据了</view>
206
+ </view>
207
+ </scroll-view>
208
+ </view>
209
+ </swiper-item>
210
+ </swiper>
211
+ </view>
212
+ </template>
213
+ <style scoped lang="less">
214
+ .content {
215
+ background-color: #F5F5F5;
216
+ min-height: 100vh;
217
+ }
218
+
219
+ .header {
220
+ position: fixed;
221
+ width: 100%;
222
+ padding: 12rpx 32rpx;
223
+ background-color: #fff;
224
+ top: 0rpx;
225
+ left: 0;
226
+ z-index: 100;
227
+
228
+ .tabList {
229
+ display: flex;
230
+ border-radius: 16rpx;
231
+ border: 1rpx solid #1D6FE9; // 选中状态的边框颜色;
232
+ overflow: hidden;
233
+ font-size: 28rpx;
234
+ line-height: 40rpx;
235
+
236
+ .tabItem {
237
+ flex: 1; // 使两个tabItem平分宽度
238
+ text-align: center; // 文字居中
239
+ padding: 16rpx 0; // 添加一些内边距
240
+ border-bottom-color: #1D6FE9;
241
+ color: #1D6FE9; // 选中状态的文字颜色
242
+ padding: 12rpx 0;
243
+
244
+ &.active {
245
+ color: #fff;
246
+ background-color: #1D6FE9;
247
+ }
248
+ }
249
+ }
250
+ }
251
+ .swiper{
252
+ height: 100vh;
253
+ }
254
+ .scroll-box {
255
+ padding: 88rpx 32rpx 32rpx 32rpx;
256
+ box-sizing: border-box;
257
+ }
258
+ .skeleton-box{
259
+ padding-top: 32rpx;
260
+ }
261
+ .record-box {
262
+ margin-top: 32rpx;
263
+ background-color: #fff;
264
+ border-radius: 16rpx;
265
+ padding: 32rpx;
266
+ position: relative;
267
+ .device-box {
268
+ padding: 16rpx 16rpx 24rpx 16rpx;
269
+ background-color: rgba(0, 0, 0, 0.05);
270
+
271
+ .deviceName {
272
+ margin-bottom: 16rpx;
273
+ font-size: 28rpx;
274
+ color: #000000;
275
+ line-height: 40rpx;
276
+ }
277
+
278
+ .deviceCode {
279
+ font-size: 28rpx;
280
+ color: rgba(0, 0, 0, 0.4);
281
+ line-height: 34px;
282
+ }
283
+
284
+ .addressInfo {
285
+ display: flex;
286
+ }
287
+
288
+ .address {
289
+ flex: 1;
290
+ width: 380rpx;
291
+ font-size: 28rpx;
292
+ color: #000000;
293
+ line-height: 40rpx;
294
+ }
295
+
296
+ .address-icon {
297
+ width: 48rpx;
298
+ height: 48rpx;
299
+ image-rendering: -webkit-optimize-contrast; /* 优化图片渲染 */
300
+ image-rendering: pixelated; /* 像素化渲染 */
301
+ transform: translateZ(0); /* 开启GPU加速 */
302
+ }
303
+ }
304
+ }
305
+ </style>
@@ -0,0 +1,288 @@
1
+ <script setup lang="ts">
2
+ import { useForm } from '@/hooks/useForm';
3
+ import { reactive } from 'vue';
4
+ import { type ValidationRules } from '@/utils/form';
5
+ import { throttle } from 'lodash-es';
6
+ import RippleBtn from '@/components/RippleBtn.vue';
7
+ import Upload from '@/components/Upload.vue';
8
+ import { FILE_UPLOAD_CONFIG, scrollIdPrefix } from '@/config/app';
9
+ import {
10
+ isReturnVisitEnum as isReturnVisit,
11
+ isSolveOptions,
12
+ isSolveEnum,
13
+ isSatisfiedEnum,
14
+ isOverdueEnum,
15
+ workNodeEnum,
16
+ isSatisfiedOptions,
17
+ isOverdueOptions
18
+ } from "@/dict/afterSale";
19
+ import { type addReturnRecordParams, addReturnRecord } from '@/api/afterSale';
20
+ import { useSystemStoreHook } from "@/stores/modules/system";
21
+ import SinglePick from '@/components/SinglePick.vue';
22
+
23
+ defineOptions({
24
+ name: "returnVisit"
25
+ });
26
+ // 定义校验规则
27
+ const validationRules: ValidationRules<Partial<addReturnRecordParams>> = {
28
+ // isResolve: {
29
+ // required: true,
30
+ // message: '请选择是否解决',
31
+ // },
32
+ }
33
+
34
+ const initialData = {
35
+ isResolve: isSolveEnum.SOLVE,
36
+ isSatisfied: isSatisfiedEnum.SATISFIED,
37
+ isOverdue:isOverdueEnum.NO
38
+ };
39
+
40
+ const focusState = reactive({
41
+ remark: false,
42
+ })
43
+ const { formData, errState, setFormItem, validateForm } = useForm<Omit<addReturnRecordParams, 'id'>>(
44
+ initialData as Omit<addReturnRecordParams, 'id'>,
45
+ validationRules,
46
+ true,
47
+ )
48
+ const dict = ref(useSystemStoreHook()?.dict);
49
+ const state = reactive({
50
+ workNodeStatus: workNodeEnum.RETURN_VISIT,
51
+ id: '',
52
+ })
53
+ const changeValue = (key: keyof Omit<addReturnRecordParams, 'id'>, detail: any) => {
54
+ setFormItem(key, detail.value);
55
+ }
56
+
57
+ const submitForm = throttle(async () => {
58
+ const validate = await validateForm();
59
+ if (!validate) {
60
+ return
61
+ }
62
+ const { imageList, ...other } = formData;
63
+ const res = await addReturnRecord({
64
+ id: parseInt(state.id),
65
+ imageList: imageList?.map((item: any) => item.id),
66
+ ...other,
67
+ })
68
+ if (res) {
69
+ uni.showToast({ title: '提交成功', icon: 'success' })
70
+ setTimeout(() => {
71
+ uni.navigateBack()
72
+ }, 1000)
73
+ uni.$emit('orderDetail-updated');
74
+ }
75
+ }, 1000)
76
+
77
+ onLoad((event: any) => {
78
+ const { orderId, workNodeStatus } = event;
79
+ if (workNodeStatus) {
80
+ state.workNodeStatus = workNodeStatus;
81
+ state.id = orderId;
82
+ }
83
+ });
84
+ onMounted(() => {
85
+
86
+ })
87
+ </script>
88
+
89
+ <template>
90
+ <view class="content">
91
+ <view class="form-content">
92
+ <view class="uni-form-item flex-space">
93
+ <view class="l-label">
94
+ 工作节点
95
+ </view>
96
+ <view class="form-value">客户回访</view>
97
+ </view>
98
+ <view class="uni-form-item flex-space" :id="`${scrollIdPrefix}isResolve`">
99
+ <view class="l-label">
100
+ <view class="flag">*</view>问题解决
101
+ </view>
102
+ <SinglePick class="select-box" :value="formData.isResolve" :range="isSolveOptions"
103
+ value-key="value" label-key="label" showRightIcon placeholder="请选择"
104
+ @change="(v) => changeValue('isResolve', { value: v })" />
105
+ </view>
106
+ <view class="uni-form-item flex-space">
107
+ <view class="l-label">
108
+ <view class="flag">*</view>客户满意
109
+ </view>
110
+ <SinglePick class="select-box" :value="formData.isSatisfied" :range="isSatisfiedOptions"
111
+ value-key="value" label-key="label" showRightIcon placeholder="请选择"
112
+ @change="(v) => changeValue('isSatisfied', { value: v })" />
113
+ </view>
114
+ <view class="uni-form-item flex-space">
115
+ <view class="l-label">
116
+ 是否超期<view class="label-tips">(大于36小时)</view>
117
+ </view>
118
+ <SinglePick class="select-box" :value="formData.isOverdue" :range="isOverdueOptions"
119
+ value-key="value" label-key="label" showRightIcon placeholder="请选择"
120
+ @change="(v) => changeValue('isOverdue', { value: v })" />
121
+ </view>
122
+ </view>
123
+ <view class="form-content">
124
+ <view class="l-label">
125
+ 备注
126
+ </view>
127
+ <textarea class="uni-textarea" placeholder="请填写" :value="formData.remark" maxlength="1000"
128
+ @input="(e: any) => changeValue('remark', e.detail)" @focus="focusState.remark = true"
129
+ @blur="focusState.remark = false" placeholder-class="holderClass" />
130
+ <view class="annotation">{{ formData.remark?.length || 0 }}/1000</view>
131
+ <view class="err-text" v-if="errState.remark">{{ errState.remark }}</view>
132
+ </view>
133
+ <view class="form-content">
134
+ <view class="uni-form-item flex-space flex-col">
135
+ <view class="l-label">附件图片</view>
136
+ <upload class="upload-box" :files="formData.imageList" :maxCount="9" :showUpload="true" :size="176"
137
+ :moduleName="FILE_UPLOAD_CONFIG.after_order.moduleName"
138
+ @change="(files: any) => changeValue('imageList', { value: files })" />
139
+ <view class="err-text" v-if="errState.imageList">{{ errState.imageList }}</view>
140
+ </view>
141
+ </view>
142
+ <RippleBtn @click="submitForm" :customStyle="'margin-top: 50rpx;padding-bottom: 10rpx'">
143
+ <view class="submit-btn">提交</view>
144
+ </RippleBtn>
145
+ </view>
146
+ </img>
147
+ </template>
148
+
149
+ <style scoped>
150
+ .content {
151
+ background-color: #F5F5F5;
152
+ min-height: 100vh;
153
+ padding: 32rpx;
154
+
155
+ .form-content {
156
+ margin-bottom: 32rpx;
157
+ background-color: #fff;
158
+ border-radius: 16rpx;
159
+ padding: 0 32rpx;
160
+ position: relative;
161
+ }
162
+
163
+ .form-value {
164
+ margin-right: 24rpx;
165
+ }
166
+
167
+ .uni-form-item {
168
+ display: flex;
169
+ }
170
+
171
+ .flex-space {
172
+ display: flex;
173
+ justify-content: space-between;
174
+ align-items: center;
175
+ color: rgba(0, 0, 0, 0.6);
176
+
177
+ &:not(:last-child) {
178
+ border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
179
+ }
180
+ }
181
+
182
+ .l-label {
183
+ display: flex;
184
+ align-items: center;
185
+ padding: 32rpx 0;
186
+ font-size: 32rpx;
187
+ color: rgba(0, 0, 0, 0.6);
188
+ line-height: 48rpx;
189
+
190
+ .flag {
191
+ font-size: 32rpx;
192
+ color: #E34D59;
193
+ line-height: 38rpx;
194
+ }
195
+ .label-tips {
196
+ margin-left: 4rpx;
197
+ font-size: 20rpx;
198
+ color: rgba(0, 0, 0, 0.5);
199
+ align-self: flex-end;
200
+ }
201
+ }
202
+
203
+ .annotation {
204
+ position: absolute;
205
+ bottom: 32rpx;
206
+ right: 32rpx;
207
+ font-weight: 400;
208
+ font-size: 24rpx;
209
+ color: rgba(0, 0, 0, 0.26);
210
+ line-height: 28rpx;
211
+ text-align: right;
212
+ }
213
+
214
+ .flex-col {
215
+ flex-direction: column;
216
+ align-items: flex-start;
217
+ }
218
+
219
+ .uni-textarea {
220
+ width: 100%;
221
+ line-height: 48rpx;
222
+ height: 288rpx;
223
+ font-size: 28rpx;
224
+ }
225
+
226
+ .select-box {
227
+ /* 确保SinglePick组件内的容器占满剩余空间 */
228
+ flex: 1;
229
+ min-width: 0;
230
+ /* 防止内容溢出 */
231
+ }
232
+
233
+ .upload-box {
234
+ display: flex;
235
+ flex-wrap: wrap;
236
+ gap: 20rpx;
237
+ padding-bottom: 32rpx;
238
+ .view-img {
239
+ width: 176rpx;
240
+ height: 176rpx;
241
+ }
242
+ }
243
+
244
+ .common-picker {
245
+ flex: 1;
246
+ text-align: right;
247
+ }
248
+
249
+ .dateSelect-box {
250
+ display: flex;
251
+ align-items: center;
252
+ flex-direction: row-reverse;
253
+ }
254
+
255
+ .right-icon {
256
+ margin-left: 16rpx;
257
+ width: 32rpx;
258
+ height: 32rpx;
259
+ text-align: right;
260
+ }
261
+
262
+ .err-text {
263
+ margin-top: 8rpx;
264
+ padding-left: 16rpx;
265
+ padding-bottom: 12rpx;
266
+ font-size: 24rpx;
267
+ color: rgb(250, 100, 100);
268
+ }
269
+
270
+ .submit-btn {
271
+ box-sizing: border-box;
272
+ width: 686rpx;
273
+ padding: 24rpx 0 26rpx 0;
274
+ line-height: 58rpx;
275
+ font-family: Source Han Sans SC, Source Han Sans SC;
276
+ font-weight: 400;
277
+ font-size: 40rpx;
278
+ color: rgba(255, 255, 255, 0.9);
279
+ background: linear-gradient(270deg, #1D9DE9 0%, #1D6FE9 100%);
280
+ box-shadow: 0px 16rpx 16rpx 2rpx rgba(29, 157, 233, 0.1);
281
+ border-radius: 52rpx;
282
+ }
283
+ }
284
+ .holderClass{
285
+ font-size: 28rpx;
286
+ color: rgba(0,0,0,0.2);
287
+ }
288
+ </style>