af-mobile-client-vue3 1.0.90 → 1.0.93

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.
@@ -0,0 +1,119 @@
1
+ <script setup lang="ts">
2
+ import { ref } from 'vue'
3
+ import { Icon as VanIcon } from 'vant'
4
+
5
+ defineEmits(['close'])
6
+
7
+ const isScanning = ref(true)
8
+ </script>
9
+
10
+ <template>
11
+ <div class="vpn-recognition">
12
+ <div class="scanner-container">
13
+ <div class="scanner-bg">
14
+ <div class="scan-circle">
15
+ <VanIcon name="idcard" size="60" color="rgb(59,130,246)"/>
16
+ </div>
17
+ <div class="scan-ripple" v-if="isScanning" />
18
+ <div class="scan-tip">
19
+ 准备读取NFC
20
+ </div>
21
+ </div>
22
+ <div class="scan-subtitle">
23
+ 请将手机靠近NFC标签进行读取
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </template>
28
+
29
+ <style scoped lang="less">
30
+ .vpn-recognition {
31
+ width: 100%;
32
+ height: 100%;
33
+ background-color: #fff;
34
+ display: flex;
35
+ flex-direction: column;
36
+ border-radius: 8px;
37
+ overflow: hidden;
38
+
39
+ .scanner-container {
40
+ flex: 1;
41
+ display: flex;
42
+ flex-direction: column;
43
+ align-items: center;
44
+ justify-content: center;
45
+ padding: 20px;
46
+ background-color: #fff;
47
+
48
+ .scanner-bg {
49
+ width: 320px;
50
+ height: 320px;
51
+ background-color: #f0f0f0;
52
+ border-radius: 8px;
53
+ padding: 20px;
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: center;
57
+ justify-content: flex-start;
58
+ padding-top: 40px;
59
+ position: relative;
60
+ }
61
+
62
+ .scan-circle {
63
+ width: 100px;
64
+ height: 100px;
65
+ border-radius: 50%;
66
+ background-color: rgba(25, 137, 250, 0.1);
67
+ display: flex;
68
+ align-items: center;
69
+ justify-content: center;
70
+ margin-bottom: 20px;
71
+ position: relative;
72
+ z-index: 2;
73
+ }
74
+
75
+ .scan-ripple {
76
+ position: absolute;
77
+ top: 35%;
78
+ left: 50%;
79
+ transform: translate(-50%, -50%);
80
+ width: 120px;
81
+ height: 120px;
82
+ background-color: rgba(25, 137, 250, 0.2);
83
+ border-radius: 50%;
84
+ animation: ripple 3s infinite;
85
+ z-index: 1;
86
+ }
87
+
88
+ .scan-tip {
89
+ color: #666;
90
+ font-size: 16px;
91
+ text-align: center;
92
+ margin-top: 30px;
93
+ margin-bottom: 8px;
94
+ width: 100%;
95
+ font-weight: normal;
96
+ }
97
+
98
+ .scan-subtitle {
99
+ font-size: 14px;
100
+ color: #969799;
101
+ text-align: center;
102
+ width: 100%;
103
+ font-weight: bold;
104
+ margin-top: 7%;
105
+ }
106
+ }
107
+ }
108
+
109
+ @keyframes ripple {
110
+ 0% {
111
+ transform: translate(-50%, -50%) scale(1);
112
+ opacity: 0.5;
113
+ }
114
+ 100% {
115
+ transform: translate(-50%, -50%) scale(2);
116
+ opacity: 0;
117
+ }
118
+ }
119
+ </style>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { defineEmits, defineModel, defineProps, onMounted, ref } from 'vue'
2
+ import { defineEmits, defineModel, defineProps, nextTick, ref } from 'vue'
3
3
  import {
4
4
  Button as VanButton,
5
5
  Col as VanCol,
@@ -11,6 +11,8 @@ import {
11
11
  } from 'vant'
12
12
  import XGridDropOption from '@af-mobile-client-vue3/components/core/XGridDropOption/index.vue'
13
13
  import XFormItem from '@af-mobile-client-vue3/components/data/XFormItem/index.vue'
14
+ import QrScanner from './QrScanner/index.vue'
15
+ import VpnRecognition from './VpnRecognition/index.vue'
14
16
 
15
17
  const props = defineProps<{
16
18
  fixQueryForm?: object
@@ -28,6 +30,9 @@ const emit = defineEmits([
28
30
  'update:conditionParams',
29
31
  'onRefresh',
30
32
  'addOption',
33
+ 'toggleView',
34
+ 'onScan',
35
+ 'onNFC',
31
36
  ])
32
37
  // 排序字段
33
38
  const currentOrderVal = defineModel('orderVal')
@@ -48,6 +53,13 @@ const colFieldNames = {
48
53
  // 查询条件参数 !!!!!建议最后点击确认的时候完成这个的整理
49
54
  const conditionParams = ref({})
50
55
 
56
+ // 视图模式
57
+ const scanType = ref('scan') // 'scan' 或 'nfc'
58
+
59
+ const scanMenuShow = ref(false)
60
+ const filterMenuShow = ref(false)
61
+ const showScanner = ref(true)
62
+
51
63
  // 重置某个选项
52
64
  function resetOptionItem(type) {
53
65
  if (conditionParams.value[type] !== undefined)
@@ -94,79 +106,211 @@ function addOption() {
94
106
  emit('addOption')
95
107
  }
96
108
 
97
- onMounted(() => {
98
- // currentOrderVal.value = props.orderVal
99
- // currentSortordVal.value = props.sortordVal
100
- // disposalData()
101
- })
109
+ // 处理扫码菜单显示
110
+ function handleScanMenuChange(value: boolean) {
111
+ scanMenuShow.value = value
112
+ if (value) {
113
+ filterMenuShow.value = false
114
+ scanType.value = 'scan'
115
+ // 先设为false再设为true,强制重新挂载组件
116
+ showScanner.value = false
117
+ setTimeout(() => {
118
+ showScanner.value = true
119
+ }, 10)
120
+ }
121
+ else {
122
+ showScanner.value = false
123
+ }
124
+ }
125
+
126
+ // 处理筛选菜单显示
127
+ function handleFilterMenuChange(value: boolean) {
128
+ filterMenuShow.value = value
129
+ if (value) {
130
+ scanMenuShow.value = false
131
+ showScanner.value = false
132
+ }
133
+ }
134
+
135
+ // 处理扫码
136
+ function handleScan() {
137
+ scanType.value = 'scan'
138
+ // 重新挂载扫描组件
139
+ showScanner.value = false
140
+ setTimeout(() => {
141
+ showScanner.value = true
142
+ }, 10)
143
+ emit('onScan')
144
+ }
145
+
146
+ // 处理NFC
147
+ function handleNFC() {
148
+ scanType.value = 'nfc'
149
+ showScanner.value = false
150
+ emit('onNFC')
151
+ }
152
+
153
+ // 处理关闭扫描按钮点击
154
+ function handleCloseScanButton() {
155
+ listFilterMenu.value.close(false)
156
+ }
102
157
  </script>
103
158
 
104
159
  <template>
105
160
  <div id="XCellListFilter">
106
- <VanDropdownMenu :close-on-click-outside="false" class="filter-dropdown-menu">
107
- <VanDropdownItem ref="listFilterMenu">
108
- <template #title>
109
- <div class="filter-icon-box">
110
- <VanIcon name="apps-o" size="24" class="filter-icon" />
111
- </div>
112
- </template>
113
- <div class="order-condition">
114
- <template v-if="props.orderList.length > 0">
115
- <VanRow justify="space-between" class="filter-title">
116
- <VanCol span="10">
117
- 排序字段
118
- </VanCol>
119
- <VanCol span="2">
120
- <div class="reset-item" @click.stop="currentOrderVal = undefined">
121
- 重置
122
- </div>
123
- </VanCol>
124
- </VanRow>
125
- <XGridDropOption :columns="props.orderList" :columns-field-names="colFieldNames" />
126
- <VanRow justify="space-between" class="filter-title">
127
- <VanCol span="10">
128
- 排序规则
129
- </VanCol>
130
- <VanCol span="2">
131
- <div class="reset-item" @click.stop="currentSortordVal = undefined">
132
- 重置
133
- </div>
134
- </VanCol>
135
- </VanRow>
136
- <XGridDropOption :columns="sortordList" :columns-field-names="colFieldNames" />
161
+ <div class="filter-buttons">
162
+ <VanDropdownMenu :close-on-click-outside="false" class="filter-dropdown-menu" ref="listFilterMenu">
163
+ <VanDropdownItem v-model="scanMenuShow" @change="handleScanMenuChange">
164
+ <template #title>
165
+ <div class="filter-icon-box">
166
+ <VanIcon name="apps-o" size="24" class="filter-icon" />
167
+ </div>
137
168
  </template>
138
- <template v-for="(item, index) in props.formQuery" :key="`${item.model}${index}`">
139
- <VanRow justify="space-between" class="filter-title">
140
- <VanCol span="10">
141
- {{ item.name }}
142
- </VanCol>
143
- <VanCol span="2">
144
- <div class="reset-item" @click.stop="resetOptionItem(item.model)">
145
- 重置
146
- </div>
147
- </VanCol>
148
- </VanRow>
149
- <XFormItem v-model="conditionParams[item.model]" :form="conditionParams" :attr="item" :service-name="props.serviceName" :show-label="false" />
169
+ <div class="scan-tab-wrapper">
170
+ <div class="scan-tabs">
171
+ <div
172
+ class="scan-tab-item"
173
+ :class="{ active: scanType === 'scan' }"
174
+ @click="handleScan"
175
+ >
176
+ <VanIcon name="scan" class="tab-icon" />
177
+ 扫码
178
+ </div>
179
+ <div
180
+ class="scan-tab-item"
181
+ :class="{ active: scanType === 'nfc' }"
182
+ @click="handleNFC"
183
+ >
184
+ <VanIcon name="wifi" class="tab-icon" />
185
+ NFC
186
+ </div>
187
+ </div>
188
+ </div>
189
+ <div v-if="scanType === 'scan'" class="scanORnfc">
190
+ <QrScanner v-if="showScanner" @close="handleCloseScanButton" />
191
+ </div>
192
+ <div v-if="scanType === 'nfc'" class="scanORnfc">
193
+ <VpnRecognition @close="handleCloseScanButton" />
194
+ </div>
195
+ <div class="closeItem">
196
+ <VanButton
197
+ type="primary"
198
+ size="normal"
199
+ class="close-scan-btn"
200
+ icon="cross"
201
+ @click="handleCloseScanButton"
202
+ >
203
+ {{ scanType === 'scan' ? '关闭扫描' : '关闭读取' }}
204
+ </VanButton>
205
+ </div>
206
+ </VanDropdownItem>
207
+ <VanDropdownItem v-model="filterMenuShow" @change="handleFilterMenuChange">
208
+ <template #title>
209
+ <div class="filter-icon-box">
210
+ <VanIcon name="filter-o" size="24" class="filter-icon" />
211
+ </div>
150
212
  </template>
151
- </div>
152
- <div class="operations-panel">
153
- <VanButton type="default" @click="resetOption">
154
- 重置
155
- </VanButton>
156
- <VanButton v-if="props.buttonState.add && props.buttonState.add === true" type="primary" @click="addOption">
157
- 新增
158
- </VanButton>
159
- <VanButton type="primary" @click="confirmOption">
160
- 查询
161
- </VanButton>
162
- </div>
163
- </VanDropdownItem>
164
- </VanDropdownMenu>
213
+ <div class="order-condition">
214
+ <template v-if="props.orderList.length > 0">
215
+ <VanRow justify="space-between" class="filter-title">
216
+ <VanCol span="10">
217
+ 排序字段
218
+ </VanCol>
219
+ <VanCol span="2">
220
+ <div class="reset-item" @click.stop="currentOrderVal = undefined">
221
+ 重置
222
+ </div>
223
+ </VanCol>
224
+ </VanRow>
225
+ <XGridDropOption :columns="props.orderList" :columns-field-names="colFieldNames" />
226
+ <VanRow justify="space-between" class="filter-title">
227
+ <VanCol span="10">
228
+ 排序规则
229
+ </VanCol>
230
+ <VanCol span="2">
231
+ <div class="reset-item" @click.stop="currentSortordVal = undefined">
232
+ 重置
233
+ </div>
234
+ </VanCol>
235
+ </VanRow>
236
+ <XGridDropOption :columns="sortordList" :columns-field-names="colFieldNames" />
237
+ </template>
238
+ <template v-for="(item, index) in props.formQuery" :key="`${item.model}${index}`">
239
+ <VanRow justify="space-between" class="filter-title">
240
+ <VanCol span="10">
241
+ {{ item.name }}
242
+ </VanCol>
243
+ <VanCol span="2">
244
+ <div class="reset-item" @click.stop="resetOptionItem(item.model)">
245
+ 重置
246
+ </div>
247
+ </VanCol>
248
+ </VanRow>
249
+ <XFormItem v-model="conditionParams[item.model]" :form="conditionParams" :attr="item" :service-name="props.serviceName" :show-label="false" />
250
+ </template>
251
+ </div>
252
+ <div class="operations-panel">
253
+ <VanButton type="default" @click="resetOption">
254
+ 重置
255
+ </VanButton>
256
+ <VanButton v-if="props.buttonState.add && props.buttonState.add === true" type="primary" @click="addOption">
257
+ 新增
258
+ </VanButton>
259
+ <VanButton type="primary" @click="confirmOption">
260
+ 查询
261
+ </VanButton>
262
+ </div>
263
+ </VanDropdownItem>
264
+ </VanDropdownMenu>
265
+ </div>
165
266
  </div>
166
267
  </template>
167
268
 
168
269
  <style scoped lang="less">
169
270
  #XCellListFilter {
271
+ width: 100%;
272
+ .filter-buttons {
273
+ display: flex;
274
+ align-items: center;
275
+ justify-content: flex-end;
276
+ gap: 8px;
277
+ }
278
+
279
+ .scan-tab-wrapper {
280
+ padding: 12px 16px;
281
+ background-color: #fff;
282
+ .scan-tabs {
283
+ display: flex;
284
+ background: #f5f5f5;
285
+ border-radius: 8px;
286
+ padding: 2px;
287
+ .scan-tab-item {
288
+ flex: 1;
289
+ height: 44px;
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ font-size: 15px;
294
+ color: #646566;
295
+ cursor: pointer;
296
+ border-radius: 6px;
297
+ gap: 4px;
298
+
299
+ .tab-icon {
300
+ font-size: 20px;
301
+ }
302
+
303
+ &.active {
304
+ background-color: #1989fa;
305
+ color: #fff;
306
+ .tab-icon {
307
+ color: #fff;
308
+ }
309
+ }
310
+ }
311
+ }
312
+ }
313
+
170
314
  .filter-dropdown-menu {
171
315
  :deep(.van-dropdown-menu__bar) {
172
316
  box-shadow: none;
@@ -177,14 +321,29 @@ onMounted(() => {
177
321
  align-items: center;
178
322
  justify-content: center;
179
323
  }
324
+ // 隐藏下拉箭头
325
+ :deep(.van-dropdown-menu__title::after) {
326
+ display: none !important;
327
+ }
180
328
  }
329
+
181
330
  .filter-icon {
182
331
  color: #333;
183
332
  background-color: rgba(245,245,245);
184
333
  }
334
+
185
335
  .filter-icon-box {
336
+ display: flex;
337
+ align-items: center;
338
+ justify-content: center;
339
+ width: 40px;
340
+ height: 40px;
186
341
  border-radius: 10px;
187
342
  background-color: rgba(245,245,245);
343
+ cursor: pointer;
344
+ &:active {
345
+ opacity: 0.7;
346
+ }
188
347
  }
189
348
  .order-condition {
190
349
  // padding-bottom: 10px;
@@ -262,5 +421,36 @@ onMounted(() => {
262
421
  color: rgba(25, 137, 250, 0.1);
263
422
  }
264
423
  }
424
+ .scanORnfc {
425
+ height: 50vh;
426
+ width: 100%;
427
+ position: relative;
428
+ background-color: #f0f0f0;
429
+ border-radius: 8px;
430
+ }
431
+ .closeItem {
432
+ display: flex;
433
+ justify-content: center;
434
+ margin-top: 16px;
435
+ margin-bottom: 20px;
436
+
437
+ .close-scan-btn {
438
+ width: 140px;
439
+ height: 40px;
440
+ background-color: #1989fa;
441
+ border-radius: 4px;
442
+ font-size: 14px;
443
+ border: none;
444
+ display: flex;
445
+ align-items: center;
446
+ justify-content: center;
447
+ padding: 0;
448
+
449
+ :deep(.van-button__icon) {
450
+ margin-right: 4px;
451
+ font-size: 16px;
452
+ }
453
+ }
454
+ }
265
455
  }
266
456
  </style>
@@ -139,7 +139,7 @@ defineExpose({ init, form, formGroupName, validate })
139
139
  :get-data-params="myGetDataParams"
140
140
  />
141
141
  </VanCellGroup>
142
- <div v-if="props.submitButton" style="margin: 16px;">
142
+ <div v-if="props.submitButton && props.mode !== '预览'" style="margin: 16px;">
143
143
  <VanButton round block type="primary" native-type="submit">
144
144
  {{ props.groupFormItems?.btnName ? props.groupFormItems.btnName : '提交' }}
145
145
  </VanButton>