af-mobile-client-vue3 1.3.29 → 1.3.30
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 +4 -2
- package/src/components/data/XCellList/XCellList.md +132 -13
- package/src/components/data/XForm/index.vue +1 -1
- package/src/components/data/XOlMap/utils/wgs84ToGcj02.js +154 -154
- package/src/router/routes.ts +1 -1
- package/src/utils/queryFormDefaultRangePicker.ts +57 -57
- package/src/views/component/XCellListView/index.vue +27 -6
- package/src/views/component/XFormGroupView/index.vue +11 -7
- package/src/views/component/XFormView/index.vue +2 -2
- package/src/views/component/XOlMapView/XLocationPicker/index.vue +118 -118
package/package.json
CHANGED
|
@@ -210,13 +210,15 @@ function handleActionSelect(option: any) {
|
|
|
210
210
|
.uploader-container {
|
|
211
211
|
display: flex;
|
|
212
212
|
flex-direction: column;
|
|
213
|
-
|
|
213
|
+
// 该属性会影响表单布局
|
|
214
|
+
// gap: 16px;
|
|
214
215
|
}
|
|
215
216
|
.custom-upload-area {
|
|
216
217
|
width: 100%;
|
|
217
218
|
min-width: 220px;
|
|
218
219
|
min-height: 100px;
|
|
219
|
-
|
|
220
|
+
// 该属性会影响表单布局
|
|
221
|
+
// margin: 0 auto 12px auto;
|
|
220
222
|
box-sizing: border-box;
|
|
221
223
|
border: 1px dashed #d9d9d9;
|
|
222
224
|
border-radius: 10px;
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
- ✅ 卡片式布局
|
|
23
23
|
- ✅ 批量操作
|
|
24
24
|
- ✅ 自定义操作按钮
|
|
25
|
+
- ✅ **长按多选功能** ✨
|
|
25
26
|
|
|
26
27
|
### 表单功能
|
|
27
28
|
|
|
@@ -33,6 +34,97 @@
|
|
|
33
34
|
- ✅ 数据字典
|
|
34
35
|
- ✅ 自定义校验规则
|
|
35
36
|
|
|
37
|
+
## 多选功能 ✨
|
|
38
|
+
|
|
39
|
+
### 功能概述
|
|
40
|
+
|
|
41
|
+
XCellList 组件新增了强大的长按多选功能,支持以下特性:
|
|
42
|
+
|
|
43
|
+
- **长按触发**:长按卡片 500ms 进入多选模式
|
|
44
|
+
- **精确选择**:点击标题切换选中状态,点击卡片其他区域不触发选择
|
|
45
|
+
- **视觉反馈**:选中项目有高亮边框和背景色变化
|
|
46
|
+
- **操作面板**:底部 ActionSheet 显示自定义操作按钮
|
|
47
|
+
- **智能提示**:启用多选功能时显示操作提示
|
|
48
|
+
- **按钮禁用**:多选模式下自动禁用其他操作按钮
|
|
49
|
+
|
|
50
|
+
### 使用方法
|
|
51
|
+
|
|
52
|
+
#### 基础多选
|
|
53
|
+
|
|
54
|
+
```vue
|
|
55
|
+
<script setup lang="ts">
|
|
56
|
+
const multiSelectActions = ref([
|
|
57
|
+
{ name: '批量操作', key: 'batchOperation', color: '#000000', icon: 'records-o' }
|
|
58
|
+
])
|
|
59
|
+
|
|
60
|
+
function handleMultiSelectAction(action, selectedIds, selectedItems) {
|
|
61
|
+
console.log('多选操作:', action, selectedIds, selectedItems)
|
|
62
|
+
// 处理批量操作逻辑
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function handleSelectionChange(selectedItems) {
|
|
66
|
+
console.log('选择变化:', selectedItems)
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<XCellList
|
|
72
|
+
config-name="listConfig"
|
|
73
|
+
:service-name="serviceName"
|
|
74
|
+
:enable-multi-select="true"
|
|
75
|
+
id-key="rr_id"
|
|
76
|
+
:multi-select-actions="multiSelectActions"
|
|
77
|
+
@multi-select-action="handleMultiSelectAction"
|
|
78
|
+
@selection-change="handleSelectionChange"
|
|
79
|
+
/>
|
|
80
|
+
</template>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
#### 自定义多选操作
|
|
84
|
+
|
|
85
|
+
```vue
|
|
86
|
+
<script setup lang="ts">
|
|
87
|
+
const multiSelectActions = ref([
|
|
88
|
+
{ name: '标记已读', key: 'markRead', color: '#1989fa', icon: 'eye-o' },
|
|
89
|
+
{ name: '移动到文件夹', key: 'moveToFolder', color: '#07c160', icon: 'folder-o' },
|
|
90
|
+
{ name: '标记重要', key: 'markImportant', color: '#ff976a', icon: 'star-o' }
|
|
91
|
+
])
|
|
92
|
+
|
|
93
|
+
function handleMultiSelectAction(action, selectedIds, selectedItems) {
|
|
94
|
+
switch (action) {
|
|
95
|
+
case 'markRead':
|
|
96
|
+
// 标记已读逻辑
|
|
97
|
+
break
|
|
98
|
+
case 'moveToFolder':
|
|
99
|
+
// 移动到文件夹逻辑
|
|
100
|
+
break
|
|
101
|
+
case 'markImportant':
|
|
102
|
+
// 标记重要逻辑
|
|
103
|
+
break
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
</script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 多选功能提示
|
|
110
|
+
|
|
111
|
+
当启用多选功能(`enableMultiSelect: true`)但未进入多选模式时,会在筛选条件下方显示一个提示条:
|
|
112
|
+
|
|
113
|
+
- 提示内容:"长按卡片可进入多选模式"
|
|
114
|
+
- 样式:浅灰色背景,信息图标,友好的提示文字
|
|
115
|
+
- 进入多选模式后,此提示自动消失,显示多选模式提示条
|
|
116
|
+
|
|
117
|
+
### 多选模式下的按钮禁用
|
|
118
|
+
|
|
119
|
+
在多选模式下,以下按钮会被自动禁用:
|
|
120
|
+
|
|
121
|
+
- 新增按钮(add-action-btn)
|
|
122
|
+
- 卡片内的操作按钮(action-button)
|
|
123
|
+
- 卡片底部的操作按钮(action-btn)
|
|
124
|
+
- 更多按钮(⋯)
|
|
125
|
+
|
|
126
|
+
这样可以避免在多选过程中误触发其他操作。
|
|
127
|
+
|
|
36
128
|
## 使用示例
|
|
37
129
|
|
|
38
130
|
### 基础列表
|
|
@@ -110,22 +202,37 @@ function updateRow(item) {
|
|
|
110
202
|
|
|
111
203
|
### XCellList Props
|
|
112
204
|
|
|
113
|
-
| 参数
|
|
114
|
-
|
|
|
115
|
-
| configName
|
|
116
|
-
| serviceName
|
|
117
|
-
| fixQueryForm
|
|
118
|
-
| idKey
|
|
119
|
-
| customAdd
|
|
120
|
-
| customEdit
|
|
205
|
+
| 参数 | 说明 | 类型 | 默认值 |
|
|
206
|
+
| ---------------------- | ---------------------- | ----------- | --------- |
|
|
207
|
+
| configName | 配置名称 | string | - |
|
|
208
|
+
| serviceName | 服务名称 | string | - |
|
|
209
|
+
| fixQueryForm | 固定查询参数 | object | null |
|
|
210
|
+
| idKey | 主键字段 | string | 'o_id' |
|
|
211
|
+
| customAdd | 是否采用自定义新增按钮 | boolean | false |
|
|
212
|
+
| customEdit | 是否采用自定义修改按钮 | boolean | false |
|
|
213
|
+
| **enableMultiSelect** | **是否启用多选功能** | **boolean** | **false** |
|
|
214
|
+
| **multiSelectActions** | **多选操作按钮配置** | **Array** | **[]** |
|
|
121
215
|
|
|
122
216
|
### XCellList Events
|
|
123
217
|
|
|
124
|
-
| 事件名
|
|
125
|
-
|
|
|
126
|
-
| toDetail
|
|
127
|
-
| add
|
|
128
|
-
| update
|
|
218
|
+
| 事件名 | 说明 | 回调参数 |
|
|
219
|
+
| --------------------- | ---------------------------------------------- | ------------------------------------------------------------------------- |
|
|
220
|
+
| toDetail | 点击详情时触发 | item: 当前项数据 |
|
|
221
|
+
| add | 点击新增按钮时触发(customAdd为true才会触发) | - |
|
|
222
|
+
| update | 点击修改按钮时触发(customEdit为true才会触发) | item: 当前项数据 |
|
|
223
|
+
| **multiSelectAction** | **多选操作时触发** | **action: 操作key, selectedIds: 选中ID数组, selectedItems: 选中项目数组** |
|
|
224
|
+
| **selectionChange** | **选择状态变化时触发** | **selectedItems: 选中项目数组** |
|
|
225
|
+
|
|
226
|
+
### 多选操作按钮配置
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
interface MultiSelectAction {
|
|
230
|
+
name: string // 按钮显示名称
|
|
231
|
+
key?: string // 操作标识(可选,默认使用name)
|
|
232
|
+
color?: string // 按钮颜色(可选,默认黑色)
|
|
233
|
+
icon?: string // 按钮图标(可选,默认records-o)
|
|
234
|
+
}
|
|
235
|
+
```
|
|
129
236
|
|
|
130
237
|
### XFormGroup Props
|
|
131
238
|
|
|
@@ -278,6 +385,18 @@ const styleFunctionForValue = `function(value) {
|
|
|
278
385
|
3. Q: 如何自定义列表样式?
|
|
279
386
|
A: 使用 styleFunctionForValue 配置样式函数
|
|
280
387
|
|
|
388
|
+
4. **Q: 多选功能如何触发?**
|
|
389
|
+
**A: 长按卡片 500ms 即可进入多选模式**
|
|
390
|
+
|
|
391
|
+
5. **Q: 如何自定义多选操作按钮?**
|
|
392
|
+
**A: 通过 `multiSelectActions` 属性配置,支持自定义名称、颜色和图标**
|
|
393
|
+
|
|
394
|
+
6. **Q: 多选模式下如何选择项目?**
|
|
395
|
+
**A: 点击项目标题可以切换选中状态,点击卡片其他区域不会触发选择**
|
|
396
|
+
|
|
397
|
+
7. **Q: 如何获取选中的项目数据?**
|
|
398
|
+
**A: 监听 `selectionChange` 事件,或通过 `multiSelectAction` 事件获取**
|
|
399
|
+
|
|
281
400
|
## 更新日志
|
|
282
401
|
|
|
283
402
|
### v1.0.0
|
|
@@ -208,7 +208,7 @@ async function initWithGroupFormItems() {
|
|
|
208
208
|
function setupFormConfig(config: GroupFormItems) {
|
|
209
209
|
loadParamLogicNameData(config.paramLogicName)
|
|
210
210
|
formConfig.value = config
|
|
211
|
-
myServiceName.value = props.serviceName ||
|
|
211
|
+
myServiceName.value = props.serviceName || undefined
|
|
212
212
|
formGroupName.value = config.groupName || 'default'
|
|
213
213
|
form.value = props.formData || {}
|
|
214
214
|
// 清理并重新设置验证规则
|
|
@@ -1,154 +1,154 @@
|
|
|
1
|
-
// 导入proj控件
|
|
2
|
-
import * as proj from 'ol/proj'
|
|
3
|
-
|
|
4
|
-
function forEachPoint(func) {
|
|
5
|
-
return function (input, opt_output, opt_dimension) {
|
|
6
|
-
const len = input.length
|
|
7
|
-
|
|
8
|
-
const dimension = opt_dimension || 2
|
|
9
|
-
let output
|
|
10
|
-
|
|
11
|
-
if (opt_output) {
|
|
12
|
-
output = opt_output
|
|
13
|
-
}
|
|
14
|
-
else {
|
|
15
|
-
if (dimension !== 2) {
|
|
16
|
-
output = input.slice()
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
output = [len]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
for (let offset = 0; offset < len; offset += dimension) {
|
|
23
|
-
func(input, output, offset)
|
|
24
|
-
}
|
|
25
|
-
return output
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const gcj02 = {}
|
|
30
|
-
const PI = Math.PI
|
|
31
|
-
const AXIS = 6378245.0
|
|
32
|
-
// eslint-disable-next-line no-loss-of-precision
|
|
33
|
-
const OFFSET = 0.00669342162296594323 // (a^2 - b^2) / a^2
|
|
34
|
-
|
|
35
|
-
function delta(wgLon, wgLat) {
|
|
36
|
-
let dLat = transformLat(wgLon - 105.0, wgLat - 35.0)
|
|
37
|
-
let dLon = transformLon(wgLon - 105.0, wgLat - 35.0)
|
|
38
|
-
const radLat = (wgLat / 180.0) * PI
|
|
39
|
-
let magic = Math.sin(radLat)
|
|
40
|
-
magic = 1 - OFFSET * magic * magic
|
|
41
|
-
const sqrtMagic = Math.sqrt(magic)
|
|
42
|
-
dLat = (dLat * 180.0) / (((AXIS * (1 - OFFSET)) / (magic * sqrtMagic)) * PI)
|
|
43
|
-
dLon = (dLon * 180.0) / ((AXIS / sqrtMagic) * Math.cos(radLat) * PI)
|
|
44
|
-
return [dLon, dLat]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function outOfChina(lon, lat) {
|
|
48
|
-
if (lon < 72.004 || lon > 137.8347) {
|
|
49
|
-
return true
|
|
50
|
-
}
|
|
51
|
-
return lat < 0.8293 || lat > 55.8271
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function transformLat(x, y) {
|
|
55
|
-
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x))
|
|
56
|
-
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0
|
|
57
|
-
ret += ((20.0 * Math.sin(y * PI) + 40.0 * Math.sin((y / 3.0) * PI)) * 2.0) / 3.0
|
|
58
|
-
ret += ((160.0 * Math.sin((y / 12.0) * PI) + 320 * Math.sin((y * PI) / 30.0)) * 2.0) / 3.0
|
|
59
|
-
return ret
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function transformLon(x, y) {
|
|
63
|
-
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x))
|
|
64
|
-
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0
|
|
65
|
-
ret += ((20.0 * Math.sin(x * PI) + 40.0 * Math.sin((x / 3.0) * PI)) * 2.0) / 3.0
|
|
66
|
-
ret += ((150.0 * Math.sin((x / 12.0) * PI) + 300.0 * Math.sin((x / 30.0) * PI)) * 2.0) / 3.0
|
|
67
|
-
return ret
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
gcj02.toWGS84 = forEachPoint((input, output, offset) => {
|
|
71
|
-
let lng = input[offset]
|
|
72
|
-
let lat = input[offset + 1]
|
|
73
|
-
if (!outOfChina(lng, lat)) {
|
|
74
|
-
const deltaD = delta(lng, lat)
|
|
75
|
-
lng = lng - deltaD[0] // 改回减法
|
|
76
|
-
lat = lat - deltaD[1] // 改回减法
|
|
77
|
-
}
|
|
78
|
-
output[offset] = lng
|
|
79
|
-
output[offset + 1] = lat
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
gcj02.fromWGS84 = forEachPoint((input, output, offset) => {
|
|
83
|
-
let lng = input[offset]
|
|
84
|
-
let lat = input[offset + 1]
|
|
85
|
-
if (!outOfChina(lng, lat)) {
|
|
86
|
-
const deltaD = delta(lng, lat)
|
|
87
|
-
lng = lng + deltaD[0] // 改回加法
|
|
88
|
-
lat = lat + deltaD[1] // 改回加法
|
|
89
|
-
}
|
|
90
|
-
output[offset] = lng
|
|
91
|
-
output[offset + 1] = lat
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
const sphericalMercator = {}
|
|
95
|
-
const RADIUS = 6378137
|
|
96
|
-
const MAX_LATITUDE = 85.0511287798
|
|
97
|
-
const RAD_PER_DEG = Math.PI / 180
|
|
98
|
-
|
|
99
|
-
sphericalMercator.forward = forEachPoint((input, output, offset) => {
|
|
100
|
-
const lat = Math.max(Math.min(MAX_LATITUDE, input[offset + 1]), -MAX_LATITUDE)
|
|
101
|
-
const sin = Math.sin(lat * RAD_PER_DEG)
|
|
102
|
-
output[offset] = RADIUS * input[offset] * RAD_PER_DEG
|
|
103
|
-
output[offset + 1] = (RADIUS * Math.log((1 + sin) / (1 - sin))) / 2
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
sphericalMercator.inverse = forEachPoint((input, output, offset) => {
|
|
107
|
-
output[offset] = input[offset] / RADIUS / RAD_PER_DEG
|
|
108
|
-
output[offset + 1] = (2 * Math.atan(Math.exp(input[offset + 1] / RADIUS)) - Math.PI / 2) / RAD_PER_DEG
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
const projzh = {}
|
|
112
|
-
|
|
113
|
-
projzh.ll2gmerc = function (input, opt_output, opt_dimension) {
|
|
114
|
-
const output = gcj02.toWGS84(input, opt_output, opt_dimension) // 改用 toWGS84
|
|
115
|
-
return projzh.ll2smerc(output, output, opt_dimension)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
projzh.gmerc2ll = function (input, opt_output, opt_dimension) {
|
|
119
|
-
const output = projzh.smerc2ll(input, input, opt_dimension)
|
|
120
|
-
return gcj02.fromWGS84(output, opt_output, opt_dimension) // 改用 fromWGS84
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// smerc2gmerc 需要修改
|
|
124
|
-
|
|
125
|
-
projzh.smerc2gmerc = function (input, opt_output, opt_dimension) {
|
|
126
|
-
let output = projzh.smerc2ll(input, input, opt_dimension)
|
|
127
|
-
output = gcj02.toWGS84(output, output, opt_dimension) // 这里应该用 toWGS84
|
|
128
|
-
return projzh.ll2smerc(output, output, opt_dimension)
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// gmerc2smerc 需要修改
|
|
132
|
-
|
|
133
|
-
projzh.gmerc2smerc = function (input, opt_output, opt_dimension) {
|
|
134
|
-
let output = projzh.smerc2ll(input, input, opt_dimension)
|
|
135
|
-
output = gcj02.fromWGS84(output, output, opt_dimension) // 这里应该用 fromWGS84
|
|
136
|
-
return projzh.ll2smerc(output, output, opt_dimension)
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
projzh.ll2smerc = sphericalMercator.forward
|
|
140
|
-
projzh.smerc2ll = sphericalMercator.inverse
|
|
141
|
-
|
|
142
|
-
// 定义WGS84转GCJ02的投影
|
|
143
|
-
const extent = [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]
|
|
144
|
-
export const wgs84ToGcj02Projection = new proj.Projection({
|
|
145
|
-
code: 'WGS84-TO-GCJ02',
|
|
146
|
-
extent,
|
|
147
|
-
units: 'm',
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
// 添加投影和转换方法
|
|
151
|
-
proj.addProjection(wgs84ToGcj02Projection)
|
|
152
|
-
// 注意这里转换方法的顺序与原来相反
|
|
153
|
-
proj.addCoordinateTransforms('EPSG:4326', wgs84ToGcj02Projection, projzh.ll2gmerc, projzh.gmerc2ll)
|
|
154
|
-
proj.addCoordinateTransforms('EPSG:3857', wgs84ToGcj02Projection, projzh.smerc2gmerc, projzh.gmerc2smerc)
|
|
1
|
+
// 导入proj控件
|
|
2
|
+
import * as proj from 'ol/proj'
|
|
3
|
+
|
|
4
|
+
function forEachPoint(func) {
|
|
5
|
+
return function (input, opt_output, opt_dimension) {
|
|
6
|
+
const len = input.length
|
|
7
|
+
|
|
8
|
+
const dimension = opt_dimension || 2
|
|
9
|
+
let output
|
|
10
|
+
|
|
11
|
+
if (opt_output) {
|
|
12
|
+
output = opt_output
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
if (dimension !== 2) {
|
|
16
|
+
output = input.slice()
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
output = [len]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (let offset = 0; offset < len; offset += dimension) {
|
|
23
|
+
func(input, output, offset)
|
|
24
|
+
}
|
|
25
|
+
return output
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const gcj02 = {}
|
|
30
|
+
const PI = Math.PI
|
|
31
|
+
const AXIS = 6378245.0
|
|
32
|
+
// eslint-disable-next-line no-loss-of-precision
|
|
33
|
+
const OFFSET = 0.00669342162296594323 // (a^2 - b^2) / a^2
|
|
34
|
+
|
|
35
|
+
function delta(wgLon, wgLat) {
|
|
36
|
+
let dLat = transformLat(wgLon - 105.0, wgLat - 35.0)
|
|
37
|
+
let dLon = transformLon(wgLon - 105.0, wgLat - 35.0)
|
|
38
|
+
const radLat = (wgLat / 180.0) * PI
|
|
39
|
+
let magic = Math.sin(radLat)
|
|
40
|
+
magic = 1 - OFFSET * magic * magic
|
|
41
|
+
const sqrtMagic = Math.sqrt(magic)
|
|
42
|
+
dLat = (dLat * 180.0) / (((AXIS * (1 - OFFSET)) / (magic * sqrtMagic)) * PI)
|
|
43
|
+
dLon = (dLon * 180.0) / ((AXIS / sqrtMagic) * Math.cos(radLat) * PI)
|
|
44
|
+
return [dLon, dLat]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function outOfChina(lon, lat) {
|
|
48
|
+
if (lon < 72.004 || lon > 137.8347) {
|
|
49
|
+
return true
|
|
50
|
+
}
|
|
51
|
+
return lat < 0.8293 || lat > 55.8271
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function transformLat(x, y) {
|
|
55
|
+
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x))
|
|
56
|
+
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0
|
|
57
|
+
ret += ((20.0 * Math.sin(y * PI) + 40.0 * Math.sin((y / 3.0) * PI)) * 2.0) / 3.0
|
|
58
|
+
ret += ((160.0 * Math.sin((y / 12.0) * PI) + 320 * Math.sin((y * PI) / 30.0)) * 2.0) / 3.0
|
|
59
|
+
return ret
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function transformLon(x, y) {
|
|
63
|
+
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x))
|
|
64
|
+
ret += ((20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0) / 3.0
|
|
65
|
+
ret += ((20.0 * Math.sin(x * PI) + 40.0 * Math.sin((x / 3.0) * PI)) * 2.0) / 3.0
|
|
66
|
+
ret += ((150.0 * Math.sin((x / 12.0) * PI) + 300.0 * Math.sin((x / 30.0) * PI)) * 2.0) / 3.0
|
|
67
|
+
return ret
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
gcj02.toWGS84 = forEachPoint((input, output, offset) => {
|
|
71
|
+
let lng = input[offset]
|
|
72
|
+
let lat = input[offset + 1]
|
|
73
|
+
if (!outOfChina(lng, lat)) {
|
|
74
|
+
const deltaD = delta(lng, lat)
|
|
75
|
+
lng = lng - deltaD[0] // 改回减法
|
|
76
|
+
lat = lat - deltaD[1] // 改回减法
|
|
77
|
+
}
|
|
78
|
+
output[offset] = lng
|
|
79
|
+
output[offset + 1] = lat
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
gcj02.fromWGS84 = forEachPoint((input, output, offset) => {
|
|
83
|
+
let lng = input[offset]
|
|
84
|
+
let lat = input[offset + 1]
|
|
85
|
+
if (!outOfChina(lng, lat)) {
|
|
86
|
+
const deltaD = delta(lng, lat)
|
|
87
|
+
lng = lng + deltaD[0] // 改回加法
|
|
88
|
+
lat = lat + deltaD[1] // 改回加法
|
|
89
|
+
}
|
|
90
|
+
output[offset] = lng
|
|
91
|
+
output[offset + 1] = lat
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const sphericalMercator = {}
|
|
95
|
+
const RADIUS = 6378137
|
|
96
|
+
const MAX_LATITUDE = 85.0511287798
|
|
97
|
+
const RAD_PER_DEG = Math.PI / 180
|
|
98
|
+
|
|
99
|
+
sphericalMercator.forward = forEachPoint((input, output, offset) => {
|
|
100
|
+
const lat = Math.max(Math.min(MAX_LATITUDE, input[offset + 1]), -MAX_LATITUDE)
|
|
101
|
+
const sin = Math.sin(lat * RAD_PER_DEG)
|
|
102
|
+
output[offset] = RADIUS * input[offset] * RAD_PER_DEG
|
|
103
|
+
output[offset + 1] = (RADIUS * Math.log((1 + sin) / (1 - sin))) / 2
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
sphericalMercator.inverse = forEachPoint((input, output, offset) => {
|
|
107
|
+
output[offset] = input[offset] / RADIUS / RAD_PER_DEG
|
|
108
|
+
output[offset + 1] = (2 * Math.atan(Math.exp(input[offset + 1] / RADIUS)) - Math.PI / 2) / RAD_PER_DEG
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const projzh = {}
|
|
112
|
+
|
|
113
|
+
projzh.ll2gmerc = function (input, opt_output, opt_dimension) {
|
|
114
|
+
const output = gcj02.toWGS84(input, opt_output, opt_dimension) // 改用 toWGS84
|
|
115
|
+
return projzh.ll2smerc(output, output, opt_dimension)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
projzh.gmerc2ll = function (input, opt_output, opt_dimension) {
|
|
119
|
+
const output = projzh.smerc2ll(input, input, opt_dimension)
|
|
120
|
+
return gcj02.fromWGS84(output, opt_output, opt_dimension) // 改用 fromWGS84
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// smerc2gmerc 需要修改
|
|
124
|
+
|
|
125
|
+
projzh.smerc2gmerc = function (input, opt_output, opt_dimension) {
|
|
126
|
+
let output = projzh.smerc2ll(input, input, opt_dimension)
|
|
127
|
+
output = gcj02.toWGS84(output, output, opt_dimension) // 这里应该用 toWGS84
|
|
128
|
+
return projzh.ll2smerc(output, output, opt_dimension)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// gmerc2smerc 需要修改
|
|
132
|
+
|
|
133
|
+
projzh.gmerc2smerc = function (input, opt_output, opt_dimension) {
|
|
134
|
+
let output = projzh.smerc2ll(input, input, opt_dimension)
|
|
135
|
+
output = gcj02.fromWGS84(output, output, opt_dimension) // 这里应该用 fromWGS84
|
|
136
|
+
return projzh.ll2smerc(output, output, opt_dimension)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
projzh.ll2smerc = sphericalMercator.forward
|
|
140
|
+
projzh.smerc2ll = sphericalMercator.inverse
|
|
141
|
+
|
|
142
|
+
// 定义WGS84转GCJ02的投影
|
|
143
|
+
const extent = [-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244]
|
|
144
|
+
export const wgs84ToGcj02Projection = new proj.Projection({
|
|
145
|
+
code: 'WGS84-TO-GCJ02',
|
|
146
|
+
extent,
|
|
147
|
+
units: 'm',
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
// 添加投影和转换方法
|
|
151
|
+
proj.addProjection(wgs84ToGcj02Projection)
|
|
152
|
+
// 注意这里转换方法的顺序与原来相反
|
|
153
|
+
proj.addCoordinateTransforms('EPSG:4326', wgs84ToGcj02Projection, projzh.ll2gmerc, projzh.gmerc2ll)
|
|
154
|
+
proj.addCoordinateTransforms('EPSG:3857', wgs84ToGcj02Projection, projzh.smerc2gmerc, projzh.gmerc2smerc)
|
package/src/router/routes.ts
CHANGED
|
@@ -1,57 +1,57 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 根据类型获取日期区间字符串
|
|
3
|
-
* @param type '当年' | 'curMonth' | '当日'
|
|
4
|
-
* @param show 区分实际值还是显示值, true为实际值, false为显示值
|
|
5
|
-
* @returns [start, end] 例:['2024-01-01 00:00:00', '2024-12-31 23:59:59']
|
|
6
|
-
*/
|
|
7
|
-
export function getRangeByType(type: string, show: boolean): [string, string] {
|
|
8
|
-
const now = new Date()
|
|
9
|
-
const year = now.getFullYear()
|
|
10
|
-
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
|
11
|
-
const day = now.getDate().toString().padStart(2, '0')
|
|
12
|
-
|
|
13
|
-
if (!show) {
|
|
14
|
-
if (type === 'curYear') {
|
|
15
|
-
return [
|
|
16
|
-
`${year}-01-01 00:00:00`,
|
|
17
|
-
`${year}-12-31 23:59:59`,
|
|
18
|
-
]
|
|
19
|
-
}
|
|
20
|
-
if (type === 'curMonth') {
|
|
21
|
-
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
22
|
-
return [
|
|
23
|
-
`${year}-${month}-01 00:00:00`,
|
|
24
|
-
`${year}-${month}-${lastDay.toString().padStart(2, '0')} 23:59:59`,
|
|
25
|
-
]
|
|
26
|
-
}
|
|
27
|
-
if (type === 'curDay') {
|
|
28
|
-
return [
|
|
29
|
-
`${year}-${month}-${day} 00:00:00`,
|
|
30
|
-
`${year}-${month}-${day} 23:59:59`,
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
if (show) {
|
|
35
|
-
if (type === 'curYear') {
|
|
36
|
-
return [
|
|
37
|
-
`${year}-01-01`,
|
|
38
|
-
`${year}-12-31`,
|
|
39
|
-
]
|
|
40
|
-
}
|
|
41
|
-
if (type === 'curMonth') {
|
|
42
|
-
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
43
|
-
return [
|
|
44
|
-
`${year}-${month}-01`,
|
|
45
|
-
`${year}-${month}-${lastDay.toString().padStart(2, '0')}`,
|
|
46
|
-
]
|
|
47
|
-
}
|
|
48
|
-
if (type === 'curDay') {
|
|
49
|
-
return [
|
|
50
|
-
`${year}-${month}-${day}`,
|
|
51
|
-
`${year}-${month}-${day}`,
|
|
52
|
-
]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
// 兜底返回空字符串数组
|
|
56
|
-
return ['', '']
|
|
57
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* 根据类型获取日期区间字符串
|
|
3
|
+
* @param type '当年' | 'curMonth' | '当日'
|
|
4
|
+
* @param show 区分实际值还是显示值, true为实际值, false为显示值
|
|
5
|
+
* @returns [start, end] 例:['2024-01-01 00:00:00', '2024-12-31 23:59:59']
|
|
6
|
+
*/
|
|
7
|
+
export function getRangeByType(type: string, show: boolean): [string, string] {
|
|
8
|
+
const now = new Date()
|
|
9
|
+
const year = now.getFullYear()
|
|
10
|
+
const month = (now.getMonth() + 1).toString().padStart(2, '0')
|
|
11
|
+
const day = now.getDate().toString().padStart(2, '0')
|
|
12
|
+
|
|
13
|
+
if (!show) {
|
|
14
|
+
if (type === 'curYear') {
|
|
15
|
+
return [
|
|
16
|
+
`${year}-01-01 00:00:00`,
|
|
17
|
+
`${year}-12-31 23:59:59`,
|
|
18
|
+
]
|
|
19
|
+
}
|
|
20
|
+
if (type === 'curMonth') {
|
|
21
|
+
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
22
|
+
return [
|
|
23
|
+
`${year}-${month}-01 00:00:00`,
|
|
24
|
+
`${year}-${month}-${lastDay.toString().padStart(2, '0')} 23:59:59`,
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
if (type === 'curDay') {
|
|
28
|
+
return [
|
|
29
|
+
`${year}-${month}-${day} 00:00:00`,
|
|
30
|
+
`${year}-${month}-${day} 23:59:59`,
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (show) {
|
|
35
|
+
if (type === 'curYear') {
|
|
36
|
+
return [
|
|
37
|
+
`${year}-01-01`,
|
|
38
|
+
`${year}-12-31`,
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
if (type === 'curMonth') {
|
|
42
|
+
const lastDay = new Date(year, now.getMonth() + 1, 0).getDate()
|
|
43
|
+
return [
|
|
44
|
+
`${year}-${month}-01`,
|
|
45
|
+
`${year}-${month}-${lastDay.toString().padStart(2, '0')}`,
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
if (type === 'curDay') {
|
|
49
|
+
return [
|
|
50
|
+
`${year}-${month}-${day}`,
|
|
51
|
+
`${year}-${month}-${day}`,
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// 兜底返回空字符串数组
|
|
56
|
+
return ['', '']
|
|
57
|
+
}
|
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import XCellList from '@af-mobile-client-vue3/components/data/XCellList/index.vue'
|
|
3
3
|
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
4
|
+
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
|
|
4
5
|
import { defineEmits, ref } from 'vue'
|
|
5
6
|
import { useRouter } from 'vue-router'
|
|
6
7
|
|
|
7
8
|
// 定义事件
|
|
8
9
|
const emit = defineEmits(['deleteRow'])
|
|
10
|
+
|
|
11
|
+
// 多选操作配置
|
|
12
|
+
const multiSelectActions = ref([
|
|
13
|
+
{ name: '批量审核', key: 'batchAudit', color: '#000000', icon: 'passed' },
|
|
14
|
+
])
|
|
15
|
+
|
|
16
|
+
const userInfo = useUserStore().getUserInfo()
|
|
9
17
|
// 访问路由
|
|
10
18
|
const router = useRouter()
|
|
11
19
|
// 获取默认值
|
|
@@ -48,7 +56,7 @@ const serviceName = ref('af-gaslink')
|
|
|
48
56
|
// 跳转到表单——以表单组来渲染纯表单
|
|
49
57
|
function toDetail(item) {
|
|
50
58
|
router.push({
|
|
51
|
-
name: '
|
|
59
|
+
name: 'XFormView',
|
|
52
60
|
query: {
|
|
53
61
|
id: item[idKey.value],
|
|
54
62
|
// id: item.rr_id,
|
|
@@ -87,18 +95,31 @@ function toDetail(item) {
|
|
|
87
95
|
function deleteRow(result) {
|
|
88
96
|
emit('deleteRow', result.o_id)
|
|
89
97
|
}
|
|
98
|
+
|
|
99
|
+
// 多选操作处理
|
|
100
|
+
function handleMultiSelectAction(action: string, selectedItems: any[], selectedItemsArray: any[]) {
|
|
101
|
+
console.log('多选操作:', action, selectedItems, selectedItemsArray)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// 选择变化处理
|
|
105
|
+
function handleSelectionChange(selectedItems: any[]) {
|
|
106
|
+
console.log('选择变化,当前选中:', selectedItems.length, '个项目')
|
|
107
|
+
// 可以在这里更新UI状态,比如显示选中数量等
|
|
108
|
+
}
|
|
90
109
|
</script>
|
|
91
110
|
|
|
92
111
|
<template>
|
|
93
112
|
<NormalDataLayout id="XCellListView" title="工作计划">
|
|
94
113
|
<template #layout_content>
|
|
95
114
|
<XCellList
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
:
|
|
99
|
-
|
|
115
|
+
config-name="lngChargeAuditMobileCRUD"
|
|
116
|
+
service-name="af-gaslink"
|
|
117
|
+
:enable-multi-select="true"
|
|
118
|
+
id-key="rr_id"
|
|
119
|
+
:multi-select-actions="multiSelectActions"
|
|
100
120
|
@to-detail="toDetail"
|
|
101
|
-
@
|
|
121
|
+
@multi-select-action="handleMultiSelectAction"
|
|
122
|
+
@selection-change="handleSelectionChange"
|
|
102
123
|
/>
|
|
103
124
|
</template>
|
|
104
125
|
</NormalDataLayout>
|
|
@@ -5,16 +5,19 @@ import { showDialog } from 'vant'
|
|
|
5
5
|
import { ref } from 'vue'
|
|
6
6
|
import { useRoute } from 'vue-router'
|
|
7
7
|
|
|
8
|
+
// const configName = ref('reviewFormGroup')
|
|
9
|
+
// const serviceName = ref('af-revenue')
|
|
10
|
+
|
|
8
11
|
// 纯表单
|
|
9
|
-
const configName = ref('form_check_test')
|
|
10
|
-
const serviceName = ref('af-system')
|
|
12
|
+
// const configName = ref('form_check_test')
|
|
13
|
+
// const serviceName = ref('af-system')
|
|
11
14
|
|
|
12
15
|
// const configName = ref("计划下发Form")
|
|
13
16
|
// const serviceName = ref("af-linepatrol")
|
|
14
17
|
|
|
15
18
|
// 表单组
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
const configName = ref('lngChargeAuditMobileFormGroup')
|
|
20
|
+
const serviceName = ref('af-gaslink')
|
|
18
21
|
|
|
19
22
|
const formData = ref({})
|
|
20
23
|
const formGroup = ref(null)
|
|
@@ -22,7 +25,8 @@ const route = useRoute()
|
|
|
22
25
|
const isInit = ref(false)
|
|
23
26
|
function submit(_result) {
|
|
24
27
|
showDialog({ message: '提交成功' }).then(() => {
|
|
25
|
-
|
|
28
|
+
console.log('12121')
|
|
29
|
+
// history.back()
|
|
26
30
|
})
|
|
27
31
|
}
|
|
28
32
|
|
|
@@ -63,8 +67,8 @@ function submit(_result) {
|
|
|
63
67
|
<!-- v-if="isInit" -->
|
|
64
68
|
<XFormGroup
|
|
65
69
|
ref="formGroup"
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
config-name="ApplyAddContractFormGroup"
|
|
71
|
+
service-name="af-apply"
|
|
68
72
|
:group-form-data="formData"
|
|
69
73
|
mode="新增"
|
|
70
74
|
@submit="submit"
|
|
@@ -3,8 +3,8 @@ import XForm from '@af-mobile-client-vue3/components/data/XForm/index.vue'
|
|
|
3
3
|
import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
|
|
4
4
|
import { ref } from 'vue'
|
|
5
5
|
|
|
6
|
-
const configName = ref('
|
|
7
|
-
const serviceName = ref('af-
|
|
6
|
+
const configName = ref('lngSecurityChecktestForm')
|
|
7
|
+
const serviceName = ref('af-safecheck')
|
|
8
8
|
|
|
9
9
|
const formGroupAddConstruction = ref(null)
|
|
10
10
|
</script>
|
|
@@ -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>
|