af-mobile-client-vue3 1.3.96 → 1.3.98
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/package.json +1 -1
- package/src/components/core/ImageUploader/index.vue +1 -1
- package/src/components/core/XMultiSelect/index.vue +41 -1
- package/src/components/core/XSelect/index.vue +120 -30
- package/src/components/data/XFormItem/index.vue +107 -1
- package/src/components/data/XOlMap/types.ts +1 -1
- package/src/views/component/XCellListView/index.vue +1 -11
- package/src/views/component/XOlMapView/XLocationPicker/index.vue +118 -118
package/package.json
CHANGED
|
@@ -225,7 +225,7 @@ function handlePhotoUpload(photoData: any) {
|
|
|
225
225
|
f_operator: 'server',
|
|
226
226
|
imgPath: photoData.filePath,
|
|
227
227
|
urlPath: `/api/${import.meta.env.VITE_APP_SYSTEM_NAME}/resource/upload`,
|
|
228
|
-
commonId: parentData
|
|
228
|
+
commonId: parentData?.commonId?.value ?? '',
|
|
229
229
|
}
|
|
230
230
|
if (props.isAsyncUpload) {
|
|
231
231
|
// 添加上传队列
|
|
@@ -34,6 +34,14 @@ const props = defineProps({
|
|
|
34
34
|
type: Boolean,
|
|
35
35
|
default: true,
|
|
36
36
|
},
|
|
37
|
+
lazyLoad: { // 是否启用懒加载
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'false',
|
|
40
|
+
},
|
|
41
|
+
onSearch: { // 懒加载时的搜索函数
|
|
42
|
+
type: Function,
|
|
43
|
+
default: null,
|
|
44
|
+
},
|
|
37
45
|
})
|
|
38
46
|
const emits = defineEmits(['input', 'confirm', 'change', 'cancel'])
|
|
39
47
|
const show = ref(false)
|
|
@@ -44,7 +52,24 @@ const checkedAll = ref(false)
|
|
|
44
52
|
const resultValue = defineModel()
|
|
45
53
|
const checkboxGroup = ref()
|
|
46
54
|
const checkboxes = ref()
|
|
55
|
+
const isLoading = ref(false)
|
|
47
56
|
function search(val) {
|
|
57
|
+
// 如果是懒加载模式
|
|
58
|
+
if (props.lazyLoad && props.lazyLoad === 'true' && props.onSearch) {
|
|
59
|
+
isLoading.value = true
|
|
60
|
+
// 调用父组件传递的搜索函数
|
|
61
|
+
props.onSearch(val).then((results) => {
|
|
62
|
+
columnsData.value = results || []
|
|
63
|
+
isLoading.value = false
|
|
64
|
+
}).catch((error) => {
|
|
65
|
+
console.error('懒加载搜索失败:', error)
|
|
66
|
+
columnsData.value = []
|
|
67
|
+
isLoading.value = false
|
|
68
|
+
})
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 普通搜索模式
|
|
48
73
|
if (val) {
|
|
49
74
|
columnsData.value = props.columns.filter((item) => {
|
|
50
75
|
return item[props.option.text].includes(val)
|
|
@@ -140,7 +165,12 @@ const resultLabel = computed(() => {
|
|
|
140
165
|
@update:model-value="search"
|
|
141
166
|
@cancel="search"
|
|
142
167
|
/>
|
|
143
|
-
<div class="
|
|
168
|
+
<div v-if="isLoading" class="loading-container">
|
|
169
|
+
<div class="loading-text">
|
|
170
|
+
搜索中...
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<div v-else class="x-multi-select-checkbox-group">
|
|
144
174
|
<VanCell title="全选">
|
|
145
175
|
<template #right-icon>
|
|
146
176
|
<VanCheckbox v-model="checkedAll" name="all" @click="toggleAll" />
|
|
@@ -185,6 +215,16 @@ const resultLabel = computed(() => {
|
|
|
185
215
|
padding: 0 16px;
|
|
186
216
|
}
|
|
187
217
|
}
|
|
218
|
+
.loading-container {
|
|
219
|
+
display: flex;
|
|
220
|
+
justify-content: center;
|
|
221
|
+
align-items: center;
|
|
222
|
+
height: 200px;
|
|
223
|
+
}
|
|
224
|
+
.loading-text {
|
|
225
|
+
color: #969799;
|
|
226
|
+
font-size: 14px;
|
|
227
|
+
}
|
|
188
228
|
//.van-popup {
|
|
189
229
|
// border-radius: 20px 20px 0 0;
|
|
190
230
|
//}
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
Field as VanField,
|
|
4
4
|
Picker as VanPicker,
|
|
5
5
|
Popup as VanPopup,
|
|
6
|
+
Search as VanSearch,
|
|
6
7
|
} from 'vant'
|
|
7
8
|
import { computed, defineEmits, defineModel, defineProps, onBeforeMount, ref, watch } from 'vue'
|
|
8
9
|
|
|
@@ -19,10 +20,6 @@ const props = defineProps({
|
|
|
19
20
|
return { text: 'label', value: 'value', children: 'children' }
|
|
20
21
|
},
|
|
21
22
|
},
|
|
22
|
-
isSearch: {
|
|
23
|
-
type: Boolean,
|
|
24
|
-
default: false,
|
|
25
|
-
},
|
|
26
23
|
offOption: { // 关闭option配置key-value;当数据是非集合的数组的时候,开启
|
|
27
24
|
type: Boolean,
|
|
28
25
|
default: false,
|
|
@@ -31,13 +28,23 @@ const props = defineProps({
|
|
|
31
28
|
type: Boolean,
|
|
32
29
|
default: false,
|
|
33
30
|
},
|
|
31
|
+
lazyLoad: { // 是否启用懒加载
|
|
32
|
+
type: String,
|
|
33
|
+
default: 'false',
|
|
34
|
+
},
|
|
35
|
+
onSearch: { // 懒加载时的搜索函数
|
|
36
|
+
type: Function,
|
|
37
|
+
default: null,
|
|
38
|
+
},
|
|
34
39
|
})
|
|
35
40
|
const emits = defineEmits(['confirm', 'change', 'cancel', 'input'])
|
|
36
41
|
const show = ref(false)
|
|
37
|
-
const searchVal = ref('')
|
|
38
42
|
const resultValue = defineModel()
|
|
39
43
|
const columnsData = ref([])
|
|
40
44
|
const selectedOption = ref([])
|
|
45
|
+
const searchValue = ref('')
|
|
46
|
+
const filteredColumns = ref([])
|
|
47
|
+
const isLoading = ref(false)
|
|
41
48
|
|
|
42
49
|
// 转换空children为空字符串
|
|
43
50
|
function transformColumns(data) {
|
|
@@ -57,8 +64,68 @@ function transformColumns(data) {
|
|
|
57
64
|
})
|
|
58
65
|
}
|
|
59
66
|
|
|
67
|
+
// 搜索过滤函数
|
|
68
|
+
function handleSearch(value) {
|
|
69
|
+
// 确保 value 是字符串
|
|
70
|
+
const searchText = typeof value === 'string' ? value : value?.target?.value || ''
|
|
71
|
+
searchValue.value = searchText
|
|
72
|
+
|
|
73
|
+
// 如果是懒加载模式
|
|
74
|
+
if (props.lazyLoad && props.lazyLoad === 'true' && props.onSearch) {
|
|
75
|
+
if (!searchText) {
|
|
76
|
+
filteredColumns.value = []
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
isLoading.value = true
|
|
81
|
+
// 调用父组件传递的搜索函数
|
|
82
|
+
props.onSearch(searchText).then((results) => {
|
|
83
|
+
filteredColumns.value = transformColumns(results || [])
|
|
84
|
+
isLoading.value = false
|
|
85
|
+
}).catch((error) => {
|
|
86
|
+
console.error('懒加载搜索失败:', error)
|
|
87
|
+
filteredColumns.value = []
|
|
88
|
+
isLoading.value = false
|
|
89
|
+
})
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// 普通搜索模式
|
|
94
|
+
if (!searchText) {
|
|
95
|
+
filteredColumns.value = columnsData.value
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const searchTextLower = searchText.toLowerCase()
|
|
100
|
+
|
|
101
|
+
filteredColumns.value = columnsData.value.filter((item) => {
|
|
102
|
+
const text = props.offOption ? item : item[props.option.text]
|
|
103
|
+
return text?.toString().toLowerCase().includes(searchTextLower)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 清空搜索
|
|
108
|
+
function handleSearchClear() {
|
|
109
|
+
searchValue.value = ''
|
|
110
|
+
if (props.lazyLoad) {
|
|
111
|
+
// 懒加载模式:清空搜索时重新获取初始数据
|
|
112
|
+
if (props.onSearch) {
|
|
113
|
+
props.onSearch('').then((results) => {
|
|
114
|
+
filteredColumns.value = transformColumns(results || [])
|
|
115
|
+
}).catch((error) => {
|
|
116
|
+
console.error('清空搜索后数据加载失败:', error)
|
|
117
|
+
filteredColumns.value = []
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
filteredColumns.value = columnsData.value
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
60
126
|
onBeforeMount(() => {
|
|
61
127
|
columnsData.value = transformColumns(props.columns)
|
|
128
|
+
filteredColumns.value = columnsData.value
|
|
62
129
|
})
|
|
63
130
|
|
|
64
131
|
const resultLabel = computed({
|
|
@@ -76,18 +143,6 @@ const resultLabel = computed({
|
|
|
76
143
|
},
|
|
77
144
|
})
|
|
78
145
|
|
|
79
|
-
function search(val) {
|
|
80
|
-
if (val) {
|
|
81
|
-
columnsData.value = transformColumns(columnsData.value).filter((item) => {
|
|
82
|
-
const data = props.offOption ? item : item[props.option.text]
|
|
83
|
-
return data.includes(val)
|
|
84
|
-
})
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
columnsData.value = transformColumns(props.columns)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
146
|
function onConfirm(value, _index) {
|
|
92
147
|
resultValue.value = props.offOption ? value.selectedValues : value.selectedValues[0]
|
|
93
148
|
// resultValue.value = value.selectedValues
|
|
@@ -109,14 +164,23 @@ function showPopu(disabled) {
|
|
|
109
164
|
if (disabled !== undefined && disabled !== false)
|
|
110
165
|
return false
|
|
111
166
|
columnsData.value = transformColumns(props.columns)
|
|
167
|
+
filteredColumns.value = columnsData.value
|
|
168
|
+
searchValue.value = '' // 重置搜索
|
|
112
169
|
show.value = !show.value
|
|
113
170
|
}
|
|
114
171
|
|
|
115
172
|
watch(() => resultValue, (newVal, _oldVal) => {
|
|
116
|
-
searchVal.value = ''
|
|
117
173
|
columnsData.value = transformColumns(props.columns)
|
|
174
|
+
filteredColumns.value = columnsData.value
|
|
118
175
|
emits('input', newVal)
|
|
119
176
|
})
|
|
177
|
+
|
|
178
|
+
// 监听 columns 变化
|
|
179
|
+
watch(() => props.columns, () => {
|
|
180
|
+
columnsData.value = transformColumns(props.columns)
|
|
181
|
+
filteredColumns.value = columnsData.value
|
|
182
|
+
searchValue.value = ''
|
|
183
|
+
}, { deep: true })
|
|
120
184
|
</script>
|
|
121
185
|
|
|
122
186
|
<template>
|
|
@@ -129,20 +193,46 @@ watch(() => resultValue, (newVal, _oldVal) => {
|
|
|
129
193
|
@click="showPopu($attrs.readonly)"
|
|
130
194
|
/>
|
|
131
195
|
<VanPopup v-model:show="show" position="bottom">
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
196
|
+
<div class="x-select-popup">
|
|
197
|
+
<!-- 搜索框 -->
|
|
198
|
+
<VanSearch
|
|
199
|
+
v-model="searchValue"
|
|
200
|
+
placeholder="搜索"
|
|
201
|
+
@clear="handleSearchClear"
|
|
202
|
+
@input="handleSearch"
|
|
203
|
+
/>
|
|
204
|
+
|
|
205
|
+
<!-- 选择器 -->
|
|
206
|
+
<div v-if="isLoading" class="loading-container">
|
|
207
|
+
<div class="loading-text">
|
|
208
|
+
搜索中...
|
|
209
|
+
</div>
|
|
210
|
+
</div>
|
|
211
|
+
<VanPicker
|
|
212
|
+
v-else
|
|
213
|
+
v-bind="$attrs"
|
|
214
|
+
:columns="filteredColumns"
|
|
215
|
+
:columns-field-names="props.option"
|
|
216
|
+
show-toolbar
|
|
217
|
+
:value-key="props.option.text"
|
|
218
|
+
@cancel="cancel"
|
|
219
|
+
@confirm="onConfirm"
|
|
220
|
+
@change="change"
|
|
221
|
+
/>
|
|
222
|
+
</div>
|
|
143
223
|
</VanPopup>
|
|
144
224
|
</template>
|
|
145
225
|
|
|
146
226
|
<style scoped>
|
|
147
|
-
|
|
227
|
+
.loading-container {
|
|
228
|
+
display: flex;
|
|
229
|
+
justify-content: center;
|
|
230
|
+
align-items: center;
|
|
231
|
+
height: 200px;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.loading-text {
|
|
235
|
+
color: #969799;
|
|
236
|
+
font-size: 14px;
|
|
237
|
+
}
|
|
148
238
|
</style>
|
|
@@ -169,6 +169,8 @@ const showArea = ref(false)
|
|
|
169
169
|
const errorMessage = ref('')
|
|
170
170
|
const showTreeSelect = ref(false)
|
|
171
171
|
const treeValue = ref('')
|
|
172
|
+
// 懒加载 最后检索版本
|
|
173
|
+
const lastFetchId = ref(0)
|
|
172
174
|
|
|
173
175
|
// 登录信息 (可以在配置的动态函数中使用 this.setupState 获取到当前组件内的全部函数和变量 例:this.setupState.userState)
|
|
174
176
|
const userState = useUserStore().getLogin()
|
|
@@ -917,6 +919,106 @@ function findOptionInTree(options, value) {
|
|
|
917
919
|
return null
|
|
918
920
|
}
|
|
919
921
|
|
|
922
|
+
// 懒加载搜索函数
|
|
923
|
+
async function handleLazySearch(searchText: string) {
|
|
924
|
+
if (!attr.keyName || typeof attr.keyName !== 'string') {
|
|
925
|
+
return []
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
try {
|
|
929
|
+
// 如果是 search@ 类型的数据源
|
|
930
|
+
if (attr.keyName.includes('search@')) {
|
|
931
|
+
let source = attr.keyName.substring(7)
|
|
932
|
+
const userid = currUser.value
|
|
933
|
+
let roleName = 'roleName'
|
|
934
|
+
|
|
935
|
+
if (source.startsWith('根据角色[') && source.endsWith(']获取人员')) {
|
|
936
|
+
const startIndex = source.indexOf('[') + 1
|
|
937
|
+
const endIndex = source.indexOf(']', startIndex)
|
|
938
|
+
roleName = source.substring(startIndex, endIndex)
|
|
939
|
+
source = '根据角色获取人员'
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
const searchData = {
|
|
943
|
+
source,
|
|
944
|
+
userid,
|
|
945
|
+
roleName,
|
|
946
|
+
searchText, // 添加搜索关键词
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
return new Promise((resolve) => {
|
|
950
|
+
if (attr.type === 'select' || attr.type === 'checkbox') {
|
|
951
|
+
searchToListOption(searchData, (res) => {
|
|
952
|
+
// 根据搜索关键词过滤结果
|
|
953
|
+
const filtered = res.filter((item) => {
|
|
954
|
+
const text = item[columnsField.value.text] || item.label || ''
|
|
955
|
+
return text.toString().toLowerCase().includes(searchText.toLowerCase())
|
|
956
|
+
})
|
|
957
|
+
resolve(filtered)
|
|
958
|
+
})
|
|
959
|
+
}
|
|
960
|
+
else {
|
|
961
|
+
searchToOption(searchData, (res) => {
|
|
962
|
+
const filtered = res.filter((item) => {
|
|
963
|
+
const text = item[columnsField.value.text] || item.label || ''
|
|
964
|
+
return text.toString().toLowerCase().includes(searchText.toLowerCase())
|
|
965
|
+
})
|
|
966
|
+
resolve(filtered)
|
|
967
|
+
})
|
|
968
|
+
}
|
|
969
|
+
})
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
// logic 数据源
|
|
973
|
+
if (attr.keyName.includes('logic@')) {
|
|
974
|
+
const logicName = attr.keyName.substring(6)
|
|
975
|
+
const value = { word: searchText, ...userInfo.value }
|
|
976
|
+
|
|
977
|
+
// 调用logic前设置参数
|
|
978
|
+
if (getDataParams && getDataParams[attr.model]) {
|
|
979
|
+
Object.assign(value, getDataParams[attr.model])
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
lastFetchId.value++
|
|
983
|
+
const fetchId = this.lastFetchId
|
|
984
|
+
// 根据搜索关键词过滤结果
|
|
985
|
+
const results = await runLogic(logicName, value, serviceName) as any
|
|
986
|
+
if (fetchId !== lastFetchId.value) {
|
|
987
|
+
return
|
|
988
|
+
}
|
|
989
|
+
if (searchText) {
|
|
990
|
+
return results.filter((item) => {
|
|
991
|
+
const text = item[columnsField.value.text] || item.label || ''
|
|
992
|
+
return text.toString().toLowerCase().includes(searchText.toLowerCase())
|
|
993
|
+
})
|
|
994
|
+
}
|
|
995
|
+
return results
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
// 自定义 js 函数
|
|
999
|
+
if (attr.keyName.includes('async ') || attr.keyName.includes('function ')) {
|
|
1000
|
+
const results = await executeStrFunctionByContext(currInst, attr.keyName, [
|
|
1001
|
+
{ ...props.form, searchText },
|
|
1002
|
+
runLogic,
|
|
1003
|
+
props.mode,
|
|
1004
|
+
getConfigByNameAsync,
|
|
1005
|
+
post,
|
|
1006
|
+
])
|
|
1007
|
+
// 根据搜索关键词过滤结果
|
|
1008
|
+
return results.filter((item) => {
|
|
1009
|
+
const text = item[columnsField.value.text] || item.label || ''
|
|
1010
|
+
return text.toString().toLowerCase().includes(searchText.toLowerCase())
|
|
1011
|
+
})
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
return []
|
|
1015
|
+
}
|
|
1016
|
+
catch (error) {
|
|
1017
|
+
console.error('懒加载搜索失败:', error)
|
|
1018
|
+
return []
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
920
1022
|
// 扫码/NFC
|
|
921
1023
|
function scanCodeOrNfc(attr) {
|
|
922
1024
|
if (attr.type === 'scanCode') {
|
|
@@ -1015,7 +1117,7 @@ function scanCodeOrNfc(attr) {
|
|
|
1015
1117
|
</VanField>
|
|
1016
1118
|
<!-- 下拉 -->
|
|
1017
1119
|
<XMultiSelect
|
|
1018
|
-
v-if="attr.showMode === 'select' && mode === '查询'"
|
|
1120
|
+
v-if="(!attr.showMode || attr.showMode === 'select') && mode === '查询'"
|
|
1019
1121
|
v-model="modelData"
|
|
1020
1122
|
:label="labelData"
|
|
1021
1123
|
:readonly="readonly"
|
|
@@ -1025,6 +1127,8 @@ function scanCodeOrNfc(attr) {
|
|
|
1025
1127
|
:option="attr.option ? attr.option : columnsField"
|
|
1026
1128
|
:rules="[{ required: attr.rule.required === 'true', message: `请选择${attr.name}` }]"
|
|
1027
1129
|
:required="attr.rule.required === 'true'"
|
|
1130
|
+
:lazy-load="attr.lazyLoad"
|
|
1131
|
+
:on-search="attr.lazyLoad ? handleLazySearch : null"
|
|
1028
1132
|
/>
|
|
1029
1133
|
</template>
|
|
1030
1134
|
|
|
@@ -1329,6 +1433,8 @@ function scanCodeOrNfc(attr) {
|
|
|
1329
1433
|
:option="attr.option ? attr.option : columnsField"
|
|
1330
1434
|
:rules="[{ required: attr.rule.required === 'true', message: `请选择${attr.name}` }]"
|
|
1331
1435
|
:required="attr.rule.required === 'true'"
|
|
1436
|
+
:lazy-load="attr.lazyLoad"
|
|
1437
|
+
:on-search="attr.lazyLoad ? handleLazySearch : null"
|
|
1332
1438
|
/>
|
|
1333
1439
|
|
|
1334
1440
|
<!-- 文本区域 -->
|
|
@@ -12,7 +12,7 @@ const router = useRouter()
|
|
|
12
12
|
// const idKey = ref('o_id')
|
|
13
13
|
|
|
14
14
|
// 简易crud表单测试
|
|
15
|
-
const configName = ref('
|
|
15
|
+
const configName = ref('ceshiCRUD')
|
|
16
16
|
const serviceName = ref('af-safecheck')
|
|
17
17
|
|
|
18
18
|
// 资源权限测试
|
|
@@ -90,14 +90,6 @@ const serviceName = ref('af-safecheck')
|
|
|
90
90
|
// const fixQueryForm = ref({
|
|
91
91
|
// f_operator_id: '487184754014158848',
|
|
92
92
|
// })
|
|
93
|
-
function phone(row: any) {
|
|
94
|
-
console.log('>>>> phone')
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function mapView() {
|
|
98
|
-
// 进行地图查看
|
|
99
|
-
console.log('等待你处理地图查看事件')
|
|
100
|
-
}
|
|
101
93
|
</script>
|
|
102
94
|
|
|
103
95
|
<template>
|
|
@@ -106,8 +98,6 @@ function mapView() {
|
|
|
106
98
|
<XCellList
|
|
107
99
|
:config-name="configName"
|
|
108
100
|
:service-name="serviceName"
|
|
109
|
-
@phone="phone"
|
|
110
|
-
@map-marked="mapView"
|
|
111
101
|
/>
|
|
112
102
|
</template>
|
|
113
103
|
</NormalDataLayout>
|
|
@@ -1,118 +1,118 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import type { LocationResult } from '@af-mobile-client-vue3/components/data/XOlMap/types'
|
|
3
|
-
import LocationPicker from '@af-mobile-client-vue3/components/data/XOlMap/XLocationPicker/index.vue'
|
|
4
|
-
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
5
|
-
import { showNotify } from 'vant'
|
|
6
|
-
import { ref } from 'vue'
|
|
7
|
-
|
|
8
|
-
const selectedLocation = ref<LocationResult>()
|
|
9
|
-
|
|
10
|
-
// 处理位置选择
|
|
11
|
-
function handleLocationConfirm(location: LocationResult) {
|
|
12
|
-
// console.log('选择的位置:', location)
|
|
13
|
-
// selectedLocation.value = location
|
|
14
|
-
showNotify({ type: 'success', message: '位置已选择' })
|
|
15
|
-
}
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<template>
|
|
19
|
-
<NormalDataLayout id="XLocationPicker" title="XOlMap地址选择器">
|
|
20
|
-
<template #layout_content>
|
|
21
|
-
<div class="location-picker-demo">
|
|
22
|
-
<!-- 页面标题 -->
|
|
23
|
-
<div class="page-header">
|
|
24
|
-
<div class="title">
|
|
25
|
-
位置选择
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<!-- 选择结果展示 -->
|
|
30
|
-
<div v-if="selectedLocation" class="location-result">
|
|
31
|
-
<div class="label">
|
|
32
|
-
已选位置:
|
|
33
|
-
</div>
|
|
34
|
-
<div class="value">
|
|
35
|
-
{{ selectedLocation.address }}
|
|
36
|
-
</div>
|
|
37
|
-
<div class="coordinates">
|
|
38
|
-
经度: {{ selectedLocation.longitude.toFixed(6) }},
|
|
39
|
-
纬度: {{ selectedLocation.latitude.toFixed(6) }}
|
|
40
|
-
</div>
|
|
41
|
-
</div>
|
|
42
|
-
|
|
43
|
-
<!-- 地图组件 -->
|
|
44
|
-
<div class="map-container">
|
|
45
|
-
<LocationPicker
|
|
46
|
-
v-model="selectedLocation"
|
|
47
|
-
:default-center="[108.948024, 34.263161]"
|
|
48
|
-
:default-zoom="12"
|
|
49
|
-
@confirm="handleLocationConfirm"
|
|
50
|
-
/>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
</template>
|
|
54
|
-
</NormalDataLayout>
|
|
55
|
-
</template>
|
|
56
|
-
|
|
57
|
-
<style scoped lang="less">
|
|
58
|
-
.location-picker-demo {
|
|
59
|
-
width: 100%;
|
|
60
|
-
height: 100%;
|
|
61
|
-
position: relative;
|
|
62
|
-
display: flex;
|
|
63
|
-
flex-direction: column;
|
|
64
|
-
background-color: #f7f8fa;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.page-header {
|
|
68
|
-
height: 44px;
|
|
69
|
-
display: flex;
|
|
70
|
-
align-items: center;
|
|
71
|
-
justify-content: center;
|
|
72
|
-
background: white;
|
|
73
|
-
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
74
|
-
position: relative;
|
|
75
|
-
z-index: 1;
|
|
76
|
-
|
|
77
|
-
.title {
|
|
78
|
-
font-size: 16px;
|
|
79
|
-
color: #333;
|
|
80
|
-
font-weight: 500;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
.location-result {
|
|
85
|
-
background: white;
|
|
86
|
-
padding: 12px 16px;
|
|
87
|
-
margin: 10px;
|
|
88
|
-
border-radius: 8px;
|
|
89
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
90
|
-
|
|
91
|
-
.label {
|
|
92
|
-
font-size: 14px;
|
|
93
|
-
color: #666;
|
|
94
|
-
margin-bottom: 4px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
.value {
|
|
98
|
-
font-size: 16px;
|
|
99
|
-
color: #333;
|
|
100
|
-
margin-bottom: 8px;
|
|
101
|
-
word-break: break-all;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.coordinates {
|
|
105
|
-
font-size: 12px;
|
|
106
|
-
color: #999;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
.map-container {
|
|
111
|
-
flex: 1;
|
|
112
|
-
position: relative;
|
|
113
|
-
margin: 0 10px 10px 10px;
|
|
114
|
-
border-radius: 8px;
|
|
115
|
-
overflow: hidden;
|
|
116
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
117
|
-
}
|
|
118
|
-
</style>
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { LocationResult } from '@af-mobile-client-vue3/components/data/XOlMap/types'
|
|
3
|
+
import LocationPicker from '@af-mobile-client-vue3/components/data/XOlMap/XLocationPicker/index.vue'
|
|
4
|
+
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
5
|
+
import { showNotify } from 'vant'
|
|
6
|
+
import { ref } from 'vue'
|
|
7
|
+
|
|
8
|
+
const selectedLocation = ref<LocationResult>()
|
|
9
|
+
|
|
10
|
+
// 处理位置选择
|
|
11
|
+
function handleLocationConfirm(location: LocationResult) {
|
|
12
|
+
// console.log('选择的位置:', location)
|
|
13
|
+
// selectedLocation.value = location
|
|
14
|
+
showNotify({ type: 'success', message: '位置已选择' })
|
|
15
|
+
}
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<NormalDataLayout id="XLocationPicker" title="XOlMap地址选择器">
|
|
20
|
+
<template #layout_content>
|
|
21
|
+
<div class="location-picker-demo">
|
|
22
|
+
<!-- 页面标题 -->
|
|
23
|
+
<div class="page-header">
|
|
24
|
+
<div class="title">
|
|
25
|
+
位置选择
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
<!-- 选择结果展示 -->
|
|
30
|
+
<div v-if="selectedLocation" class="location-result">
|
|
31
|
+
<div class="label">
|
|
32
|
+
已选位置:
|
|
33
|
+
</div>
|
|
34
|
+
<div class="value">
|
|
35
|
+
{{ selectedLocation.address }}
|
|
36
|
+
</div>
|
|
37
|
+
<div class="coordinates">
|
|
38
|
+
经度: {{ selectedLocation.longitude.toFixed(6) }},
|
|
39
|
+
纬度: {{ selectedLocation.latitude.toFixed(6) }}
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
<!-- 地图组件 -->
|
|
44
|
+
<div class="map-container">
|
|
45
|
+
<LocationPicker
|
|
46
|
+
v-model="selectedLocation"
|
|
47
|
+
:default-center="[108.948024, 34.263161]"
|
|
48
|
+
:default-zoom="12"
|
|
49
|
+
@confirm="handleLocationConfirm"
|
|
50
|
+
/>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</template>
|
|
54
|
+
</NormalDataLayout>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<style scoped lang="less">
|
|
58
|
+
.location-picker-demo {
|
|
59
|
+
width: 100%;
|
|
60
|
+
height: 100%;
|
|
61
|
+
position: relative;
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
background-color: #f7f8fa;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.page-header {
|
|
68
|
+
height: 44px;
|
|
69
|
+
display: flex;
|
|
70
|
+
align-items: center;
|
|
71
|
+
justify-content: center;
|
|
72
|
+
background: white;
|
|
73
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
74
|
+
position: relative;
|
|
75
|
+
z-index: 1;
|
|
76
|
+
|
|
77
|
+
.title {
|
|
78
|
+
font-size: 16px;
|
|
79
|
+
color: #333;
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.location-result {
|
|
85
|
+
background: white;
|
|
86
|
+
padding: 12px 16px;
|
|
87
|
+
margin: 10px;
|
|
88
|
+
border-radius: 8px;
|
|
89
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
90
|
+
|
|
91
|
+
.label {
|
|
92
|
+
font-size: 14px;
|
|
93
|
+
color: #666;
|
|
94
|
+
margin-bottom: 4px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.value {
|
|
98
|
+
font-size: 16px;
|
|
99
|
+
color: #333;
|
|
100
|
+
margin-bottom: 8px;
|
|
101
|
+
word-break: break-all;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.coordinates {
|
|
105
|
+
font-size: 12px;
|
|
106
|
+
color: #999;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.map-container {
|
|
111
|
+
flex: 1;
|
|
112
|
+
position: relative;
|
|
113
|
+
margin: 0 10px 10px 10px;
|
|
114
|
+
border-radius: 8px;
|
|
115
|
+
overflow: hidden;
|
|
116
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
117
|
+
}
|
|
118
|
+
</style>
|