wui-components-v2 1.1.54 → 1.1.56
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/components/action-popup/action-popup.vue +18 -3
- package/components/custom-date-picker/custom-date-picker.vue +4 -6
- package/components/form-control/form-control.vue +108 -4
- package/components/list-top-buttons/list-top-buttons.vue +3 -4
- package/components/scan-input/scan-input.vue +312 -0
- package/components/user-choose/user-choose.vue +2 -4
- package/components/wui-list/wui-list.vue +7 -7
- package/components/wui-select-list/wui-select-list.vue +14 -1
- package/components/wui-user/wui-user.vue +14 -0
- package/composables/useCompanyFieldFilter.ts +2 -2
- package/package.json +2 -1
- package/store/language.ts +1 -1
- package/store/manualThemeStore.ts +1 -1
|
@@ -31,23 +31,38 @@ const show = computed({
|
|
|
31
31
|
},
|
|
32
32
|
})
|
|
33
33
|
|
|
34
|
+
// 格式化文件数据为后端期望的 JSON 字符串
|
|
35
|
+
function formatFileData(data: Record<string, any>) {
|
|
36
|
+
const result = { ...data }
|
|
37
|
+
for (const key in result) {
|
|
38
|
+
if (result[key]?.response) {
|
|
39
|
+
const fileObj = result[key]
|
|
40
|
+
const res = typeof fileObj.response === 'string' ? JSON.parse(fileObj.response) : fileObj.response
|
|
41
|
+
result[key] = JSON.stringify({
|
|
42
|
+
valid: fileObj.disabled ? 'old' : 'new',
|
|
43
|
+
fileKey: res.fileKey,
|
|
44
|
+
fileName: fileObj.name,
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
|
|
34
51
|
// 提交数据
|
|
35
52
|
async function action() {
|
|
36
|
-
console.log('提交action')
|
|
37
53
|
btnLoading.value = true
|
|
38
54
|
if (!props.fieldGroup?.id) {
|
|
39
55
|
return toast.warning({ msg: '无sourceId' })
|
|
40
56
|
}
|
|
41
57
|
try {
|
|
42
58
|
const data = await formControlRef.value.submit()
|
|
43
|
-
await actionDataSave(props.fieldGroup?.id || '', props.code, data)
|
|
59
|
+
await actionDataSave(props.fieldGroup?.id || '', props.code, formatFileData(data))
|
|
44
60
|
btnLoading.value = false
|
|
45
61
|
show.value = false
|
|
46
62
|
props.zpaging.reload()
|
|
47
63
|
toast.success({ msg: '操作成功!' })
|
|
48
64
|
}
|
|
49
65
|
catch (error: any) {
|
|
50
|
-
console.log(error, 'error')
|
|
51
66
|
btnLoading.value = false
|
|
52
67
|
toast.error(error)
|
|
53
68
|
}
|
|
@@ -26,9 +26,6 @@ interface SelectOption {
|
|
|
26
26
|
value: string | number
|
|
27
27
|
[key: string]: any
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
console.log(props.type, 'props.type')
|
|
31
|
-
|
|
32
29
|
const open = ref(false)
|
|
33
30
|
const currentValue = ref<any>(props.modelValue)
|
|
34
31
|
function clear() {
|
|
@@ -38,7 +35,6 @@ function clear() {
|
|
|
38
35
|
watch(
|
|
39
36
|
() => props.modelValue,
|
|
40
37
|
(val) => {
|
|
41
|
-
console.log(val, 'val1111')
|
|
42
38
|
currentValue.value = val
|
|
43
39
|
},
|
|
44
40
|
)
|
|
@@ -55,8 +51,10 @@ const labelText = computed(() => {
|
|
|
55
51
|
} = {
|
|
56
52
|
date: 'YYYY-MM-DD',
|
|
57
53
|
datetime: 'YYYY-MM-DD HH:mm',
|
|
54
|
+
year:'YYYY'
|
|
58
55
|
}
|
|
59
|
-
|
|
56
|
+
|
|
57
|
+
if (['date', 'datetime', 'year'].includes(props.type)) {
|
|
60
58
|
return currentValue.value ? dayjs(currentValue.value).format(formatMap[props.type] as string) : ''
|
|
61
59
|
}
|
|
62
60
|
else {
|
|
@@ -79,7 +77,7 @@ const labelText = computed(() => {
|
|
|
79
77
|
</div>
|
|
80
78
|
|
|
81
79
|
<wd-calendar
|
|
82
|
-
v-if="['date', 'datetime'].includes(type)"
|
|
80
|
+
v-if="['date', 'datetime',].includes(type)"
|
|
83
81
|
v-model="currentValue"
|
|
84
82
|
v-model:visible="open"
|
|
85
83
|
label-key="label"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import { computed, onBeforeMount, ref, toRaw } from 'vue'
|
|
2
|
+
import { computed, onBeforeMount, ref, toRaw, watch } from 'vue'
|
|
3
3
|
import type { FormSchema, FormSchemaIssue } from '@wot-ui/ui/components/wd-form/types'
|
|
4
4
|
import dayjs from 'dayjs/esm/index'
|
|
5
5
|
import type { Enums, Fields, Groups } from '../../type'
|
|
@@ -50,6 +50,19 @@ const { filteredFields: fields } = useCompanyFieldFilter(
|
|
|
50
50
|
props.companyFilter, // 是否自适应显示快递公司填充框
|
|
51
51
|
props.companyFieldSourceId, // 快递公司对应字段
|
|
52
52
|
)
|
|
53
|
+
const giveDefaultValue =(value:any)=>{
|
|
54
|
+
const {extInfo={}} = uni.getStorageSync('userInfo')||{}
|
|
55
|
+
const rawDefaultValue=extInfo.fieldMap||{};
|
|
56
|
+
const defaultValue: Record<string, any> = {}
|
|
57
|
+
for (const key in rawDefaultValue) {
|
|
58
|
+
if (Object.prototype.hasOwnProperty.call(rawDefaultValue, key)) {
|
|
59
|
+
const val = rawDefaultValue[key]
|
|
60
|
+
defaultValue[key] = typeof val === 'string' && val.includes('@R@') ? val.split('@R@')[0] : val
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return defaultValue[value]||{}
|
|
64
|
+
}
|
|
65
|
+
giveDefaultValue({})
|
|
53
66
|
// 初始化表单数据
|
|
54
67
|
function initFormData() {
|
|
55
68
|
const models: { [key: string]: any } = {}
|
|
@@ -81,14 +94,84 @@ function initFormData() {
|
|
|
81
94
|
return models[item.sourceId] = (props.entity && props.entity[item.sourceId]) || item.transDefaultValue || ''
|
|
82
95
|
})
|
|
83
96
|
|
|
84
|
-
|
|
97
|
+
// 遍历 models,处理 $$user. 前缀
|
|
98
|
+
const processedModels: Record<string, any> = {}
|
|
99
|
+
for (const key in models) {
|
|
100
|
+
if (Object.prototype.hasOwnProperty.call(models, key)) {
|
|
101
|
+
const val = models[key]
|
|
102
|
+
if (typeof val === 'string' && val.includes('$$user.')) {
|
|
103
|
+
processedModels[key] = giveDefaultValue(val.split('$$user.')[1])
|
|
104
|
+
} else {
|
|
105
|
+
processedModels[key] = val
|
|
106
|
+
}
|
|
107
|
+
}
|
|
85
108
|
}
|
|
86
109
|
|
|
110
|
+
model.value = {
|
|
111
|
+
...processedModels,
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
//-s
|
|
116
|
+
const shouldMonitor=computed(()=>{
|
|
117
|
+
const newList=fields.value.filter((item:any)=>item.relValueField||item.relValueField3).map((innerItem:any)=>({
|
|
118
|
+
id: innerItem.sourceId,
|
|
119
|
+
title: innerItem.title,
|
|
120
|
+
relValueField: innerItem.relValueField.id,
|
|
121
|
+
relValueField3: innerItem.relValueField3.id,
|
|
122
|
+
}))
|
|
123
|
+
console.log('shouldMonitor:', newList)
|
|
124
|
+
return newList
|
|
125
|
+
})
|
|
126
|
+
//-e
|
|
127
|
+
|
|
128
|
+
// 存储变化后的数据,{ [fieldKey]: newValue, ... }
|
|
129
|
+
const changedData = ref<Record<string, any>>({})
|
|
130
|
+
const initialModel = ref<Record<string, any>>({})
|
|
131
|
+
|
|
132
|
+
// 监听 shouldMonitor 中 relValueField / relValueField3 对应的 model 字段
|
|
133
|
+
watch(
|
|
134
|
+
() => {
|
|
135
|
+
const snapshot: Record<string, any> = {}
|
|
136
|
+
shouldMonitor.value?.forEach((item: any) => {
|
|
137
|
+
if (item.relValueField)
|
|
138
|
+
snapshot.relValueField = model.value[item.relValueField]
|
|
139
|
+
if (item.relValueField3)
|
|
140
|
+
snapshot.relValueField3 = model.value[item.relValueField3]
|
|
141
|
+
})
|
|
142
|
+
return snapshot
|
|
143
|
+
},
|
|
144
|
+
(newVal) => {
|
|
145
|
+
// 只存储与初始值不同的字段(表单变化的值)
|
|
146
|
+
const changed: Record<string, any> = {}
|
|
147
|
+
shouldMonitor.value?.forEach((item: any) => {
|
|
148
|
+
if (item.relValueField && newVal.relValueField !== initialModel.value[item.relValueField]) {
|
|
149
|
+
changed.relValueField = newVal.relValueField
|
|
150
|
+
}
|
|
151
|
+
if (item.relValueField3 && newVal.relValueField3 !== initialModel.value[item.relValueField3]) {
|
|
152
|
+
changed.relValueField3 = newVal.relValueField3
|
|
153
|
+
}
|
|
154
|
+
})
|
|
155
|
+
changedData.value = changed
|
|
156
|
+
|
|
157
|
+
// 当所有被监听的字段都有值时,存入缓存供 select-list 页面读取
|
|
158
|
+
const values = Object.values(newVal)
|
|
159
|
+
const allExist = values.length > 0 && values.every(v => v !== null && v !== undefined && v !== '')
|
|
160
|
+
if (allExist) {
|
|
161
|
+
uni.setStorageSync('paramsData', {
|
|
162
|
+
changedData: changedData.value,
|
|
163
|
+
rawData: shouldMonitor.value,
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
)
|
|
168
|
+
|
|
87
169
|
onBeforeMount(() => {
|
|
88
170
|
action.value = uni.getStorageSync('BASE_URL')
|
|
89
171
|
hydrocarbonProgramToken.value = uni.getStorageSync('HYDROCARBON_PROGRAM_TOKEN')
|
|
90
172
|
token.value = uni.getStorageSync('TOKEN')
|
|
91
173
|
initFormData()
|
|
174
|
+
initialModel.value = JSON.parse(JSON.stringify(model.value))
|
|
92
175
|
})
|
|
93
176
|
function formatSelectColumns(columns: any) {
|
|
94
177
|
return columns.map((item: any) => {
|
|
@@ -154,7 +237,6 @@ function submit() {
|
|
|
154
237
|
})
|
|
155
238
|
}
|
|
156
239
|
}
|
|
157
|
-
console.log('submit', model.value)
|
|
158
240
|
resolve(data)
|
|
159
241
|
}
|
|
160
242
|
else {
|
|
@@ -168,16 +250,22 @@ function submit() {
|
|
|
168
250
|
})
|
|
169
251
|
}
|
|
170
252
|
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
|
|
171
257
|
// 暴露方法/变量给父组件
|
|
172
258
|
defineExpose({
|
|
173
259
|
submit,
|
|
174
260
|
})
|
|
261
|
+
|
|
262
|
+
|
|
175
263
|
</script>
|
|
176
264
|
|
|
177
265
|
<template>
|
|
178
266
|
<view>
|
|
179
267
|
<wd-form ref="form" :model="model" :schema="schema" error-type="toast" :label-width="120" class="custom-from-style">
|
|
180
|
-
<addAddressPage v-if="props
|
|
268
|
+
<addAddressPage v-if="props?.smartPaste" v-model="model" :group="props.fieldGroup" />
|
|
181
269
|
<view v-for="item in fields" :key="item.sourceId">
|
|
182
270
|
<view v-show="!item.title?.includes('y') && !item.hidden">
|
|
183
271
|
<wd-form-item
|
|
@@ -318,6 +406,22 @@ defineExpose({
|
|
|
318
406
|
:clearable="!item.disabled"
|
|
319
407
|
:placeholder="`请选择${item.title}`"
|
|
320
408
|
/>
|
|
409
|
+
|
|
410
|
+
</wd-form-item>
|
|
411
|
+
<wd-form-item
|
|
412
|
+
v-else-if="ControlTypeSupportor.getControlType(item, props.entity && props.entity[item.sourceId]) === 'date-YY'"
|
|
413
|
+
:class="{ 'no-border-top': fields.indexOf(item) === 0 }"
|
|
414
|
+
:prop="item.sourceId"
|
|
415
|
+
:title="item.title"
|
|
416
|
+
>
|
|
417
|
+
<customDatePicker
|
|
418
|
+
v-model="model[item.sourceId]"
|
|
419
|
+
type="year"
|
|
420
|
+
use-second
|
|
421
|
+
:clearable="!item.disabled"
|
|
422
|
+
:placeholder="`请选择${item.title}`"
|
|
423
|
+
/>
|
|
424
|
+
|
|
321
425
|
</wd-form-item>
|
|
322
426
|
<wd-form-item
|
|
323
427
|
v-else-if="ControlTypeSupportor.getControlType(item, props.entity && props.entity[item.sourceId]) === 'file' || ControlTypeSupportor.getControlType(item, props.entity && props.entity[item.sourceId]) === 'relfile'"
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { defineOptions, defineProps } from 'vue'
|
|
3
2
|
import { useRouter } from 'uni-mini-router'
|
|
4
3
|
|
|
5
4
|
defineOptions({
|
|
6
5
|
name: 'ListTopButtons',
|
|
7
6
|
})
|
|
8
|
-
const props = defineProps<{ mainCode: string, buttons: string[], sourceId: string, id?: string, pageTitle: string, pageType?: string, addEvent?: string }>()
|
|
7
|
+
const props = defineProps<{ mainCode: string, buttons: string[], sourceId: string, id?: string, pageTitle: string, pageType?: string, addEvent?: string, config?: any }>()
|
|
9
8
|
const router = useRouter()
|
|
10
9
|
// 跳转添加页面
|
|
11
10
|
function gotoAddPage() {
|
|
@@ -14,7 +13,7 @@ function gotoAddPage() {
|
|
|
14
13
|
</script>
|
|
15
14
|
|
|
16
15
|
<template>
|
|
17
|
-
<view class="flex justify-end gap-1 py-2
|
|
18
|
-
<wd-
|
|
16
|
+
<view class="flex justify-end gap-1 py-2 px-2 .light:bg-white">
|
|
17
|
+
<wd-button class="flex-1" v-if="buttons.includes('dtmplAdd')" type="primary" @click="gotoAddPage" icon="plus">{{ props.config?.editBtnTitle || '新增' }}</wd-button>
|
|
19
18
|
</view>
|
|
20
19
|
</template>
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, onMounted, onUnmounted, nextTick } from 'vue'
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
name: 'ScanInput',
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(defineProps<{
|
|
9
|
+
autoStart?: boolean
|
|
10
|
+
placeholder?: string
|
|
11
|
+
}>(), {
|
|
12
|
+
autoStart: false,
|
|
13
|
+
placeholder: '请输入或扫描二维码/条形码',
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const emit = defineEmits<{
|
|
17
|
+
(e: 'scan', data: string): void
|
|
18
|
+
(e: 'input', data: string): void
|
|
19
|
+
(e: 'error', error: string): void
|
|
20
|
+
}>()
|
|
21
|
+
|
|
22
|
+
const inputValue = ref('')
|
|
23
|
+
const isScanning = ref(false)
|
|
24
|
+
const showScanModal = ref(false)
|
|
25
|
+
const isLoading = ref(false)
|
|
26
|
+
let html5QrcodeScanner: any = null
|
|
27
|
+
|
|
28
|
+
// #ifdef H5
|
|
29
|
+
import { Html5Qrcode } from 'html5-qrcode'
|
|
30
|
+
|
|
31
|
+
function checkCameraEnvironment(): { ok: boolean, reason?: string } {
|
|
32
|
+
const hostname = window.location.hostname
|
|
33
|
+
if (hostname === 'localhost' || hostname === '127.0.0.1') return { ok: true }
|
|
34
|
+
if (window.location.protocol !== 'https:') {
|
|
35
|
+
return { ok: false, reason: '当前非HTTPS环境,请在 https 下使用扫码功能' }
|
|
36
|
+
}
|
|
37
|
+
return { ok: true }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function startScan() {
|
|
41
|
+
if (isScanning.value) return
|
|
42
|
+
const envCheck = checkCameraEnvironment()
|
|
43
|
+
if (!envCheck.ok) {
|
|
44
|
+
uni.showToast({ title: envCheck.reason || '环境不支持', icon: 'none' })
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
isLoading.value = true
|
|
49
|
+
isScanning.value = true
|
|
50
|
+
showScanModal.value = true
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
await nextTick()
|
|
54
|
+
// 减少延时,库已打包进 bundle 无需等待加载
|
|
55
|
+
await new Promise(r => setTimeout(r, 200))
|
|
56
|
+
|
|
57
|
+
const container = document.getElementById('h5-scan-reader')
|
|
58
|
+
if (!container) throw new Error('容器未找到')
|
|
59
|
+
|
|
60
|
+
html5QrcodeScanner = new Html5Qrcode('h5-scan-reader')
|
|
61
|
+
|
|
62
|
+
await html5QrcodeScanner.start(
|
|
63
|
+
{ facingMode: 'environment' },
|
|
64
|
+
{
|
|
65
|
+
fps: 5,
|
|
66
|
+
// 不设置 qrbox,全屏显示摄像头画面
|
|
67
|
+
},
|
|
68
|
+
(decodedText: string) => {
|
|
69
|
+
console.log('扫码成功:', decodedText)
|
|
70
|
+
// 防抖:短时间内多次触发只处理第一次
|
|
71
|
+
if (!isScanning.value) return
|
|
72
|
+
inputValue.value = decodedText
|
|
73
|
+
emit('scan', decodedText)
|
|
74
|
+
emit('input', decodedText)
|
|
75
|
+
stopScan()
|
|
76
|
+
uni.showToast({ title: '扫描成功', icon: 'success' })
|
|
77
|
+
},
|
|
78
|
+
() => {}, // 忽略中间帧错误
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
catch (error: any) {
|
|
82
|
+
console.error('扫码启动失败:', error)
|
|
83
|
+
let msg = '摄像头访问失败'
|
|
84
|
+
const errMsg = error.message || ''
|
|
85
|
+
if (/Permission|NotAllowed/i.test(errMsg)) msg = '请允许浏览器使用摄像头'
|
|
86
|
+
else if (/NotFound|not found/i.test(errMsg)) msg = '未检测到摄像头设备'
|
|
87
|
+
else if (/secure origin|insecure/i.test(errMsg)) msg = '需要HTTPS环境才能使用摄像头'
|
|
88
|
+
|
|
89
|
+
emit('error', msg)
|
|
90
|
+
isScanning.value = false
|
|
91
|
+
showScanModal.value = false
|
|
92
|
+
uni.showModal({ title: '提示', content: msg, showCancel: false })
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
isLoading.value = false
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async function stopScan() {
|
|
100
|
+
isScanning.value = false
|
|
101
|
+
showScanModal.value = false
|
|
102
|
+
if (html5QrcodeScanner) {
|
|
103
|
+
try {
|
|
104
|
+
if (html5QrcodeScanner.isScanning) await html5QrcodeScanner.stop()
|
|
105
|
+
html5QrcodeScanner.clear()
|
|
106
|
+
}
|
|
107
|
+
catch { /* ignore */ }
|
|
108
|
+
html5QrcodeScanner = null
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// #endif
|
|
112
|
+
|
|
113
|
+
function startUniScanCode() {
|
|
114
|
+
// #ifndef H5
|
|
115
|
+
uni.scanCode({
|
|
116
|
+
success(res: any) {
|
|
117
|
+
inputValue.value = res.result
|
|
118
|
+
emit('scan', res.result)
|
|
119
|
+
emit('input', res.result)
|
|
120
|
+
uni.showToast({ title: '扫描成功', icon: 'success' })
|
|
121
|
+
},
|
|
122
|
+
fail() { emit('error', '扫描已取消') },
|
|
123
|
+
})
|
|
124
|
+
// #endif
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function handleStartScan() {
|
|
128
|
+
// #ifdef H5
|
|
129
|
+
isScanning.value ? stopScan() : startScan()
|
|
130
|
+
// #endif
|
|
131
|
+
// #ifndef H5
|
|
132
|
+
startUniScanCode()
|
|
133
|
+
// #endif
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function handleConfirm() {
|
|
137
|
+
if (inputValue.value.trim()) emit('scan', inputValue.value.trim())
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
onMounted(() => { if (props.autoStart) handleStartScan() })
|
|
141
|
+
onUnmounted(() => { /* #ifdef H5 */ stopScan() /* #endif */ })
|
|
142
|
+
</script>
|
|
143
|
+
|
|
144
|
+
<template>
|
|
145
|
+
<view class="si-wrap">
|
|
146
|
+
<!-- 使用 wot-ui wd-input -->
|
|
147
|
+
<wd-input
|
|
148
|
+
v-model="inputValue"
|
|
149
|
+
class="!pr-3"
|
|
150
|
+
:placeholder="placeholder"
|
|
151
|
+
type="text"
|
|
152
|
+
confirm-type="search"
|
|
153
|
+
clearable
|
|
154
|
+
no-border
|
|
155
|
+
custom-class="si-wd-input"
|
|
156
|
+
@confirm="handleConfirm"
|
|
157
|
+
@change="(val: string) => emit('input', val)"
|
|
158
|
+
suffix-icon="scan"
|
|
159
|
+
@clicksuffixicon="handleStartScan"
|
|
160
|
+
>
|
|
161
|
+
</wd-input>
|
|
162
|
+
|
|
163
|
+
<!-- #ifdef H5 -->
|
|
164
|
+
<!-- 全屏扫码遮罩 -->
|
|
165
|
+
<view v-if="showScanModal" class="si-modal" catchtouchmove>
|
|
166
|
+
<!-- 摄像头区域 -->
|
|
167
|
+
<view class="si-camera-area">
|
|
168
|
+
<!-- 加载中 -->
|
|
169
|
+
<view v-if="isLoading" class="si-loading-mask">
|
|
170
|
+
<view class="si-loading-box">
|
|
171
|
+
<text class="si-loading-text">正在启动摄像头...</text>
|
|
172
|
+
</view>
|
|
173
|
+
</view>
|
|
174
|
+
<!-- 渲染容器 -->
|
|
175
|
+
<div id="h5-scan-reader" class="si-reader" />
|
|
176
|
+
<!-- 扫描框装饰 -->
|
|
177
|
+
<view v-show="isScanning && !isLoading" class="si-scan-frame">
|
|
178
|
+
<view class="si-scan-line" />
|
|
179
|
+
</view>
|
|
180
|
+
</view>
|
|
181
|
+
|
|
182
|
+
<!-- 底部提示 -->
|
|
183
|
+
<view class="si-modal-footer">
|
|
184
|
+
<text class="si-tip">识别二维码 / 条形码 / 商品码等</text>
|
|
185
|
+
</view>
|
|
186
|
+
</view>
|
|
187
|
+
<!-- #endif -->
|
|
188
|
+
</view>
|
|
189
|
+
</template>
|
|
190
|
+
|
|
191
|
+
<!-- 全局样式:html5-qrcode 内部元素 -->
|
|
192
|
+
<style lang="scss">
|
|
193
|
+
#h5-scan-reader {
|
|
194
|
+
width: 100%;
|
|
195
|
+
height: 100%;
|
|
196
|
+
border-radius: inherit;
|
|
197
|
+
display: flex;
|
|
198
|
+
|
|
199
|
+
video {
|
|
200
|
+
border-radius: inherit;
|
|
201
|
+
object-fit: cover;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
#qr-shaded-region {
|
|
205
|
+
border-radius: inherit;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
209
|
+
|
|
210
|
+
<style scoped lang="scss">
|
|
211
|
+
.si-wrap {
|
|
212
|
+
width: 100%;
|
|
213
|
+
padding: 16rpx;
|
|
214
|
+
box-sizing: border-box;
|
|
215
|
+
|
|
216
|
+
// ---- wot-ui 输入框容器 ----
|
|
217
|
+
:deep(.si-wd-input) {
|
|
218
|
+
background: #f6f7f9;
|
|
219
|
+
border-radius: 10rpx;
|
|
220
|
+
border: 2rpx solid #eaecef;
|
|
221
|
+
padding-right: 4rpx;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// ---- 全屏扫码遮罩 ----
|
|
225
|
+
.si-modal {
|
|
226
|
+
position: fixed;
|
|
227
|
+
top: 0; left: 0; right: 0; bottom: 0;
|
|
228
|
+
z-index: 999;
|
|
229
|
+
background: #000;
|
|
230
|
+
display: flex;
|
|
231
|
+
flex-direction: column;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.si-camera-area {
|
|
235
|
+
flex: 1;
|
|
236
|
+
width: 100%;
|
|
237
|
+
position: relative;
|
|
238
|
+
overflow: hidden;
|
|
239
|
+
|
|
240
|
+
.si-reader {
|
|
241
|
+
position: absolute;
|
|
242
|
+
top: 50%;
|
|
243
|
+
left: 0;
|
|
244
|
+
transform: translateY(-50%);
|
|
245
|
+
width: 100%;
|
|
246
|
+
height: 50vh;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ---- 扫描框(覆盖在 reader 上方) ----
|
|
250
|
+
.si-scan-frame {
|
|
251
|
+
position: absolute;
|
|
252
|
+
top: 50%;
|
|
253
|
+
left: 0;
|
|
254
|
+
transform: translateY(-50%);
|
|
255
|
+
width: 100%;
|
|
256
|
+
height: 50vh;
|
|
257
|
+
pointer-events: none;
|
|
258
|
+
z-index: 5;
|
|
259
|
+
overflow: hidden;
|
|
260
|
+
|
|
261
|
+
.si-scan-line {
|
|
262
|
+
position: absolute;
|
|
263
|
+
top: 0;
|
|
264
|
+
left: 10rpx;
|
|
265
|
+
right: 10rpx;
|
|
266
|
+
height: 6rpx;
|
|
267
|
+
background: #07C160;
|
|
268
|
+
border-radius: 3rpx;
|
|
269
|
+
box-shadow: 0 0 20rpx 4rpx rgba(7,193,96,0.7);
|
|
270
|
+
animation: si-sweep 2.5s ease-in-out infinite;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.si-loading-mask {
|
|
275
|
+
position: absolute;
|
|
276
|
+
top: 50%;
|
|
277
|
+
left: 50%;
|
|
278
|
+
transform: translate(-50%, -50%);
|
|
279
|
+
z-index: 10;
|
|
280
|
+
|
|
281
|
+
.si-loading-box {
|
|
282
|
+
background: rgba(0,0,0,0.75);
|
|
283
|
+
padding: 30rpx 48rpx;
|
|
284
|
+
border-radius: 16rpx;
|
|
285
|
+
|
|
286
|
+
.si-loading-text {
|
|
287
|
+
color: #fff;
|
|
288
|
+
font-size: 28rpx;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.si-modal-footer {
|
|
295
|
+
padding: 40rpx 32rpx 80rpx;
|
|
296
|
+
text-align: center;
|
|
297
|
+
flex-shrink: 0;
|
|
298
|
+
|
|
299
|
+
.si-tip {
|
|
300
|
+
color: rgba(255,255,255,0.65);
|
|
301
|
+
font-size: 26rpx;
|
|
302
|
+
letter-spacing: 2rpx;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
@keyframes si-sweep {
|
|
308
|
+
0% { top: 0; opacity: 1; }
|
|
309
|
+
50% { opacity: 1; }
|
|
310
|
+
100% { top: calc(100% - 4rpx); opacity: 0.3; }
|
|
311
|
+
}
|
|
312
|
+
</style>
|
|
@@ -66,7 +66,6 @@ const fetchDataById = async (id: string) => {
|
|
|
66
66
|
if (!id || !props.sourceId) return
|
|
67
67
|
const newId=Array.isArray(id)?id[0]:id
|
|
68
68
|
const requestId = newId?.split('@R@')[0] || props.sourceId
|
|
69
|
-
console.log('fetchDataById', requestId, props.sourceId,id)
|
|
70
69
|
try {
|
|
71
70
|
const config = await pageConfig(props.sourceId)
|
|
72
71
|
const newConfig=config.ltmplConfig
|
|
@@ -96,18 +95,17 @@ const emitIfNeeded = (val: string) => {
|
|
|
96
95
|
emitVal = val + '@R@' + showValue.name
|
|
97
96
|
}
|
|
98
97
|
if (emitVal !== props.modelValue) {
|
|
99
|
-
console.log('emit update:modelValue', emitVal)
|
|
100
98
|
emit('update:modelValue', emitVal)
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
onMounted(() => {
|
|
105
103
|
if (currentValue.value) {
|
|
106
|
-
|
|
104
|
+
const requestId= currentValue.value.includes('$$user.')? currentValue.value.split('$$user.')[1] : currentValue.value
|
|
105
|
+
fetchDataById(requestId)
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
uni.$on(EVENT_NAME, (id: string) => {
|
|
110
|
-
console.log('user-choose 接收到id:', id)
|
|
111
109
|
currentValue.value = id
|
|
112
110
|
fetchDataById(id)
|
|
113
111
|
})
|
|
@@ -95,6 +95,7 @@ async function getPageConfig() {
|
|
|
95
95
|
const res = await pageConfig(sourceId.value)
|
|
96
96
|
if (res.ltmplConfig) {
|
|
97
97
|
config.value = res.ltmplConfig
|
|
98
|
+
console.log('config', config.value)
|
|
98
99
|
getEnums()
|
|
99
100
|
}
|
|
100
101
|
}
|
|
@@ -175,19 +176,18 @@ function tabSearchClick(data: any) {
|
|
|
175
176
|
>
|
|
176
177
|
<template #top>
|
|
177
178
|
<slot name="top" />
|
|
178
|
-
<view class="flex items-center pl-3 bg-white">
|
|
179
|
-
<ListTopButtons
|
|
180
|
-
:add-event="addEvent" :main-code="mainCode" :buttons="config.buttons" :source-id="sourceId"
|
|
181
|
-
:page-title="pageTitle" :page-type="pageType"
|
|
182
|
-
/>
|
|
183
179
|
<Search
|
|
184
180
|
:main-code="mainCode" :enum-column="enumColumn" :criterias="config.criterias"
|
|
185
181
|
:primary-criteria="config.primaryCriteria" :split2-tab-criterias="config.split2TabCriterias"
|
|
186
182
|
@submit="submitSearch"
|
|
187
183
|
/>
|
|
184
|
+
<view>
|
|
185
|
+
<ListTopButtons
|
|
186
|
+
:add-event="addEvent" :main-code="mainCode" :buttons="config.buttons" :source-id="sourceId"
|
|
187
|
+
:page-title="pageTitle" :page-type="pageType"
|
|
188
|
+
:config="config"
|
|
189
|
+
/>
|
|
188
190
|
</view>
|
|
189
|
-
|
|
190
|
-
|
|
191
191
|
<!-- 自定义tab搜索 -->
|
|
192
192
|
<view v-if="config.split2TabCriterias">
|
|
193
193
|
<tabSearch :split2-tab-criterias="config.split2TabCriterias" :enums="enumColumn" @click="tabSearchClick" />
|
|
@@ -141,6 +141,7 @@ async function getEnums() {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
|
|
144
145
|
// @query所绑定的方法不要自己调用!!需要刷新列表数据时,只需要调用this.$refs.paging.reload()即可
|
|
145
146
|
async function queryList(pageNo: number, pageSize: number) {
|
|
146
147
|
// 此处请求仅为演示,请替换为自己项目中的请求
|
|
@@ -155,7 +156,16 @@ async function queryList(pageNo: number, pageSize: number) {
|
|
|
155
156
|
// paging.value.reload() // 手动触发加载
|
|
156
157
|
// })
|
|
157
158
|
|
|
158
|
-
|
|
159
|
+
const search=uni.getStorageSync('paramsData')?.changedData || {}
|
|
160
|
+
const newParams={
|
|
161
|
+
thirdCriteria:search.relValueField3 || '',
|
|
162
|
+
secondCriteria:search.relValueField?.toString() || '',
|
|
163
|
+
|
|
164
|
+
}
|
|
165
|
+
const params = Object.entries(newParams)
|
|
166
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
167
|
+
.join('&');
|
|
168
|
+
let qre = searchData.value?`${searchData.value+'&'+params}`:params
|
|
159
169
|
if (config.value.defaultCriteriaValue) {
|
|
160
170
|
for (const key in config.value.defaultCriteriaValue) {
|
|
161
171
|
if (Object.prototype.hasOwnProperty.call(config.value.defaultCriteriaValue, key)) {
|
|
@@ -237,6 +247,9 @@ const formatAddress = (value:string) => {
|
|
|
237
247
|
const checkboxType:any=computed(()=>{
|
|
238
248
|
return ['relselect','relselect-extdis'].includes(extControlType.value)?'':'square'
|
|
239
249
|
})
|
|
250
|
+
onUnmounted(() => {
|
|
251
|
+
uni.removeStorageSync('paramsData')
|
|
252
|
+
})
|
|
240
253
|
</script>
|
|
241
254
|
|
|
242
255
|
<template>
|
|
@@ -6,6 +6,9 @@ import {
|
|
|
6
6
|
import { useUser } from '../../composables/useUser'
|
|
7
7
|
import { generateGradientColor } from '../../utils'
|
|
8
8
|
import { useManualTheme } from '../../composables/useManualTheme'
|
|
9
|
+
import scan from '../scan-input/scan-input.vue'
|
|
10
|
+
import { getUserConfig } from '../../api/login'
|
|
11
|
+
import { useGlobalToast } from '../../composables/useGlobalToast'
|
|
9
12
|
|
|
10
13
|
defineOptions({
|
|
11
14
|
name: 'WuiUser',
|
|
@@ -21,6 +24,7 @@ const {
|
|
|
21
24
|
} = useManualTheme()
|
|
22
25
|
const user = useUser().getUserInfo()
|
|
23
26
|
const dialog = useDialog()
|
|
27
|
+
const toast = useGlobalToast()
|
|
24
28
|
const userInfo = ref({
|
|
25
29
|
name: user.name,
|
|
26
30
|
nickName: user.nickName,
|
|
@@ -50,6 +54,14 @@ function setting() {
|
|
|
50
54
|
url: '/pages/system-settings/index',
|
|
51
55
|
})
|
|
52
56
|
}
|
|
57
|
+
async function clearCache() {
|
|
58
|
+
// uni.removeStorageSync('userInfo')
|
|
59
|
+
const res= await getUserConfig();
|
|
60
|
+
if(res.status=='success') {
|
|
61
|
+
toast.success({ msg: '清除成功!' })
|
|
62
|
+
uni.setStorageSync('userInfo', res.user)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
53
65
|
|
|
54
66
|
// 查看用户信息
|
|
55
67
|
// function goUserInfo() {
|
|
@@ -60,6 +72,7 @@ function setting() {
|
|
|
60
72
|
</script>
|
|
61
73
|
|
|
62
74
|
<template>
|
|
75
|
+
<!-- <scan/> -->
|
|
63
76
|
<view class="user">
|
|
64
77
|
<view class="top-box">
|
|
65
78
|
<!-- 用户头部信息 -->
|
|
@@ -87,6 +100,7 @@ function setting() {
|
|
|
87
100
|
<!-- <wd-cell title="修改密码" icon="keywords" :is-link="true" :clickable="true" /> -->
|
|
88
101
|
<wd-cell title="系统设置" icon="setting" :is-link="true" :clickable="true" @click="setting" />
|
|
89
102
|
<wd-cell title="退出登录" icon="logout" :is-link="true" :clickable="true" @click="quit" />
|
|
103
|
+
<wd-cell title="清空缓存" :is-link="true" :clickable="true" @click="clearCache" />
|
|
90
104
|
</wd-cell-group>
|
|
91
105
|
<wd-dialog />
|
|
92
106
|
</view>
|
|
@@ -41,7 +41,7 @@ export function useCompanyFieldFilter(
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const formatFieldsItem=(company:string,item:any)=>{
|
|
44
|
-
const transDefaultValue = item.usableRuleCriterias[0]?.transDefaultValue||''
|
|
44
|
+
const transDefaultValue = item.usableRuleCriterias?.[0]?.transDefaultValue||''
|
|
45
45
|
const isHidden=item?.unusableMode==='hidden'
|
|
46
46
|
const values = transDefaultValue.split(',').map(v => v.trim())
|
|
47
47
|
if(!company){
|
|
@@ -73,7 +73,7 @@ export function useCompanyFieldFilter(
|
|
|
73
73
|
return true
|
|
74
74
|
}
|
|
75
75
|
// 获取 transDefaultValue 并检查是否包含选中的公司
|
|
76
|
-
const transDefaultValue = item.usableRuleCriterias[0]?.transDefaultValue
|
|
76
|
+
const transDefaultValue = item.usableRuleCriterias?.[0]?.transDefaultValue
|
|
77
77
|
if (typeof transDefaultValue === 'string') {
|
|
78
78
|
const values = transDefaultValue.split(',').map(v => v.trim())
|
|
79
79
|
// console.log('transDefaultValue', company, 'values', values,values.includes(company))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wui-components-v2",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.56",
|
|
4
4
|
"description": "wui 组件库",
|
|
5
5
|
"author": "wgxshh",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"@wot-ui/ui": "^2.0.8",
|
|
17
17
|
"china-address-parse": "^1.2.1",
|
|
18
18
|
"dayjs": "^1.11.20",
|
|
19
|
+
"html5-qrcode": "^2.3.8",
|
|
19
20
|
"jsencrypt": "^3.3.2",
|
|
20
21
|
"sass": "^1.100.0",
|
|
21
22
|
"z-paging": "^2.8.5"
|
package/store/language.ts
CHANGED
|
@@ -48,7 +48,7 @@ export const useLanguageStore = defineStore('language', () => {
|
|
|
48
48
|
* 加载并设置语言
|
|
49
49
|
*/
|
|
50
50
|
const loadLanguage = async (lang: string): Promise<void> => {
|
|
51
|
-
console.log(`网络加载语言 ${lang}...`)
|
|
51
|
+
// console.log(`网络加载语言 ${lang}...`)
|
|
52
52
|
if (loadedLanguages.value.includes(lang)) {
|
|
53
53
|
currentLanguage.value = lang
|
|
54
54
|
return
|
|
@@ -129,7 +129,7 @@ export const useManualThemeStore = defineStore('manualTheme', {
|
|
|
129
129
|
this.theme = systemTheme
|
|
130
130
|
if (!this.hasUserSet) {
|
|
131
131
|
this.followSystem = true
|
|
132
|
-
console.log('首次启动,使用系统主题:', this.theme)
|
|
132
|
+
// console.log('首次启动,使用系统主题:', this.theme)
|
|
133
133
|
}
|
|
134
134
|
else {
|
|
135
135
|
console.log('跟随系统主题:', this.theme)
|