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.
- package/.editorconfig +12 -0
- package/.eslintrc-auto-import.json +113 -0
- package/.eslintrc.js +121 -0
- package/.prettierrc.js +9 -0
- package/.stylelintignore +4 -0
- package/README.md +43 -0
- package/components.d.ts +23 -0
- package/index.html +20 -0
- package/package.json +70 -0
- package/shims-uni.d.ts +10 -0
- package/src/App.vue +81 -0
- package/src/api/afterSale.ts +184 -0
- package/src/api/context.ts +26 -0
- package/src/api/device.ts +134 -0
- package/src/api/index.ts +80 -0
- package/src/api/installtion.ts +155 -0
- package/src/api/model/index.ts +15 -0
- package/src/api/model/userModel.ts +62 -0
- package/src/api/order.ts +49 -0
- package/src/api/system.ts +19 -0
- package/src/api/user.ts +171 -0
- package/src/auto-imports.d.ts +108 -0
- package/src/components/ConfirmDialog.vue +101 -0
- package/src/components/DaySelect.vue +212 -0
- package/src/components/Drawer.vue +104 -0
- package/src/components/DrawerSelect.vue +105 -0
- package/src/components/DropMenu.vue +144 -0
- package/src/components/Empty.vue +49 -0
- package/src/components/Loading.vue +41 -0
- package/src/components/RippleBtn.vue +159 -0
- package/src/components/SinglePick.vue +120 -0
- package/src/components/Skeleton.vue +43 -0
- package/src/components/Timeline.vue +85 -0
- package/src/components/Upload.vue +217 -0
- package/src/config/app.ts +32 -0
- package/src/config/env.ts +29 -0
- package/src/dict/afterSale.ts +161 -0
- package/src/dict/device.ts +29 -0
- package/src/dict/installtion.ts +141 -0
- package/src/dict/systems.ts +4 -0
- package/src/env.d.ts +8 -0
- package/src/hooks/useForm.ts +222 -0
- package/src/hooks/useUpload.ts +80 -0
- package/src/main.ts +8 -0
- package/src/manifest.json +39 -0
- package/src/pages/acceptance/DeviceInfo.vue +132 -0
- package/src/pages/acceptance/list.vue +276 -0
- package/src/pages/afterSale/DeviceInfo.vue +128 -0
- package/src/pages/afterSale/Step.vue +0 -0
- package/src/pages/afterSale/faultReport.vue +552 -0
- package/src/pages/afterSale/orderDetail.vue +327 -0
- package/src/pages/afterSale/orderFinish.vue +517 -0
- package/src/pages/afterSale/orderList.vue +305 -0
- package/src/pages/afterSale/returnVisit.vue +288 -0
- package/src/pages/afterSale/searchDeviceList.vue +148 -0
- package/src/pages/device/Search.vue +201 -0
- package/src/pages/device/acceptance.vue +270 -0
- package/src/pages/device/detail.vue +165 -0
- package/src/pages/device/index.vue +322 -0
- package/src/pages/device/info.vue +140 -0
- package/src/pages/device/list.vue +219 -0
- package/src/pages/device/materialTowerCode.vue +589 -0
- package/src/pages/device/searchList.vue +224 -0
- package/src/pages/installtion/Record.vue +145 -0
- package/src/pages/installtion/StatusTimeline.vue +85 -0
- package/src/pages/installtion/addAcceptance.vue +409 -0
- package/src/pages/installtion/addRecord.vue +338 -0
- package/src/pages/installtion/orderDetail.vue +220 -0
- package/src/pages/installtion/orderList.vue +100 -0
- package/src/pages/user/component/PersonAgree.vue +226 -0
- package/src/pages/user/component/PrivayAgree.vue +221 -0
- package/src/pages/user/component/SliderCode.vue +173 -0
- package/src/pages/user/forgetPassword.vue +249 -0
- package/src/pages/user/index.vue +139 -0
- package/src/pages/user/login.vue +342 -0
- package/src/pages/user/register.vue +348 -0
- package/src/pages/user/repassword.vue +329 -0
- package/src/pages/user/utils/mcaptcha.js +75 -0
- package/src/pages/user/utils/verifyCode.ts +41 -0
- package/src/pages/workspace/index.vue +225 -0
- package/src/pages.json +203 -0
- package/src/shime-uni.d.ts +6 -0
- package/src/static/icon/system/breeder_icon.png +0 -0
- package/src/static/icon/system/check.png +0 -0
- package/src/static/icon/system/factory_icon.png +0 -0
- package/src/static/icon/system/plus.png +0 -0
- package/src/static/icon/system/right.png +0 -0
- package/src/static/icon/system/unCheck.png +0 -0
- package/src/static/icon/tab/search.png +0 -0
- package/src/static/icon/tab/user.png +0 -0
- package/src/static/icon/tab/user_active.png +0 -0
- package/src/static/icon/tab/workspace.png +0 -0
- package/src/static/icon/tab/workspace_active.png +0 -0
- package/src/static/img/active_dot.png +0 -0
- package/src/static/img/afterSale_icon.png +0 -0
- package/src/static/img/check.png +0 -0
- package/src/static/img/close.png +0 -0
- package/src/static/img/confirm.png +0 -0
- package/src/static/img/empty.png +0 -0
- package/src/static/img/equipment_icon.png +0 -0
- package/src/static/img/fault_icon.png +0 -0
- package/src/static/img/install_icon.png +0 -0
- package/src/static/img/login_bg2.png +0 -0
- package/src/static/img/movable_right.png +0 -0
- package/src/static/img/navigation.png +0 -0
- package/src/static/img/psw_off.png +0 -0
- package/src/static/img/psw_on.png +0 -0
- package/src/static/img/scan.png +0 -0
- package/src/static/img/scan_icon.png +0 -0
- package/src/static/img/search.png +0 -0
- package/src/static/img/turn_right.png +0 -0
- package/src/static/img/unActive_dot.png +0 -0
- package/src/static/img/verifyBg.png +0 -0
- package/src/stores/index.ts +11 -0
- package/src/stores/modules/customer.ts +146 -0
- package/src/stores/modules/installtion.ts +30 -0
- package/src/stores/modules/system.ts +56 -0
- package/src/stores/modules/user.ts +133 -0
- package/src/stores/types.ts +16 -0
- package/src/stores/utils.ts +6 -0
- package/src/styles/index.less +63 -0
- package/src/types/chengyiApi.d.ts +36 -0
- package/src/types/index.d.ts +95 -0
- package/src/utils/address.ts +17 -0
- package/src/utils/cipher.ts +61 -0
- package/src/utils/form.ts +155 -0
- package/src/utils/httpEnum.ts +31 -0
- package/src/utils/image.ts +21 -0
- package/src/utils/index.ts +111 -0
- package/src/utils/request.ts +139 -0
- package/src/utils/requestCancelHandle.ts +67 -0
- package/stylelint.config.js +87 -0
- package/tsconfig.docs.json +11 -0
- package/tsconfig.json +30 -0
- package/typedoc.json +6 -0
- package/vite.config.ts +55 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { reactive } from 'vue'
|
|
2
|
+
import { throttle } from 'lodash-es'
|
|
3
|
+
import { scrollToFirstError } from '@/utils/form'
|
|
4
|
+
// 定义校验规则类型
|
|
5
|
+
export interface ValidationRule<T = any> {
|
|
6
|
+
required?: boolean;
|
|
7
|
+
pattern?: RegExp;
|
|
8
|
+
message?: string;
|
|
9
|
+
validatFunc?: (
|
|
10
|
+
value: T
|
|
11
|
+
) => boolean | string | Promise<boolean> | Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// 定义校验规则对象类型
|
|
15
|
+
export type ValidationRules<T = any> = {
|
|
16
|
+
[K in keyof T]?: ValidationRule<T[K]>
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 表单钩子函数,提供表单数据管理、验证和重置功能
|
|
20
|
+
* @template T 表单数据类型
|
|
21
|
+
* @param initialData 表单初始数据
|
|
22
|
+
* @param rules 表单验证规则
|
|
23
|
+
* @param validateScroll 是否在验证失败时滚动到第一个错误字段
|
|
24
|
+
* @returns 返回表单相关方法和状态
|
|
25
|
+
*/
|
|
26
|
+
export function useForm<T extends Record<string, any>>(
|
|
27
|
+
initialData: T,
|
|
28
|
+
rules: ValidationRules<T>,
|
|
29
|
+
validateScroll: boolean = false
|
|
30
|
+
) {
|
|
31
|
+
// 表单数据
|
|
32
|
+
const formData = reactive<T>({ ...initialData }) as T
|
|
33
|
+
|
|
34
|
+
// 错误状态类型定义
|
|
35
|
+
const errState: any = reactive(
|
|
36
|
+
Object.keys(initialData).reduce((acc, key) => {
|
|
37
|
+
acc[key as keyof T] = ''
|
|
38
|
+
return acc
|
|
39
|
+
}, {} as Record<keyof T, string>)
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 验证整个表单
|
|
44
|
+
* @returns 表单是否验证通过
|
|
45
|
+
*/
|
|
46
|
+
const validateForm = async() => {
|
|
47
|
+
if (!rules) return true
|
|
48
|
+
const [isValid, firstErrorKey] = await formValidateFunc()
|
|
49
|
+
if (validateScroll && firstErrorKey) {
|
|
50
|
+
scrollToFirstError(firstErrorKey)
|
|
51
|
+
}
|
|
52
|
+
return isValid
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 重置表单到初始状态
|
|
57
|
+
*/
|
|
58
|
+
const resetForm = () => {
|
|
59
|
+
Object.keys(initialData).forEach(key => {
|
|
60
|
+
formData[key as keyof T] = initialData[key as keyof T]
|
|
61
|
+
errState[key as keyof T] = ''
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 设置表单字段值
|
|
67
|
+
* @param key 字段键名
|
|
68
|
+
* @param value 字段值
|
|
69
|
+
*/
|
|
70
|
+
const setFormItem = (key: keyof T, value: T[keyof T]) => {
|
|
71
|
+
formData[key] = value
|
|
72
|
+
const validateField = throttle(() => {
|
|
73
|
+
if (!rules || !rules[key]) return
|
|
74
|
+
validateOneField(key)
|
|
75
|
+
}, 300)
|
|
76
|
+
validateField()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* 初始化表单数据
|
|
81
|
+
* @param data 初始数据
|
|
82
|
+
*/
|
|
83
|
+
const initialForm = (data: Partial<T>) => {
|
|
84
|
+
Object.keys(data).forEach(key => {
|
|
85
|
+
formData[key as keyof T] = data[key as keyof T] || initialData[key as keyof T]
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 异步验证单个字段
|
|
90
|
+
* @param key 字段键名
|
|
91
|
+
* @returns 字段是否验证通过
|
|
92
|
+
*/
|
|
93
|
+
const validateOneField = async (
|
|
94
|
+
key: keyof T,
|
|
95
|
+
): Promise<boolean> => {
|
|
96
|
+
let isValid = true;
|
|
97
|
+
const value = formData[key];
|
|
98
|
+
const rule = rules[key];
|
|
99
|
+
if (!rule) {
|
|
100
|
+
return isValid;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 处理数组类型
|
|
104
|
+
if (Array.isArray(value)) {
|
|
105
|
+
if (rule.required && value.length === 0) {
|
|
106
|
+
errState[key] = rule.message;
|
|
107
|
+
isValid = false;
|
|
108
|
+
} else if (rule.validatFunc) {
|
|
109
|
+
try {
|
|
110
|
+
const result = await Promise.resolve(rule.validatFunc(value));
|
|
111
|
+
if (!result) {
|
|
112
|
+
errState[key] = rule.message;
|
|
113
|
+
isValid = false;
|
|
114
|
+
} else {
|
|
115
|
+
errState[key] = '';
|
|
116
|
+
isValid = true;
|
|
117
|
+
}
|
|
118
|
+
} catch (error) {
|
|
119
|
+
// 捕获reject的错误信息
|
|
120
|
+
errState[key] = typeof error === 'string' ? error : rule.message;
|
|
121
|
+
isValid = false;
|
|
122
|
+
}
|
|
123
|
+
} else {
|
|
124
|
+
// 数组类型,没有validatFunc且必填校验通过,清空错误状态
|
|
125
|
+
errState[key] = '';
|
|
126
|
+
isValid = true;
|
|
127
|
+
}
|
|
128
|
+
} else {
|
|
129
|
+
// 处理字符串类型
|
|
130
|
+
const stringValue = value || '';
|
|
131
|
+
let hasError = false;
|
|
132
|
+
let errorMessage = '';
|
|
133
|
+
|
|
134
|
+
// 必填校验
|
|
135
|
+
if (rule.required && !stringValue) {
|
|
136
|
+
errorMessage = rule.message || '';
|
|
137
|
+
isValid = false;
|
|
138
|
+
hasError = true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 正则校验(只有在有值且必填校验通过时才检查)
|
|
142
|
+
if (!hasError && rule.pattern && stringValue && !rule.pattern.test(stringValue)) {
|
|
143
|
+
errorMessage = rule.message || '';
|
|
144
|
+
isValid = false;
|
|
145
|
+
hasError = true;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 自定义校验函数(只有在必填和正则校验都通过时才检查)
|
|
149
|
+
if (!hasError && rule.validatFunc) {
|
|
150
|
+
try {
|
|
151
|
+
const result = await Promise.resolve(rule.validatFunc(value));
|
|
152
|
+
if (!result) {
|
|
153
|
+
errorMessage = typeof result === 'string' ? result : (rule.message || '');
|
|
154
|
+
isValid = false;
|
|
155
|
+
hasError = true;
|
|
156
|
+
}
|
|
157
|
+
} catch (error) {
|
|
158
|
+
// 捕获reject的错误信息
|
|
159
|
+
errorMessage = typeof error === 'string' ? error : (rule.message || '');
|
|
160
|
+
isValid = false;
|
|
161
|
+
hasError = true;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 根据是否有错误来设置或清空错误状态
|
|
166
|
+
if (hasError) {
|
|
167
|
+
errState[key] = errorMessage;
|
|
168
|
+
} else {
|
|
169
|
+
// 所有校验都通过,清空错误状态
|
|
170
|
+
errState[key] = '';
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return isValid;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 表单校验函数
|
|
179
|
+
* @param key 可选参数,用于指定校验单个字段
|
|
180
|
+
* @returns 校验结果和第一个错误字段的键名
|
|
181
|
+
*/
|
|
182
|
+
const formValidateFunc = async (
|
|
183
|
+
key?: keyof T
|
|
184
|
+
): Promise<[boolean, keyof T | undefined]> => {
|
|
185
|
+
let isValid = true;
|
|
186
|
+
let firstErrorKey: keyof T | undefined;
|
|
187
|
+
|
|
188
|
+
if (key) {
|
|
189
|
+
// 校验单个字段
|
|
190
|
+
const rule = rules[key];
|
|
191
|
+
if (rule) {
|
|
192
|
+
isValid = await validateOneField(key);
|
|
193
|
+
}
|
|
194
|
+
} else {
|
|
195
|
+
// 校验整个表单
|
|
196
|
+
for (const vKey of Object.keys(rules) as Array<keyof T>) {
|
|
197
|
+
const rule = rules[vKey];
|
|
198
|
+
if (rule) {
|
|
199
|
+
const fieldValid = await validateOneField(vKey);
|
|
200
|
+
if (!fieldValid) {
|
|
201
|
+
isValid = false;
|
|
202
|
+
if (!firstErrorKey) {
|
|
203
|
+
firstErrorKey = vKey;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return [isValid, firstErrorKey];
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
formData,
|
|
215
|
+
errState,
|
|
216
|
+
validateForm,
|
|
217
|
+
setFormItem,
|
|
218
|
+
resetForm,
|
|
219
|
+
initialForm,
|
|
220
|
+
validateOneField
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ref } from 'vue';
|
|
2
|
+
import { uploadWxFile } from '@/api';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @description: 文件路径数组
|
|
6
|
+
* @param {string} url 文件路径
|
|
7
|
+
* @param {string} uid 文件唯一标识
|
|
8
|
+
* @param {string} id 文件id
|
|
9
|
+
*/
|
|
10
|
+
type filePaths = {
|
|
11
|
+
url: string;
|
|
12
|
+
uid: string;
|
|
13
|
+
id?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @description: 上传文件
|
|
18
|
+
* @param {filePaths} files 文件路径数组
|
|
19
|
+
* @param {any} formData 表单数据
|
|
20
|
+
* @return {Promise} Promise对象
|
|
21
|
+
*/
|
|
22
|
+
export function useUpload() {
|
|
23
|
+
const progress = ref(0);
|
|
24
|
+
const fileProgress = reactive<Record<string, number>>({});
|
|
25
|
+
const uploading = ref(false);
|
|
26
|
+
|
|
27
|
+
const upload = async (files: filePaths[], formData?: any) => {
|
|
28
|
+
const filePaths = files.map(file => file.url);
|
|
29
|
+
const paths = Array.isArray(filePaths) ? filePaths : [filePaths];
|
|
30
|
+
uploading.value = true;
|
|
31
|
+
|
|
32
|
+
// 初始化进度
|
|
33
|
+
files.forEach(fItem => {
|
|
34
|
+
fileProgress[fItem.uid] = 0;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
try {
|
|
38
|
+
return Promise.all(
|
|
39
|
+
files.map(fitem =>
|
|
40
|
+
uploadWxFile(fitem, formData, (p) => {
|
|
41
|
+
fileProgress[fitem.uid] = p;
|
|
42
|
+
updateTotalProgress();
|
|
43
|
+
})
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
} finally {
|
|
47
|
+
uploading.value = false;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @description: 更新总进度
|
|
53
|
+
* @return {void} void
|
|
54
|
+
*/
|
|
55
|
+
const updateTotalProgress = () => {
|
|
56
|
+
const progresses = Object.values(fileProgress);
|
|
57
|
+
if (progresses.length === 0) {
|
|
58
|
+
progress.value = 0;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
progress.value = Math.round(
|
|
62
|
+
progresses.reduce((sum, p) => sum + p, 0) / progresses.length
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
upload,
|
|
68
|
+
progress,
|
|
69
|
+
fileProgress: readonly(fileProgress),
|
|
70
|
+
uploading
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const formatFileRes = (res: any) => {
|
|
75
|
+
if (Array.isArray(res)) {
|
|
76
|
+
return res.map(item => {
|
|
77
|
+
return item.data?.data?.fileUrl;
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
}
|
package/src/main.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "chengyi",
|
|
3
|
+
"appid": "",
|
|
4
|
+
"description": "chengyi-app",
|
|
5
|
+
"versionName": "1.0.0",
|
|
6
|
+
"versionCode": "100",
|
|
7
|
+
"transformPx": false,
|
|
8
|
+
"mp-weixin": {
|
|
9
|
+
"appid": "",
|
|
10
|
+
"setting": {
|
|
11
|
+
"urlCheck": false
|
|
12
|
+
},
|
|
13
|
+
"usingComponents": true
|
|
14
|
+
},
|
|
15
|
+
"uniStatistics": {
|
|
16
|
+
"enable": false
|
|
17
|
+
},
|
|
18
|
+
"vueVersion": "3",
|
|
19
|
+
"permission": {
|
|
20
|
+
"scope.writePhotosAlbum": {
|
|
21
|
+
"desc": "需要访问您的相册"
|
|
22
|
+
},
|
|
23
|
+
"scope.userLocation": {
|
|
24
|
+
"desc": "你的位置信息将用于小程序位置接口的效果展示"
|
|
25
|
+
},
|
|
26
|
+
"scope.systemAlbum": {
|
|
27
|
+
"desc": "需要访问您的系统相册"
|
|
28
|
+
},
|
|
29
|
+
"scope.userLocationBackground": {
|
|
30
|
+
"desc": "需要在后台获取您的位置信息"
|
|
31
|
+
},
|
|
32
|
+
"scope.camera": {
|
|
33
|
+
"desc": "需要摄像头权限进行扫码"
|
|
34
|
+
},
|
|
35
|
+
"scope.chooseLocation": {
|
|
36
|
+
"desc": "需要从地图选择位置"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { PLACEHOLDER } from '@/config/app'
|
|
3
|
+
import { installWorkNodeEnum, installWorkNodeMap } from '@/dict/installtion'
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
data: {
|
|
6
|
+
type: Object,
|
|
7
|
+
default: {}
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
const emit = defineEmits(['clickDevice']);
|
|
11
|
+
const handleClickDevice = (item: any) => {
|
|
12
|
+
emit('clickDevice', {
|
|
13
|
+
...item,
|
|
14
|
+
planId: props.data.planId
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
<template>
|
|
19
|
+
<view class="urgency" v-if="data.isUrgency">紧急</view>
|
|
20
|
+
<view class="customerName">{{ data.customerName || PLACEHOLDER }}</view>
|
|
21
|
+
<view class="orderCode">{{ data.workOrderCode || PLACEHOLDER }}</view>
|
|
22
|
+
<view class="contact">
|
|
23
|
+
<view class="name">联系人姓名:{{ data.contactsName || PLACEHOLDER }}</view>
|
|
24
|
+
<view class="mobile">联系电话:{{ data.contactsMobile || PLACEHOLDER }}</view>
|
|
25
|
+
</view>
|
|
26
|
+
<view class="device-box" v-for="item in data.deviceList"
|
|
27
|
+
:key="item.id" @click="handleClickDevice(item)">
|
|
28
|
+
<view class="deviceName">{{ item.deviceName || PLACEHOLDER }}</view>
|
|
29
|
+
<view class="deviceStatus" v-if="installWorkNodeMap[item.status]">
|
|
30
|
+
{{ installWorkNodeMap[item.status]?.label }}-正常</view>
|
|
31
|
+
<view class="deviceCode">{{ item.deviceCode || PLACEHOLDER }}</view>
|
|
32
|
+
<view class="addressInfo">
|
|
33
|
+
设备地址:
|
|
34
|
+
<view class="address">{{ `${item.provinceName || PLACEHOLDER}
|
|
35
|
+
${item.cityName || PLACEHOLDER}
|
|
36
|
+
${item.areaName || PLACEHOLDER}
|
|
37
|
+
${item.address || PLACEHOLDER}` }}</view>
|
|
38
|
+
</view>
|
|
39
|
+
</view>
|
|
40
|
+
</template>
|
|
41
|
+
|
|
42
|
+
<style scoped>
|
|
43
|
+
.urgency {
|
|
44
|
+
position: absolute;
|
|
45
|
+
right: 32rpx;
|
|
46
|
+
top: 32rpx;
|
|
47
|
+
display: block;
|
|
48
|
+
padding: 6rpx 16rpx 8rpx 16rpx;
|
|
49
|
+
font-size: 24rpx;
|
|
50
|
+
color: #E34D59;
|
|
51
|
+
line-height: 34rpx;
|
|
52
|
+
background: rgba(227,77,89,0.1);
|
|
53
|
+
border-radius: 8rpx;
|
|
54
|
+
border: 1rpx solid #E34D59;
|
|
55
|
+
}
|
|
56
|
+
.customerName {
|
|
57
|
+
font-size: 32rpx;
|
|
58
|
+
color: #000000;
|
|
59
|
+
line-height: 48rpx;
|
|
60
|
+
margin-bottom: 16rpx;
|
|
61
|
+
font-weight: 600;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.orderCode {
|
|
65
|
+
font-size: 28rpx;
|
|
66
|
+
color: rgba(0, 0, 0, 0.4);
|
|
67
|
+
line-height: 34rpx;
|
|
68
|
+
margin-bottom: 16rpx;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.contact {
|
|
72
|
+
display: flex;
|
|
73
|
+
justify-content: space-between;
|
|
74
|
+
margin-bottom: 32rpx;
|
|
75
|
+
font-size: 28rpx;
|
|
76
|
+
color: #000000;
|
|
77
|
+
line-height: 40rpx;
|
|
78
|
+
}
|
|
79
|
+
.device-box {
|
|
80
|
+
margin-bottom: 16rpx;
|
|
81
|
+
padding: 16rpx 16rpx 24rpx 16rpx;
|
|
82
|
+
background-color: #F3F8FE;
|
|
83
|
+
border-radius: 8rpx;
|
|
84
|
+
position: relative;
|
|
85
|
+
.deviceName {
|
|
86
|
+
font-size: 28rpx;
|
|
87
|
+
color: #000000;
|
|
88
|
+
line-height: 40rpx;
|
|
89
|
+
font-weight: 500;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.deviceCode {
|
|
93
|
+
font-size: 28rpx;
|
|
94
|
+
color: rgba(0, 0, 0, 0.4);
|
|
95
|
+
line-height: 34px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.addressInfo {
|
|
99
|
+
display: flex;
|
|
100
|
+
font-size: 28rpx;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.address {
|
|
104
|
+
flex: 1;
|
|
105
|
+
width: 380rpx;
|
|
106
|
+
font-size: 28rpx;
|
|
107
|
+
color: #000000;
|
|
108
|
+
line-height: 40rpx;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.address-icon {
|
|
112
|
+
width: 48rpx;
|
|
113
|
+
height: 48rpx;
|
|
114
|
+
image-rendering: -webkit-optimize-contrast; /* 优化图片渲染 */
|
|
115
|
+
image-rendering: pixelated; /* 像素化渲染 */
|
|
116
|
+
transform: translateZ(0); /* 开启GPU加速 */
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.deviceStatus {
|
|
120
|
+
display: block;
|
|
121
|
+
position: absolute;
|
|
122
|
+
top: 16rpx;
|
|
123
|
+
right: 16rpx;
|
|
124
|
+
padding: 4rpx 16rpx 6rpx 16rpx;
|
|
125
|
+
font-size: 20rpx;
|
|
126
|
+
color: #1D6FE9;
|
|
127
|
+
line-height: 30rpx;
|
|
128
|
+
border-radius: 8rpx;
|
|
129
|
+
border: 1rpx solid #1D6FE9;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
</style>
|