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,148 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { queryDevicePageList } from '@/api/device'
4
+ import { isCheckStatusEnum } from '@/dict/device'
5
+ import Empty from '@/components/Empty.vue';
6
+ const state = reactive({
7
+ keyword: '',
8
+ itemDatas: [] as any[]
9
+ })
10
+ const handleBack = () => {
11
+ uni.redirectTo({
12
+ url: '/pages/afterSale/faultReport'
13
+ });
14
+ }
15
+ const toReport = (item: any) => {
16
+ uni.redirectTo({
17
+ url: `/pages/afterSale/faultReport?deviceCode=${item.deviceCode}`
18
+ })
19
+ }
20
+ const getCheckedList = async () => {
21
+ const res = await queryDevicePageList({
22
+ size: 1000,
23
+ page: 1,
24
+ deviceCode: state.keyword
25
+ })
26
+ if (res) {
27
+ state.itemDatas = res.records.filter((item: any) => item.isCheckStatus === isCheckStatusEnum.YES)
28
+ }
29
+ }
30
+ </script>
31
+ <template>
32
+ <view class="content">
33
+ <view class="header">
34
+ <view class="input-wrapper">
35
+ <input class="search-input"
36
+ v-model="state.keyword" placeholder="请输入设备编号" @input="getCheckedList" />
37
+ <image class="uni-icon" src="/static/img/search.png" />
38
+ </view>
39
+ <view class="back-icon" @click="handleBack">
40
+ 返回
41
+ </view>
42
+ </view>
43
+ <view class="scroll-view">
44
+ <scroll-view class="scroll-view" :scroll-y="true">
45
+ <view class="search-item" v-for="item in state.itemDatas" :key="item.id" @click="toReport(item)">
46
+ <view class="img"></view>
47
+ <view class="info">
48
+ <view class="inlineBox">
49
+ <view class="code">设备编号:{{item.deviceCode}}</view>
50
+ <view class="contact">客户:{{item.customerName}}</view>
51
+ </view>
52
+ <view class="status" :class="{'unCheck': item.isCheckStatus === isCheckStatusEnum.NO}">
53
+ {{item.isCheckStatus === isCheckStatusEnum.YES ? '已验收' : '未验收'}}
54
+ </view>
55
+ </view>
56
+ </view>
57
+ </scroll-view>
58
+ </view>
59
+ <view v-if="!state.keyword" class="tips">请输入设备号模糊搜索</view>
60
+ <Empty v-else-if="state.itemDatas.length === 0" />
61
+ </view>
62
+ </template>
63
+ <style scoped lang="less">
64
+ .content {
65
+ background-color: #F5F5F5;
66
+ min-height: 100vh;
67
+ }
68
+ .tips{
69
+ font-size: 24rpx;
70
+ color: rgba(0,0,0,0.6);
71
+ padding: 24rpx 0 48rpx 36rpx;
72
+ background-color: #fff;
73
+ }
74
+ .header {
75
+ padding: 12rpx 18rpx;
76
+ background-color: #fff;
77
+ display: flex;
78
+ align-items: center;
79
+ position: relative;
80
+ .input-wrapper{
81
+ flex: 1;
82
+ margin-left: 4rpx;
83
+ padding: 0 24rpx;
84
+ background: rgba(0,0,0,0.04);
85
+ border-radius: 8rpx;
86
+ display: flex;
87
+ align-items: center;
88
+ position: relative;
89
+ }
90
+ .back-icon{
91
+ padding-left: 12rpx;
92
+ font-size: 24rpx;
93
+ color: rgba(0,0,0,0.6);
94
+ }
95
+ .search-input {
96
+ flex: 1;
97
+ font-size: 24rpx;
98
+ padding: 12rpx 0;
99
+ }
100
+ .uni-icon {
101
+ position: absolute;
102
+ right: 16rpx;
103
+ top: 18rpx;
104
+ width: 28rpx;
105
+ height: 28rpx;
106
+ }
107
+ }
108
+ .scroll-box {
109
+ padding: 16rpx 64rpx;
110
+ box-sizing: border-box;
111
+ }
112
+ .searchist, .deviceBox{
113
+ margin-top: 24rpx;
114
+ }
115
+ .info{
116
+ width: 100%;
117
+ display: flex;
118
+ justify-content: space-between;
119
+ align-items: center;
120
+ }
121
+ .inlineBox{
122
+ font-size: 26rpx;
123
+ .code{
124
+ padding-bottom: 16rpx;
125
+ }
126
+ }
127
+ .status{
128
+ color: rgba(0,0,0,0.6);
129
+ font-size: 24rpx;
130
+ }
131
+ .contact {
132
+ font-size: 24rpx;
133
+ color: rgba(0,0,0,0.6);
134
+ }
135
+ .search-item{
136
+ display: flex;
137
+ align-items: flex-end;
138
+ background-color: #fff;
139
+ padding: 18rpx 42rpx;
140
+ font-size: 28rpx;
141
+ margin-bottom: 1rpx;
142
+ color: rgba(0,0,0,0.4);
143
+ .code{
144
+ font-size: 24rpx;
145
+ color: rgba(0,0,0,0.6);
146
+ }
147
+ }
148
+ </style>
@@ -0,0 +1,201 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import DropMenu from '@/components/DropMenu.vue'
4
+ import { isCheckStatusEnum } from '@/dict/device'
5
+ import { debounce } from 'lodash-es';
6
+ import Skeleton from '@/components/Skeleton.vue';
7
+ import LoadingView from '@/components/Loading.vue';
8
+ import Empty from '@/components/Empty.vue';
9
+ import { queryCustomerCode, queryDevicePageList } from '@/api/device'
10
+
11
+ defineOptions({
12
+ name: "searchList"
13
+ });
14
+ const selectedValue = ref('customerCode')
15
+ const state = reactive({
16
+ customerCode: '',
17
+ searchList: [],
18
+ itemDatas: [],
19
+ searchLoading: false,
20
+ deviceLoading: false,
21
+ hasSearch: false, // 是否有搜索过
22
+ searchValue: ''
23
+ });
24
+ const options = [
25
+ { value: 'customerCode', name: '客户名称' },
26
+ { value: 'deviceCode', name: '设备编号' }
27
+ ]
28
+ const toDeviceDetail = (item: any) => {
29
+ uni.navigateTo({ url: `/pages/device/detail?deviceCode=${item.deviceCode}` })
30
+ }
31
+ const searchCustomer = debounce(async (value: string) => {
32
+ state.searchLoading = true;
33
+ state.searchList = [];
34
+ const res = await queryCustomerCode({
35
+ customerName: value, // 假设搜索字段为customerName
36
+ })
37
+ state.searchLoading = false;
38
+ if (!res) {
39
+ return; // 搜索失败时不更新数据
40
+ }
41
+ state.searchList = res;
42
+ })
43
+ const searchDevice = async (value: string) => {
44
+ if (!value) {
45
+ return; // 输入为空时不进行搜索
46
+ }
47
+ state.hasSearch = false;
48
+ state.deviceLoading = true;
49
+ const res = await queryDevicePageList({
50
+ size: 10,
51
+ current: 1,
52
+ customerCode: value, // 假设搜索字段为deviceCode
53
+ })
54
+ state.deviceLoading = false;
55
+ if (!res) {
56
+ return; // 搜索失败时不更新数据
57
+ }
58
+ state.itemDatas = res.records;
59
+ }
60
+ const handleSearchInput = (e: any) => {
61
+ const { value } = e.detail
62
+ if (value === state.searchValue) {
63
+ return; // 输入为空时不进行搜索
64
+ }
65
+ state.searchValue = value; // 更新搜索框的值
66
+ searchCustomer(value); // 刷新数据
67
+ if (!state.hasSearch) {
68
+ state.hasSearch = true; // 标记为已搜索
69
+ }
70
+ }
71
+ onMounted(async () => {
72
+ })
73
+ </script>
74
+
75
+ <template>
76
+ <view class="content">
77
+ <view class="header">
78
+ <DropMenu v-model="selectedValue" :options="options" />
79
+ <view class="input-wrapper">
80
+ <input class="search-input" @change="handleSearchInput" />
81
+ </view>
82
+ <image class="uni-icon" src="/static/img/search.png" />
83
+ </view>
84
+ <view class="searchist" v-if="state.hasSearch">
85
+ <view class="skeleton-box" v-if="state.searchLoading">
86
+ <Skeleton class="skeleton-container"></Skeleton>
87
+ <Skeleton class="skeleton-container"></Skeleton>
88
+ <Skeleton class="skeleton-container"></Skeleton>
89
+ <Skeleton class="skeleton-container"></Skeleton>
90
+ <Skeleton class="skeleton-container"></Skeleton>
91
+ </view>
92
+ <view class="search-item"
93
+ v-else
94
+ v-for="item in state.searchList" :key="item.customerCode"
95
+ @click="searchDevice(item.customerCode)"
96
+ >
97
+ {{ item.customerName }}<view class="code">{{ item.customerCode }}</view>
98
+ </view>
99
+ </view>
100
+ </view>
101
+ </template>
102
+ <style scoped lang="less">
103
+ .content {
104
+ background-color: #F5F5F5;
105
+ min-height: 100vh;
106
+ }
107
+ .header {
108
+ padding: 12rpx 18rpx;
109
+ background-color: #fff;
110
+ display: flex;
111
+ align-items: center;
112
+ position: relative;
113
+ .input-wrapper{
114
+ flex: 1;
115
+ margin-left: 4rpx;
116
+ padding: 0 24rpx;
117
+ background: rgba(0,0,0,0.04);
118
+ border-radius: 8rpx;
119
+ display: flex;
120
+ align-items: center;
121
+ }
122
+ .search-input {
123
+ flex: 1;
124
+ font-size: 24rpx;
125
+ padding: 12rpx 0;
126
+ }
127
+ .uni-icon {
128
+ position: absolute;
129
+ right: 36rpx;
130
+ top: 28rpx;
131
+ width: 36rpx;
132
+ height: 36rpx;
133
+ }
134
+ }
135
+ .scroll-box {
136
+ padding: 16rpx 32rpx;
137
+ box-sizing: border-box;
138
+ }
139
+ .record-box{
140
+ display: flex;
141
+ margin-bottom: 16rpx;
142
+ padding: 36rpx;
143
+ background: #FFFFFF;
144
+ border-radius: 16rpx;
145
+ .img{
146
+ margin-right: 16rpx;
147
+ width: 96rpx;
148
+ height: 96rpx;
149
+ background: #E8E8E8;
150
+ border-radius: 8rpx;
151
+ }
152
+ .inlineBox{
153
+ display: flex;
154
+ margin-bottom: 6rpx;
155
+ .code{
156
+ margin-right: 16rpx;
157
+ font-weight: bold;
158
+ font-size: 32rpx;
159
+ color: #000000;
160
+ line-height: 38rpx;
161
+ }
162
+ .status{
163
+ padding: 6rpx 16rpx 8rpx 16rpx;
164
+ font-weight: 400;
165
+ font-size: 24rpx;
166
+ color: #1D6FE9;
167
+ line-height: 34rpx;
168
+ border-radius: 24rpx;
169
+ background: rgba(29,111,233,0.1);
170
+ border: 1rpx solid #1D6FE9;
171
+ }
172
+ .unCheck {
173
+ color: #F5894E;
174
+ border: 1rpx solid #F5894E;
175
+ background: rgba(245,137,78,0.1);
176
+ }
177
+ }
178
+ .contact{
179
+ font-size: 28rpx;
180
+ color: rgba(0,0,0, 0.6);
181
+ line-height: 40rpx;
182
+ }
183
+ }
184
+ .searchist, .deviceBox{
185
+ margin-top: 24rpx;
186
+ }
187
+ .search-item{
188
+ display: flex;
189
+ align-items: flex-end;
190
+ background-color: #fff;
191
+ padding: 18rpx 16rpx 18rpx 42rpx;
192
+ font-size: 28rpx;
193
+ margin-bottom: 1rpx;
194
+ color: rgba(0,0,0,0.6);
195
+ .code{
196
+ margin-left: 24rpx;
197
+ font-size: 24rpx;
198
+ color: rgba(0,0,0,0.4);
199
+ }
200
+ }
201
+ </style>
@@ -0,0 +1,270 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { useForm } from '@/hooks/useForm';
4
+ import { queryDeviceDetail, type DeviceCheckParams, deviceCheck } from '@/api/device'
5
+ import { FILE_UPLOAD_CONFIG, UPLOAD_HOST } from '@/config/app';
6
+ import Skeleton from '@/components/Skeleton.vue';
7
+ import { useUserStore } from '@/stores/modules/user';
8
+ import { type ValidationRules } from '@/utils/form';
9
+ import Upload from '@/components/Upload.vue';
10
+ import RippleBtn from '@/components/RippleBtn.vue';
11
+ import { isCheckStatusEnum } from '@/dict/device'
12
+
13
+ defineOptions({
14
+ name: "deviceAcceptance"
15
+ });
16
+
17
+ const initialData = {
18
+ customerCheckDate: '',
19
+ };
20
+
21
+ const validationRules: ValidationRules<Partial<DeviceCheckParams>> = {
22
+ customerCheckDate: {
23
+ required: true,
24
+ message: '请选择验收时间',
25
+ },
26
+ }
27
+
28
+ const { formData, errState, setFormItem, validateForm, validateOneField, initialForm } = useForm<Omit<DeviceCheckParams, 'deviceCode'>>(
29
+ initialData as Omit<DeviceCheckParams, 'deviceCode'>,
30
+ validationRules,
31
+ false,
32
+ )
33
+ const useStore = useUserStore();
34
+ const state = reactive({
35
+ info: {} as any,
36
+ loading: false,
37
+ lockCustomerCheckDate: false
38
+ })
39
+ const changeValue = (key: keyof Omit<DeviceCheckParams, 'deviceCode'>, detail: any) => {
40
+ setFormItem(key, detail.value);
41
+ }
42
+ const fetchDetail = async (code: string) => {
43
+ state.loading = true;
44
+ const res = await queryDeviceDetail({
45
+ deviceCode: code,
46
+ });
47
+ state.loading = false;
48
+ if (res) {
49
+ const { attachmentList, ...other } = res
50
+ // 是否验收,如果是已验收,禁止修改验收时间
51
+ state.lockCustomerCheckDate = !!other.customerCheckDate;
52
+ initialForm({
53
+ ...other,
54
+ customerCheckAttachments: attachmentList?.map((item: any) => ({
55
+ id: item.attachmentId,
56
+ attachmentUrl: UPLOAD_HOST + item.attachmentUrl,
57
+ })) || [],
58
+ })
59
+ state.info = res;
60
+ }
61
+ }
62
+ const submitForm= async () => {
63
+ const isValid = await validateForm();
64
+ if (!isValid) {
65
+ return;
66
+ }
67
+ const params = {
68
+ ...formData,
69
+ customerCheckAttachments: formData.customerCheckAttachments?.map((item: any) => item.id) || [],
70
+ deviceCode: state.info.deviceCode,
71
+ customerCheckBy: 1
72
+ }
73
+ const res = await deviceCheck(params);
74
+ if (res) {
75
+ uni.showToast({
76
+ title: '提交成功',
77
+ icon: 'success',
78
+ duration: 2000,
79
+ success: () => {
80
+ uni.$emit('deviceList-updated');
81
+ uni.$emit('deviceList-updated-success');
82
+ setTimeout(() => {
83
+ uni.navigateBack();
84
+ }, 2000);
85
+ }
86
+ });
87
+ }
88
+ }
89
+ onLoad((event: any) => {
90
+ const { deviceCode } = event;
91
+ fetchDetail(deviceCode);
92
+ });
93
+ </script>
94
+
95
+ <template>
96
+ <view class="content" :style="{padding: '36rpx'}">
97
+ <view class="skeleton-box" v-if="state.loading">
98
+ <Skeleton class="skeleton-container"></Skeleton>
99
+ <Skeleton class="skeleton-container"></Skeleton>
100
+ <Skeleton class="skeleton-container"></Skeleton>
101
+ <Skeleton class="skeleton-container"></Skeleton>
102
+ <Skeleton class="skeleton-container"></Skeleton>
103
+ </view>
104
+ <view v-else class="form-box">
105
+ <view class="text">产品名称:{{ state.info.productName }}</view>
106
+ <view class="text">设备编码:{{ state.info.deviceCode }}</view>
107
+ <view class="text">所属用户:{{ state.info.customerName }}</view>
108
+ <view class="text">设备地址:{{ state.info.address || '--'}}</view>
109
+ </view>
110
+ <view class="form-content">
111
+ <view class="uni-form-item flex-space">
112
+ <view class="l-label">验收人</view>
113
+ <view class="text">{{ useStore.getUserInfo?.nickname }}</view>
114
+ </view>
115
+ <view class="uni-form-item flex-space">
116
+ <view class="l-label">
117
+ <view class="flag">*</view>客户验收时间
118
+ </view>
119
+ <view class="dateSelect-box">
120
+ <div v-if="state.lockCustomerCheckDate">{{ formData.customerCheckDate }}</div>
121
+ <image v-else class="right-icon" src="/static/img/turn_right.png" />
122
+ <uni-datetime-picker v-model="formData.customerCheckDate" v-if="!state.lockCustomerCheckDate"
123
+ @change="(v: string) => changeValue('customerCheckDate', { value: v })">
124
+ <view class="common-picker">{{ formData.customerCheckDate || '请选择' }}</view>
125
+ </uni-datetime-picker>
126
+ </view>
127
+ </view>
128
+ <view class="err-text" v-if="errState.customerCheckDate">{{errState.customerCheckDate}}</view>
129
+ </view>
130
+ <view class="form-content">
131
+ <view class="l-label">备注</view>
132
+ <textarea class="uni-textarea" placeholder="请填写" :value="formData.customerCheckMemo" maxlength="1000"
133
+ @input="(e: any) => changeValue('customerCheckMemo', e.detail)" placeholder-class="holderClass" />
134
+ <view class="annotation">{{ formData.customerCheckMemo?.length || 0 }}/1000</view>
135
+ </view>
136
+ <view class="form-content">
137
+ <view class="flex-space flex-col">
138
+ <view class="l-label">处理完结水印照片</view>
139
+ <upload class="upload-box" :files="formData.customerCheckAttachments" :maxCount="9" :showUpload="true" :size="176"
140
+ :moduleName="FILE_UPLOAD_CONFIG.after_order.moduleName"
141
+ @change="(files: any) => changeValue('customerCheckAttachments', { value: files })" />
142
+ <view class="err-text" v-if="errState.customerCheckAttachments">{{ errState.customerCheckAttachments }}</view>
143
+ </view>
144
+ </view>
145
+ <RippleBtn @click="submitForm" :customStyle="'margin-top: 50rpx;padding-bottom: 18rpx'">
146
+ <view class="submit-btn">保存验收</view>
147
+ </RippleBtn>
148
+ </view>
149
+ </template>
150
+ <style scoped lang="less">
151
+ .content {
152
+ .form-box{
153
+ margin-bottom: 32rpx;
154
+ }
155
+ .flex-space {
156
+ display: flex;
157
+ justify-content: space-between;
158
+ align-items: center;
159
+ color: rgba(0, 0, 0, 0.6);
160
+
161
+ &:not(:last-child) {
162
+ border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
163
+ }
164
+ }
165
+ .flex-col{
166
+ flex-direction: column;
167
+ align-items: flex-start;
168
+ }
169
+ .form-content {
170
+ margin-bottom: 32rpx;
171
+ background-color: #fff;
172
+ border-radius: 16rpx;
173
+ padding: 0 32rpx;
174
+ position: relative;
175
+ }
176
+ .uni-form-item {
177
+ display: flex;
178
+ }
179
+ .dateSelect-box {
180
+ display: flex;
181
+ align-items: center;
182
+ flex-direction: row-reverse;
183
+ flex: 1;
184
+ min-width: 0;
185
+ .right-icon {
186
+ margin-left: 16rpx;
187
+ width: 32rpx;
188
+ height: 32rpx;
189
+ text-align: right;
190
+ }
191
+ }
192
+ .text {
193
+ margin-bottom: 22rpx;
194
+ font-weight: 400;
195
+ font-size: 28rpx;
196
+ color: #000000;
197
+ line-height: 40rpx;
198
+
199
+ &:last-child {
200
+ margin-bottom: 0;
201
+ }
202
+ }
203
+ .l-label {
204
+ display: flex;
205
+ align-items: center;
206
+ padding: 32rpx 0;
207
+ font-size: 32rpx;
208
+ color: rgba(0, 0, 0, 0.6);
209
+ line-height: 48rpx;
210
+
211
+ .flag {
212
+ font-size: 32rpx;
213
+ color: #E34D59;
214
+ line-height: 38rpx;
215
+ }
216
+ }
217
+ .uni-textarea {
218
+ width: 100%;
219
+ line-height: 48rpx;
220
+ height: 288rpx;
221
+ font-size: 28rpx;
222
+
223
+ }
224
+ .annotation {
225
+ position: absolute;
226
+ bottom: 32rpx;
227
+ right: 32rpx;
228
+ font-weight: 400;
229
+ font-size: 24rpx;
230
+ color: rgba(0, 0, 0, 0.26);
231
+ line-height: 28rpx;
232
+ text-align: right;
233
+ }
234
+ .common-picker {
235
+ flex: 1;
236
+ text-align: right;
237
+ font-size: 32rpx;
238
+ color: rgba(0, 0, 0, 0.4);
239
+ line-height: 48rpx;
240
+ }
241
+ .upload-box {
242
+ display: flex;
243
+ flex-wrap: wrap;
244
+ gap: 20rpx;
245
+ padding-bottom: 32rpx;
246
+ .view-img {
247
+ width: 176rpx;
248
+ height: 176rpx;
249
+ }
250
+ }
251
+ .submit-btn {
252
+ box-sizing: border-box;
253
+ width: 686rpx;
254
+ padding: 24rpx 0 26rpx 0;
255
+ line-height: 58rpx;
256
+ font-family: Source Han Sans SC, Source Han Sans SC;
257
+ font-weight: 400;
258
+ font-size: 40rpx;
259
+ color: rgba(255, 255, 255, 0.9);
260
+ background: linear-gradient(270deg, #1D9DE9 0%, #1D6FE9 100%);
261
+ box-shadow: 0px 16rpx 16rpx 2rpx rgba(29, 157, 233, 0.1);
262
+ border-radius: 52rpx;
263
+ }
264
+ .err-text{
265
+ padding: 8rpx 16rpx 16rpx 16rpx;
266
+ font-size: 24rpx;
267
+ color: rgb(245, 140, 140);
268
+ }
269
+ }
270
+ </style>