af-mobile-client-vue3 1.1.42 → 1.1.44

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.1.42",
4
+ "version": "1.1.44",
5
5
  "description": "Vue + Vite component lib",
6
6
  "license": "MIT",
7
7
  "engines": {
@@ -734,7 +734,7 @@ defineExpose({
734
734
 
735
735
  <style scoped lang="less">
736
736
  #XCellList {
737
- height: calc(100vh - var(--van-nav-bar-height) - 5px);
737
+ height: calc(100vh - var(--van-nav-bar-height) - 20px);
738
738
  display: flex;
739
739
  flex-direction: column;
740
740
  --van-search-padding: 3px;
@@ -953,6 +953,7 @@ defineExpose({
953
953
 
954
954
  .action-btn {
955
955
  min-width: 76px;
956
+ height: 40px;
956
957
  border-radius: 10px;
957
958
  font-size: 1rem;
958
959
  transition: all 0.2s ease;
@@ -218,7 +218,7 @@ defineExpose({ init, form, formGroupName, validate })
218
218
  </VanCellGroup>
219
219
  </div>
220
220
  <div v-if="resolvedSubmitButton && props.mode !== '预览'" class="form-footer-fixed">
221
- <VanButton round block type="primary" native-type="submit">
221
+ <VanButton class="action-btn" round block type="primary" native-type="submit">
222
222
  {{ props.groupFormItems?.btnName ? props.groupFormItems.btnName : '提交' }}
223
223
  </VanButton>
224
224
  <slot />
@@ -228,7 +228,7 @@ defineExpose({ init, form, formGroupName, validate })
228
228
 
229
229
  <style scoped>
230
230
  .x-form-container {
231
- height: calc(100vh - var(--van-nav-bar-height) - 5px);
231
+ height: calc(100vh - var(--van-nav-bar-height) - 20px);
232
232
  display: flex;
233
233
  flex-direction: column;
234
234
  max-height: 100vh;
@@ -239,11 +239,13 @@ defineExpose({ init, form, formGroupName, validate })
239
239
  flex: 1;
240
240
  overflow-y: auto;
241
241
  min-height: 0;
242
- padding: 0 16px;
243
242
  }
244
243
 
245
244
  .form-footer-fixed {
246
245
  margin: 16px;
247
246
  flex-shrink: 0;
247
+ .action-btn {
248
+ border-radius: 10px;
249
+ }
248
250
  }
249
251
  </style>
@@ -837,7 +837,7 @@ function handleAddressConfirm(location) {
837
837
  :rules="[{ required: attr.rule.required === 'true', message: '请选择' }]"
838
838
  @click="readonly ? null : showPicker = true"
839
839
  />
840
- <VanPopup v-model:show="showPicker" round position="bottom" teleport="body">
840
+ <VanPopup v-model:show="showPicker" round position="bottom" teleport="body" overlay-class="date-picker-overlay">
841
841
  <VanPicker
842
842
  v-model="(localValue as Numeric[])"
843
843
  :title="attr.name"
@@ -870,6 +870,7 @@ function handleAddressConfirm(location) {
870
870
  switch-mode="year-month"
871
871
  type="range"
872
872
  teleport="body"
873
+ overlay-class="date-picker-overlay"
873
874
  :show-confirm="attr.showConfirm"
874
875
  @confirm="onCalendarConfirm"
875
876
  />
@@ -888,7 +889,7 @@ function handleAddressConfirm(location) {
888
889
  :rules="[{ required: attr.rule.required === 'true', message: '请选择' }]"
889
890
  @click="readonly ? null : showDataTimePicker()"
890
891
  />
891
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
892
+ <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body" overlay-class="date-picker-overlay">
892
893
  <VanPickerGroup
893
894
  :title="attr.name"
894
895
  :tabs="['选择日期', '选择时间']"
@@ -925,7 +926,7 @@ function handleAddressConfirm(location) {
925
926
  :rules="[{ required: attr.rule.required === 'true', message: '请选择' }]"
926
927
  @click="showDatePicker = true"
927
928
  />
928
- <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body">
929
+ <VanPopup v-model:show="showDatePicker" position="bottom" teleport="body" overlay-class="date-picker-overlay">
929
930
  <VanPickerGroup
930
931
  :title="attr.name"
931
932
  :tabs="['选择日期', '选择时间']"
@@ -962,7 +963,7 @@ function handleAddressConfirm(location) {
962
963
  :rules="[{ required: attr.rule.required === 'true', message: '请选择' }]"
963
964
  @click="showTimePicker = true"
964
965
  />
965
- <VanPopup v-model:show="showTimePicker" position="bottom" teleport="body">
966
+ <VanPopup v-model:show="showTimePicker" position="bottom" teleport="body" overlay-class="date-picker-overlay">
966
967
  <VanTimePicker
967
968
  v-model="localValue as string[]"
968
969
  :title="attr.name"
@@ -989,7 +990,7 @@ function handleAddressConfirm(location) {
989
990
  :rules="[{ required: attr.rule.required === 'true', message: '请选择' }]"
990
991
  @click="readonly ? null : showArea = true"
991
992
  />
992
- <VanPopup v-model:show="showArea" position="bottom" teleport="body">
993
+ <VanPopup v-model:show="showArea" position="bottom" teleport="body" overlay-class="date-picker-overlay">
993
994
  <VanArea
994
995
  v-model="localValue as string" :title="attr.name" :area-list="areaList"
995
996
  @confirm="onAreaConfirm"
@@ -1063,6 +1064,7 @@ function handleAddressConfirm(location) {
1063
1064
  position="bottom"
1064
1065
  :style="{ height: '80vh' }"
1065
1066
  teleport="body"
1067
+ overlay-class="date-picker-overlay"
1066
1068
  >
1067
1069
  <XLocationPicker
1068
1070
  :default-center="defaultMapCenter"
@@ -1073,5 +1075,7 @@ function handleAddressConfirm(location) {
1073
1075
  </template>
1074
1076
 
1075
1077
  <style scoped>
1076
-
1078
+ .date-picker-overlay {
1079
+ background-color: rgba(0, 0, 0, 0.2); /* 设置为半透明的黑色 */
1080
+ }
1077
1081
  </style>
@@ -15,6 +15,7 @@ import type {
15
15
  WebGLPointOptions,
16
16
  WMSLayerConfig,
17
17
  WMSOptions,
18
+ TrackData,
18
19
  } from './types'
19
20
  import locationIcon from '@af-mobile-client-vue3/assets/img/component/positioning.png'
20
21
  import { getConfigByName } from '@af-mobile-client-vue3/services/api/common'
@@ -23,11 +24,12 @@ import { Map, View } from 'ol'
23
24
  import { defaults as defaultControls, ScaleLine } from 'ol/control'
24
25
  import Feature from 'ol/Feature'
25
26
  import Point from 'ol/geom/Point'
27
+ import LineString from 'ol/geom/LineString'
26
28
  import { defaults as defaultInteractions } from 'ol/interaction'
27
29
  import { Image as ImageLayer, Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
28
30
  import { fromLonLat, toLonLat } from 'ol/proj'
29
31
  import { ImageWMS, Vector as VectorSource, XYZ } from 'ol/source'
30
- import { Fill, Icon, Stroke, Style, Text } from 'ol/style'
32
+ import { Fill, Icon, Stroke, Style, Text, Circle } from 'ol/style'
31
33
  import { Button } from 'vant'
32
34
  import { getCurrentInstance, onUnmounted, ref } from 'vue'
33
35
  import { wgs84ToGcj02Projection } from './utils/wgs84ToGcj02'
@@ -83,6 +85,10 @@ let locationTimer: ReturnType<typeof setInterval> | null = null
83
85
  /** 位置图标图层 */
84
86
  let locationLayer: VectorLayer<VectorSource> | null = null
85
87
 
88
+ /** 存储轨迹图层 */
89
+ const trackLayers: Record<number, VectorLayer<VectorSource>> = {}
90
+ const trackLayerStatus = ref<TrackData[]>([])
91
+
86
92
  /**
87
93
  * 创建位置图标图层
88
94
  */
@@ -890,6 +896,139 @@ function navigationHandleLocation() {
890
896
  }
891
897
  }
892
898
 
899
+ /**
900
+ * 添加轨迹图层
901
+ * @param trackData - 轨迹数据
902
+ */
903
+ function addTrackLayer(trackData: TrackData): void {
904
+ if (!map)
905
+ return
906
+
907
+ const vectorSource = new VectorSource()
908
+ const vectorLayer = new VectorLayer({
909
+ source: vectorSource,
910
+ visible: true,
911
+ zIndex: 2,
912
+ })
913
+
914
+ // 创建轨迹线要素
915
+ const coordinates = trackData.trackData.map(coord => fromLonLat(coord))
916
+ const lineString = new Feature({
917
+ geometry: new LineString(coordinates),
918
+ })
919
+
920
+ // 设置轨迹线样式
921
+ const lineStyle = new Style({
922
+ stroke: new Stroke({
923
+ color: trackData.color,
924
+ width: 3,
925
+ }),
926
+ })
927
+ lineString.setStyle(lineStyle)
928
+
929
+ // 创建起点和终点图标
930
+ const startPoint = new Feature({
931
+ geometry: new Point(coordinates[0]),
932
+ })
933
+ const endPoint = new Feature({
934
+ geometry: new Point(coordinates[coordinates.length - 1]),
935
+ })
936
+
937
+ // 设置起点图标样式 - 使用绿色圆形图标
938
+ const startStyle = new Style({
939
+ image: new Circle({
940
+ radius: 8,
941
+ fill: new Fill({
942
+ color: '#4CAF50',
943
+ }),
944
+ stroke: new Stroke({
945
+ color: '#fff',
946
+ width: 2,
947
+ }),
948
+ }),
949
+ text: new Text({
950
+ text: '起点',
951
+ offsetY: -15,
952
+ font: '12px sans-serif',
953
+ fill: new Fill({
954
+ color: '#333',
955
+ }),
956
+ stroke: new Stroke({
957
+ color: '#fff',
958
+ width: 2,
959
+ }),
960
+ }),
961
+ })
962
+
963
+ // 设置终点图标样式 - 使用红色圆形图标
964
+ const endStyle = new Style({
965
+ image: new Circle({
966
+ radius: 8,
967
+ fill: new Fill({
968
+ color: '#F44336',
969
+ }),
970
+ stroke: new Stroke({
971
+ color: '#fff',
972
+ width: 2,
973
+ }),
974
+ }),
975
+ text: new Text({
976
+ text: '终点',
977
+ offsetY: -15,
978
+ font: '12px sans-serif',
979
+ fill: new Fill({
980
+ color: '#333',
981
+ }),
982
+ stroke: new Stroke({
983
+ color: '#fff',
984
+ width: 2,
985
+ }),
986
+ }),
987
+ })
988
+
989
+ startPoint.setStyle(startStyle)
990
+ endPoint.setStyle(endStyle)
991
+
992
+ // 添加要素到图层
993
+ vectorSource.addFeatures([lineString, startPoint, endPoint])
994
+
995
+ // 添加到地图
996
+ map.addLayer(vectorLayer)
997
+ trackLayers[trackData.id] = vectorLayer
998
+
999
+ // 更新图层状态,确保 show 属性被正确设置
1000
+ const trackDataWithShow = {
1001
+ ...trackData,
1002
+ show: true, // 默认显示
1003
+ }
1004
+ trackLayerStatus.value.push(trackDataWithShow)
1005
+ }
1006
+
1007
+ /**
1008
+ * 控制轨迹图层显示/隐藏
1009
+ * @param trackId - 轨迹ID
1010
+ * @param visible - 是否显示
1011
+ */
1012
+ function setTrackLayerVisible(trackId: number, visible: boolean): void {
1013
+ const layer = trackLayers[trackId]
1014
+ if (layer) {
1015
+ layer.setVisible(visible)
1016
+ // 更新图层状态
1017
+ const layerIndex = trackLayerStatus.value.findIndex(layer => layer.id === trackId)
1018
+ if (layerIndex !== -1) {
1019
+ trackLayerStatus.value[layerIndex].show = visible
1020
+ }
1021
+ }
1022
+ }
1023
+
1024
+ /**
1025
+ * 切换轨迹图层显示状态
1026
+ */
1027
+ function handleToggleTrackLayer(track: TrackData): void {
1028
+ track.show = !track.show
1029
+ setTrackLayerVisible(track.id, track.show)
1030
+ }
1031
+
893
1032
  // 暴露方法给父组件
894
1033
  defineExpose({
895
1034
  init,
@@ -909,6 +1048,9 @@ defineExpose({
909
1048
  handleLocation,
910
1049
  startNavigation,
911
1050
  stopNavigation,
1051
+ addTrackLayer,
1052
+ setTrackLayerVisible,
1053
+ handleToggleTrackLayer,
912
1054
  })
913
1055
 
914
1056
  // 组件卸载时清理地图实例
@@ -1008,6 +1150,25 @@ onUnmounted(() => {
1008
1150
  </div>
1009
1151
  </div>
1010
1152
  </div>
1153
+
1154
+ <!-- 轨迹图层 -->
1155
+ <div v-if="trackLayerStatus.length > 0" class="control-panel layer-control">
1156
+ <div class="control-title">
1157
+ <i class="van-icon van-icon-location-o" /> 轨迹图层
1158
+ </div>
1159
+ <div class="layer-list">
1160
+ <div
1161
+ v-for="track in trackLayerStatus"
1162
+ :key="track.id"
1163
+ class="layer-item"
1164
+ :class="{ active: track.show }"
1165
+ @click="handleToggleTrackLayer(track)"
1166
+ >
1167
+ <i class="van-icon" :class="track.show ? 'van-icon-eye' : 'van-icon-closed-eye'" />
1168
+ <span>{{ track.name }}</span>
1169
+ </div>
1170
+ </div>
1171
+ </div>
1011
1172
  </div>
1012
1173
  </div>
1013
1174
  </div>
@@ -132,3 +132,14 @@ export interface WMSOptions {
132
132
  /** WMS 服务配置 */
133
133
  wms: WMSConfig
134
134
  }
135
+
136
+ /**
137
+ * 轨迹数据类型
138
+ */
139
+ export interface TrackData {
140
+ id: number
141
+ name: string
142
+ trackData: [number, number][] // 经纬度数组
143
+ color: string
144
+ show?: boolean // 是否显示
145
+ }
@@ -1,107 +1,24 @@
1
1
  <script setup lang="ts">
2
2
  import XCellList from '@af-mobile-client-vue3/components/data/XCellList/index.vue'
3
- import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDataLayout/index.vue'
4
- import { defineEmits, ref } from 'vue'
3
+ import { ref } from 'vue'
5
4
  import { useRouter } from 'vue-router'
6
5
 
7
- // 定义事件
8
- const emit = defineEmits(['deleteRow'])
9
- // 访问路由
10
- const router = useRouter()
11
- // 获取默认值
12
- const idKey = ref('o_id')
6
+ // 巡检计划
7
+ defineOptions({
8
+ name: 'PatrolPlan',
9
+ })
13
10
 
14
- // 简易crud表单测试
11
+ const router = useRouter()
15
12
  const configName = ref('crud_patroltask_managePhoneCRUD')
16
- const serviceName = ref('af-linepatrol')
17
-
18
- // 资源权限测试
19
- // const configName = ref('crud_sources_test')
20
- // const serviceName = ref('af-system')
21
-
22
- // 实际业务测试
23
- // const configName = ref('lngChargeAuditMobileCRUD')
24
- // const serviceName = ref('af-gaslink')
25
-
26
- // 跳转到详情页面
27
- // function toDetail(item) {
28
- // router.push({
29
- // name: 'XCellDetailView',
30
- // params: { id: item[idKey.value] }, // 如果使用命名路由,推荐使用路由参数而不是直接构建 URL
31
- // query: {
32
- // operName: item[operNameKey.value],
33
- // method:item[methodKey.value],
34
- // requestMethod:item[requestMethodKey.value],
35
- // operatorType:item[operatorTypeKey.value],
36
- // operUrl:item[operUrlKey.value],
37
- // operIp:item[operIpKey.value],
38
- // costTime:item[costTimeKey.value],
39
- // operTime:item[operTimeKey.value],
40
- //
41
- // title: item[titleKey.value],
42
- // businessType: item[businessTypeKey.value],
43
- // status:item[statusKey.value]
44
- // }
45
- // })
46
- // }
47
-
48
- // 跳转到表单——以表单组来渲染纯表单
49
- function toDetail(item) {
50
- router.push({
51
- name: 'XFormGroupView',
52
- query: {
53
- id: item[idKey.value],
54
- // id: item.rr_id,
55
- // o_id: item.o_id,
56
- },
57
- })
58
- }
59
-
60
- // 新增功能
61
- // function addOption(totalCount) {
62
- // router.push({
63
- // name: 'XFormView',
64
- // params: { id: totalCount, openid: totalCount },
65
- // query: {
66
- // configName: configName.value,
67
- // serviceName: serviceName.value,
68
- // mode: '新增',
69
- // },
70
- // })
71
- // }
72
-
73
- // 修改功能
74
- // function updateRow(result) {
75
- // router.push({
76
- // name: 'XFormView',
77
- // params: { id: result.o_id, openid: result.o_id },
78
- // query: {
79
- // configName: configName.value,
80
- // serviceName: serviceName.value,
81
- // mode: '修改',
82
- // },
83
- // })
84
- // }
85
-
86
- // 删除功能
87
- function deleteRow(result) {
88
- emit('deleteRow', result.o_id)
89
- }
13
+ const xCellListRefPatrolPlan = ref()
90
14
  </script>
91
15
 
92
16
  <template>
93
- <NormalDataLayout id="XCellListView" title="工作计划">
94
- <template #layout_content>
95
- <XCellList
96
- :config-name="configName"
97
- :service-name="serviceName"
98
- :fix-query-form="{ o_f_oper_name: 'edu_test' }"
99
- :id-key="idKey"
100
- @to-detail="toDetail"
101
- @delete-row="deleteRow"
102
- />
103
- </template>
104
- </NormalDataLayout>
17
+ <XCellList
18
+ ref="xCellListRefPatrolPlan"
19
+ service-name="af-linepatrol"
20
+ :config-name="configName"
21
+ />
105
22
  </template>
106
23
 
107
24
  <style scoped lang="less">
@@ -12,16 +12,19 @@ const formGroupAddConstruction = ref(null)
12
12
  <template>
13
13
  <NormalDataLayout id="XFormGroupView" title="纯表单">
14
14
  <template #layout_content>
15
- <XForm
15
+ <div class="form"> <XForm
16
16
  ref="formGroupAddConstruction"
17
17
  mode="新增"
18
18
  :config-name="configName"
19
19
  :service-name="serviceName"
20
- />
20
+ /></div>
21
+
21
22
  </template>
22
23
  </NormalDataLayout>
23
24
  </template>
24
25
 
25
26
  <style scoped lang="less">
26
-
27
+ .form {
28
+ margin-top: 2px;
29
+ }
27
30
  </style>
@@ -3,6 +3,7 @@ import NormalDataLayout from '@af-mobile-client-vue3/components/layout/NormalDat
3
3
  import { showNotify } from 'vant'
4
4
  import { onMounted, ref } from 'vue'
5
5
  import XOlMap from '../../../components/data/XOlMap/index.vue'
6
+ import { trackTestData } from './testData'
6
7
  import 'vant/lib/index.css'
7
8
 
8
9
  const mapRef = ref()
@@ -265,6 +266,13 @@ function handleAddMassPoints() {
265
266
  })
266
267
  }
267
268
 
269
+ // 添加轨迹测试
270
+ function handleAddTrack() {
271
+ trackTestData.forEach((track) => {
272
+ mapRef.value.addTrackLayer(track)
273
+ })
274
+ }
275
+
268
276
  // 导航模式相关
269
277
  const isNavigationMode = ref(false)
270
278
 
@@ -322,6 +330,15 @@ function stopNavigation() {
322
330
  </van-button>
323
331
  </div>
324
332
 
333
+ <div class="control-group">
334
+ <div class="group-title">
335
+ 轨迹示例
336
+ </div>
337
+ <van-button type="primary" size="small" @click="handleAddTrack">
338
+ 添加测试轨迹
339
+ </van-button>
340
+ </div>
341
+
325
342
  <div class="control-group">
326
343
  <div class="group-title">
327
344
  导航模式测试
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 轨迹测试数据
3
+ */
4
+
5
+ // 轨迹数据类型定义
6
+ export interface TrackData {
7
+ id: number
8
+ name: string
9
+ trackData: [number, number][] // 经纬度数组
10
+ color: string
11
+ show?: boolean // 是否显示
12
+ }
13
+
14
+ /**
15
+ * 生成随机轨迹点
16
+ * @param startPoint - 起始点 [经度, 纬度]
17
+ * @param pointCount - 点的数量
18
+ * @param maxOffset - 最大偏移量(经纬度)
19
+ * @returns 轨迹点数组
20
+ */
21
+ function generateRandomTrack(
22
+ startPoint: [number, number],
23
+ pointCount: number,
24
+ maxOffset: number = 0.01,
25
+ ): [number, number][] {
26
+ const points: [number, number][] = [startPoint]
27
+ let currentPoint = startPoint
28
+
29
+ for (let i = 1; i < pointCount; i++) {
30
+ // 生成随机偏移量,使用正态分布使轨迹更自然
31
+ const offsetLng = (Math.random() - 0.5) * maxOffset * (1 + Math.random() * 0.5)
32
+ const offsetLat = (Math.random() - 0.5) * maxOffset * (1 + Math.random() * 0.5)
33
+
34
+ // 添加一些随机性,使轨迹更自然
35
+ const randomFactor = Math.random() > 0.8 ? 2 : 1 // 偶尔会有较大的偏移
36
+ const newPoint: [number, number] = [
37
+ currentPoint[0] + offsetLng * randomFactor,
38
+ currentPoint[1] + offsetLat * randomFactor,
39
+ ]
40
+
41
+ points.push(newPoint)
42
+ currentPoint = newPoint
43
+ }
44
+
45
+ return points
46
+ }
47
+
48
+ // 测试数据
49
+ export const trackTestData: TrackData[] = [
50
+ {
51
+ id: 1,
52
+ name: '张三的轨迹',
53
+ trackData: generateRandomTrack([108.948024, 34.263161], 1000, 0.005),
54
+ color: '#FF0000',
55
+ show: true,
56
+ },
57
+ {
58
+ id: 2,
59
+ name: '李四的轨迹',
60
+ trackData: generateRandomTrack([108.948024, 34.263161], 500, 0.003),
61
+ color: '#00FF00',
62
+ show: true,
63
+ },
64
+ ]
package/vite.config.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import type { ConfigEnv, UserConfig } from 'vite'
2
2
  import path from 'node:path'
3
3
  import process from 'node:process'
4
- // import autoprefixer from 'autoprefixer'
5
- // import viewport from 'postcss-mobile-forever'
4
+ import autoprefixer from 'autoprefixer'
5
+ import viewport from 'postcss-mobile-forever'
6
6
  import { loadEnv } from 'vite'
7
7
  import { createVitePlugins } from './build/vite'
8
8
 
@@ -95,15 +95,15 @@ export default ({ mode }: ConfigEnv): UserConfig => {
95
95
  postcss: {
96
96
  plugins: [
97
97
  // 自动获取浏览器的流行度和能够支持的属性,并为 CSS 规则添加前缀
98
- // autoprefixer(),
99
- // viewport({
100
- // appSelector: '#system-app',
101
- // viewportWidth: 375,
102
- // maxDisplayWidth: 800,
103
- // appContainingBlock: 'auto',
104
- // necessarySelectorWhenAuto: '.app-wrapper',
105
- // rootContainingBlockSelectorList: ['van-tabbar', 'van-popup'],
106
- // }),
98
+ autoprefixer(),
99
+ viewport({
100
+ appSelector: '#system-app',
101
+ viewportWidth: 375,
102
+ maxDisplayWidth: 800,
103
+ appContainingBlock: 'auto',
104
+ necessarySelectorWhenAuto: '.app-wrapper',
105
+ rootContainingBlockSelectorList: ['van-tabbar', 'van-popup'],
106
+ }),
107
107
  ],
108
108
  },
109
109
  },