af-mobile-client-vue3 1.3.28 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "af-mobile-client-vue3",
3
3
  "type": "module",
4
- "version": "1.3.28",
4
+ "version": "1.3.30",
5
5
  "packageManager": "pnpm@10.13.1",
6
6
  "description": "Vue + Vite component lib",
7
7
  "engines": {
@@ -16,7 +16,7 @@ const props = defineProps({
16
16
  attr: { type: Object as () => { addOrEdit?: string, acceptCount?: number, uploadImage?: boolean }, default: () => ({}) },
17
17
  mode: { default: '新增' }, // 预览
18
18
  })
19
- const emit = defineEmits(['updateFileList'])
19
+ const emit = defineEmits(['updateFileList', 'updateAllFileList'])
20
20
 
21
21
  const imageList = ref<Array<any>>(props.imageList ?? [])
22
22
 
@@ -97,6 +97,8 @@ function handlePhotoUpload(photoData: any) {
97
97
  }
98
98
  }
99
99
 
100
+ emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item)) // 新增
101
+
100
102
  const doneIds = Object.values(imageList.value)
101
103
  .filter(item => item.status === 'done')
102
104
  .map(item => item.id)
@@ -117,6 +119,9 @@ function deleteFileFunction(file: any) {
117
119
  const targetIndex = imageList.value.findIndex(item => item.id === file.id)
118
120
  if (targetIndex !== -1) {
119
121
  imageList.value.splice(targetIndex, 1)
122
+
123
+ emit('updateAllFileList', imageList.value.filter(item => item.status === 'done').map(item => item)) // 新增
124
+
120
125
  const doneIds = Object.values(imageList.value)
121
126
  .filter(item => item.status === 'done')
122
127
  .map(item => item.id)
@@ -205,13 +210,15 @@ function handleActionSelect(option: any) {
205
210
  .uploader-container {
206
211
  display: flex;
207
212
  flex-direction: column;
208
- gap: 16px;
213
+ // 该属性会影响表单布局
214
+ // gap: 16px;
209
215
  }
210
216
  .custom-upload-area {
211
217
  width: 100%;
212
218
  min-width: 220px;
213
219
  min-height: 100px;
214
- margin: 0 auto 12px auto;
220
+ // 该属性会影响表单布局
221
+ // margin: 0 auto 12px auto;
215
222
  box-sizing: border-box;
216
223
  border: 1px dashed #d9d9d9;
217
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 | 配置名称 | string | - |
116
- | serviceName | 服务名称 | string | - |
117
- | fixQueryForm | 固定查询参数 | object | null |
118
- | idKey | 主键字段 | string | 'o_id' |
119
- | customAdd | 是否采用自定义新增按钮 | boolean | false |
120
- | customEdit | 是否采用自定义修改按钮 | boolean | false |
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 | 点击详情时触发 | item: 当前项数据 |
127
- | add | 点击新增按钮时触发(customAdd为true才会触发) | - |
128
- | update | 点击修改按钮时触发(customEdit为true才会触发) | item: 当前项数据 |
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
  // 清理并重新设置验证规则
@@ -122,7 +122,7 @@ const routes: Array<RouteRecordRaw> = [
122
122
  component: XFormAppraiseView,
123
123
  },
124
124
  {
125
- path: '/Component/XFormView/:id/:openid',
125
+ path: '/Component/XFormView',
126
126
  name: 'XFormView',
127
127
  component: XFormView,
128
128
  },
@@ -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,19 +1,27 @@
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
  // 获取默认值
12
20
  const idKey = ref('o_id')
13
21
 
14
22
  // 简易crud表单测试
15
- const configName = ref('mobile_meterInfoManageCRUD')
16
- const serviceName = ref('af-revenue')
23
+ const configName = ref('lngChargeAuditMobileCRUD')
24
+ const serviceName = ref('af-gaslink')
17
25
 
18
26
  // 资源权限测试
19
27
  // const configName = ref('crud_sources_test')
@@ -48,7 +56,7 @@ const serviceName = ref('af-revenue')
48
56
  // 跳转到表单——以表单组来渲染纯表单
49
57
  function toDetail(item) {
50
58
  router.push({
51
- name: 'XFormGroupView',
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
- :config-name="configName"
97
- :service-name="serviceName"
98
- :fix-query-form="{ o_f_oper_name: 'edu_test' }"
99
- :id-key="idKey"
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
- @delete-row="deleteRow"
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
- // const configName = ref('lngChargeAuditMobileFormGroup')
17
- // const serviceName = ref('af-gaslink')
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
- history.back()
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
- :config-name="configName"
67
- :service-name="serviceName"
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('AddConstructionForm')
7
- const serviceName = ref('af-linepatrol')
6
+ const configName = ref('lngSecurityChecktestForm')
7
+ const serviceName = ref('af-safecheck')
8
8
 
9
9
  const formGroupAddConstruction = ref(null)
10
10
  </script>
package/vite.config.ts CHANGED
@@ -68,13 +68,6 @@ export default ({ mode }: ConfigEnv): UserConfig => {
68
68
  changeOrigin: true,
69
69
  rewrite: path => path.replace(/^\/linepatrol\/geoserver/, '/geoserver'),
70
70
  },
71
- '/api/af-revenue': {
72
- // target: v4Server,
73
- rewrite: (path: string) => path.replace(/^\/api\/af-revenue\//, '/'),
74
- target: 'http://127.0.0.1:9026',
75
- ws: false,
76
- changeOrigin: true,
77
- },
78
71
  '/api': {
79
72
  // v3用
80
73
  // rewrite: (path: string) => path.replace(/^\/api\/af-system\//, '/rs/'),