af-mobile-client-vue3 1.0.82 → 1.0.84-1

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.
Files changed (25) hide show
  1. package/package.json +1 -1
  2. package/src/components/data/XCellList/XCellList.md +275 -275
  3. package/src/components/data/XFormItem/index.vue +0 -2
  4. package/src/components/data/XReportGrid/XAddReport/XAddReport.vue +208 -0
  5. package/src/components/data/XReportGrid/XAddReport/index.js +3 -0
  6. package/src/components/data/XReportGrid/XAddReport/index.md +56 -0
  7. package/src/components/data/XReportGrid/XAddReport/index.ts +10 -0
  8. package/src/components/data/XReportGrid/XReport.vue +972 -0
  9. package/src/components/data/XReportGrid/XReportDemo.vue +33 -0
  10. package/src/components/data/XReportGrid/XReportDesign.vue +597 -0
  11. package/src/components/data/XReportGrid/XReportDrawer/XReportDrawer.vue +154 -0
  12. package/src/components/data/XReportGrid/XReportDrawer/index.js +3 -0
  13. package/src/components/data/XReportGrid/XReportDrawer/index.ts +10 -0
  14. package/src/components/data/XReportGrid/XReportJsonRender.vue +386 -0
  15. package/src/components/data/XReportGrid/XReportTrGroup.vue +589 -0
  16. package/src/components/data/XReportGrid/index.md +44 -0
  17. package/src/components/data/XReportGrid/index.ts +10 -0
  18. package/src/components/data/XReportGrid/print.js +184 -0
  19. package/src/router/routes.ts +13 -1
  20. package/src/views/component/XCellListView/index.vue +10 -18
  21. package/src/views/component/XFormGroupView/index.vue +6 -15
  22. package/src/views/component/XReportGridView/index.vue +14 -0
  23. package/src/views/component/index.vue +4 -0
  24. package/src/views/component/test/index.vue +52 -0
  25. package/tsconfig.json +43 -43
@@ -0,0 +1,154 @@
1
+ <template>
2
+ <van-popup
3
+ v-model:show="visible"
4
+ position="right"
5
+ :style="{ width: '85vw', height: '100%' }"
6
+ @close="close"
7
+ v-bind="attr"
8
+ >
9
+ <XReport
10
+ ref="mainRef"
11
+ :env="env"
12
+ :use-oss-for-img="false"
13
+ :config-name="configName"
14
+ :show-img-in-cell="true"
15
+ :display-only="displayOnly"
16
+ :edit-mode="false"
17
+ :show-save-button="false"
18
+ :dont-format="true"
19
+ @update-img="updateImg"
20
+ @select-row="selectRow"
21
+ />
22
+ </van-popup>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { ref, provide, inject } from 'vue'
27
+ import { storeToRefs } from 'pinia'
28
+ import { useUserStore } from '@/stores/modules/user'
29
+ import { Popup as VanPopup } from 'vant'
30
+ import { executeStrFunctionByContext } from '@/utils/runEvalFunction'
31
+ import { runLogic } from '@/services/api/common'
32
+ import { getMicroData, getWindow, isMicroAppEnv, microDispatch } from '@/utils/microAppUtils'
33
+ import { getRealKeyData } from '@/utils/util'
34
+ import XReport from '../XReport.vue'
35
+
36
+ // Props
37
+ const props = defineProps({
38
+ env: {
39
+ type: String,
40
+ default: 'prod'
41
+ }
42
+ })
43
+
44
+ // 状态管理
45
+ const configName = ref('')
46
+ const displayOnly = ref(true)
47
+ const serverName = ref(process.env.VUE_APP_SYSTEM_NAME)
48
+ const loading = ref(false)
49
+ const visible = ref(false)
50
+ const selectedId = ref(null)
51
+ const mixinData = ref({})
52
+ const outEnv = ref({})
53
+ const attr = ref({})
54
+
55
+ // Store
56
+ const userStore = useUserStore()
57
+ const { user: currUser } = storeToRefs(userStore)
58
+
59
+ // Refs
60
+ const mainRef = ref()
61
+
62
+ // 注入
63
+ const getParentComponentByName = inject<Function>('getParentComponentByName')
64
+ const setGlobalData = inject<Function>('setGlobalData')
65
+ const getGlobalData = inject<Function>('getGlobalData')
66
+
67
+ // 提供依赖
68
+ provide('getSelectedId', () => getSelectedId())
69
+ provide('getSelectedData', () => selectedId.value)
70
+ provide('getMixinData', () => mixinData.value)
71
+ provide('getOutEnv', () => outEnv.value)
72
+ provide('isInAModal', () => true)
73
+ provide('currUser', currUser)
74
+
75
+ // Methods
76
+ const init = (params: {
77
+ configName?: string
78
+ serverName?: string
79
+ displayOnly?: boolean
80
+ selectedId?: any
81
+ outEnv?: Record<string, any>
82
+ mixinData?: Record<string, any>
83
+ attr?: Record<string, any>
84
+ }) => {
85
+ const {
86
+ configName: initConfigName = '',
87
+ serverName: initServerName = process.env.VUE_APP_SYSTEM_NAME,
88
+ displayOnly: initDisplayOnly = true,
89
+ selectedId: initSelectedId = null,
90
+ outEnv: initOutEnv = {},
91
+ mixinData: initMixinData = {},
92
+ attr: initAttr = {}
93
+ } = params
94
+
95
+ configName.value = initConfigName
96
+ serverName.value = initServerName
97
+ displayOnly.value = initDisplayOnly
98
+ visible.value = true
99
+ attr.value = initAttr
100
+
101
+ if (initSelectedId) {
102
+ selectedId.value = initSelectedId
103
+ }
104
+ mixinData.value = initMixinData
105
+ outEnv.value = initOutEnv
106
+ }
107
+
108
+ const getSelectedId = () => {
109
+ if (typeof selectedId.value === 'object') {
110
+ if (selectedId.value?.selectedId) {
111
+ return selectedId.value.selectedId
112
+ }
113
+ if (Object.keys(selectedId.value).length > 0) {
114
+ return selectedId.value[Object.keys(selectedId.value)[0]]
115
+ }
116
+ }
117
+ return selectedId.value
118
+ }
119
+
120
+ const selectRow = (selectedRowKeys: any[], selectedRows: any[]) => {
121
+ console.log('XReportDrawer')
122
+ emit('selectRow', selectedRowKeys, selectedRows)
123
+ }
124
+
125
+ const close = () => {
126
+ loading.value = false
127
+ visible.value = false
128
+ emit('close')
129
+ }
130
+
131
+ const getComponentByName = (name: string) => {
132
+ const innerRef = getParentComponentByName?.(name)
133
+ if (innerRef) {
134
+ return innerRef
135
+ }
136
+ return mainRef.value?.getComponentByName(name)
137
+ }
138
+
139
+ const updateImg = (data: any) => {
140
+ console.log(data)
141
+ }
142
+
143
+ // Emits
144
+ const emit = defineEmits<{
145
+ (e: 'close'): void
146
+ (e: 'selectRow', keys: any[], rows: any[]): void
147
+ }>()
148
+
149
+ // 暴露方法
150
+ defineExpose({
151
+ init,
152
+ getComponentByName
153
+ })
154
+ </script>
@@ -0,0 +1,3 @@
1
+ import XReportDrawer from './XReportDrawer'
2
+
3
+ export default XReportDrawer
@@ -0,0 +1,10 @@
1
+ import type { App } from 'vue'
2
+ import XReportDrawer from './XReportDrawer.vue'
3
+
4
+ export { XReportDrawer }
5
+
6
+ export default {
7
+ install(app: App) {
8
+ app.component('XReportDrawer', XReportDrawer)
9
+ }
10
+ }
@@ -0,0 +1,386 @@
1
+ <script setup lang="ts">
2
+ import { onBeforeMount, ref } from 'vue'
3
+ import type { Ref } from 'vue'
4
+ import { Dialog as VanDialog } from 'vant'
5
+ import Upload from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
6
+
7
+ interface JsonRenderConfig {
8
+ data: Record<string, any>
9
+ content: Array<{
10
+ type: string
11
+ customFunctionForLabel: string
12
+ customFunctionForValue: string
13
+ jsonArrayDataIndex?: string
14
+ }>
15
+ title?: {
16
+ type: string
17
+ value: string
18
+ }
19
+ style?: Record<string, string>
20
+ }
21
+
22
+ // Props
23
+ const props = defineProps({
24
+ config: {
25
+ type: Object as () => JsonRenderConfig,
26
+ required: true,
27
+ },
28
+ displayOnly: {
29
+ type: Boolean,
30
+ default: false,
31
+ },
32
+ noPadding: {
33
+ type: Boolean,
34
+ default: false,
35
+ },
36
+ noTopBorder: {
37
+ type: Boolean,
38
+ default: false,
39
+ },
40
+ showTitle: {
41
+ type: Boolean,
42
+ default: true,
43
+ },
44
+ imgPrefix: {
45
+ type: String,
46
+ default: '',
47
+ },
48
+ serverName: {
49
+ type: String,
50
+ default: 'af-system',
51
+ },
52
+ })
53
+
54
+ // Emits
55
+ const emit = defineEmits<{
56
+ (e: 'updateImg', data: any): void
57
+ }>()
58
+
59
+ // 状态
60
+ const showImgModal = ref(false)
61
+ const showImageSrc = ref('')
62
+ const receivedFunction: Ref<Array<{
63
+ labelFunction: Function
64
+ valueFunction: Function
65
+ }>> = ref([])
66
+
67
+ // Methods
68
+ function checkImg(target: any[]) {
69
+ if (!target)
70
+ return []
71
+ target.forEach((obj) => {
72
+ if (obj.url === undefined)
73
+ obj.url = obj.path
74
+
75
+ if (obj.name === undefined) {
76
+ const withOutEndFix = obj.url.split('.')[0]
77
+ const temp = withOutEndFix.split('/')
78
+ obj.name = temp[temp.length - 1]
79
+ }
80
+ if (obj.status === undefined)
81
+ obj.status = 'done'
82
+ })
83
+ return target
84
+ }
85
+
86
+ function setImages(args: any[], item: any, config: any) {
87
+ // 如果基础上传组件在初始化完成后,就调用emit了setImage,此时图片并没有变化,直接返回
88
+ if (args[2] === 'created')
89
+ return
90
+
91
+ const result = {
92
+ name: item.f_project,
93
+ data: args[0],
94
+ orignalData: config,
95
+ }
96
+ emit('updateImg', result)
97
+ }
98
+
99
+ function determineCellStyle(labelFunctionReturn: any, color = '#000', borderWidth = '1px') {
100
+ if (labelFunctionReturn.style) {
101
+ // 如果声明了边框颜色
102
+ if (labelFunctionReturn.style.borderColor)
103
+ color = labelFunctionReturn.style.borderColor
104
+
105
+ // 如果声明了边框宽度
106
+ if (labelFunctionReturn.style.borderWidth)
107
+ borderWidth = labelFunctionReturn.style.borderWidth
108
+ }
109
+
110
+ // 正常边框单元格
111
+ const withBorder = {
112
+ border: `${borderWidth} solid ${color}`,
113
+ padding: '8px',
114
+ }
115
+
116
+ // 仅没有上边框单元格
117
+ const NoTopBorder = {
118
+ borderTopStyle: 'none',
119
+ borderLeft: `${borderWidth} solid ${color}`,
120
+ borderRight: `${borderWidth} solid ${color}`,
121
+ borderBottom: `${borderWidth} solid ${color}`,
122
+ padding: '8px',
123
+ }
124
+
125
+ let result = {}
126
+ // 判断表头是否有声明的样式
127
+ if (labelFunctionReturn.style !== undefined)
128
+ result = props.noTopBorder ? { ...NoTopBorder, ...labelFunctionReturn.style } : { ...withBorder, ...labelFunctionReturn.style }
129
+ else
130
+ result = props.noTopBorder ? { ...NoTopBorder } : { ...withBorder }
131
+
132
+ return result
133
+ }
134
+
135
+ function handleShowImgOk() {
136
+ showImgModal.value = false
137
+ showImageSrc.value = ''
138
+ }
139
+
140
+ function handleShowImgCancel() {
141
+ showImgModal.value = false
142
+ showImageSrc.value = ''
143
+ }
144
+
145
+ function openImgModal(img: string) {
146
+ showImageSrc.value = img
147
+ showImgModal.value = true
148
+ }
149
+
150
+ function formatImgName(imgSrc: string) {
151
+ return imgSrc.split('/').pop() || ''
152
+ }
153
+
154
+ // 生命周期
155
+ onBeforeMount(() => {
156
+ // 遍历配置,将所有JSON传递的方法保存到一个数组中,并用index来一一对应
157
+ for (let i = 0; i < props.config.content.length; i++) {
158
+ receivedFunction.value.push({
159
+ // eslint-disable-next-line no-eval
160
+ labelFunction: eval(`(${props.config.content[i].customFunctionForLabel})`),
161
+ // eslint-disable-next-line no-eval
162
+ valueFunction: eval(`(${props.config.content[i].customFunctionForValue})`),
163
+ })
164
+ }
165
+ })
166
+ </script>
167
+
168
+ <template>
169
+ <div :class="noPadding ? 'reportMainNoPadding' : 'reportMain'" id="xreportjsonrender">
170
+ <table class="reportTable" :style="config.style ? config.style : ''">
171
+ <tbody class="'reportTable'">
172
+ <!-- 标题 -->
173
+ <tr v-if="showTitle && config.title.type && config.title.type !== ''">
174
+ <td :class="noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'" colspan="12">
175
+ <template v-if="config.title.type === 'titleKey'">
176
+ {{ config.data[config.title.value] }}
177
+ </template>
178
+ <template v-else-if="config.title.type === 'titleValue'">
179
+ {{ config.title.value }}
180
+ </template>
181
+ </td>
182
+ </tr>
183
+ <template v-for="(row, rowIndex) in config.content">
184
+ <!-- 数据对象是一个Obj -->
185
+ <template v-if="row.type === 'jsonKey'">
186
+ <tr :key="rowIndex">
187
+ <!-- 表头 -->
188
+ <td
189
+ :class="noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'"
190
+ :style="determineCellStyle(receivedFunction[rowIndex].labelFunction(config, item))"
191
+ colspan="6"
192
+ >
193
+ <template v-if="receivedFunction[rowIndex].labelFunction(config).type === 'key'">
194
+ {{ config.data[receivedFunction[rowIndex].labelFunction(config).content] }}
195
+ </template>
196
+ <template v-else-if="receivedFunction[rowIndex].labelFunction(config).type === 'value'">
197
+ {{ receivedFunction[rowIndex].labelFunction(config).content }}
198
+ </template>
199
+ </td>
200
+ <!-- 内容 -->
201
+ <td
202
+ :class="noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'"
203
+ :style="determineCellStyle(receivedFunction[rowIndex].valueFunction(config))"
204
+ colspan="6"
205
+ >
206
+ <template v-if="displayOnly">
207
+ <template v-if="receivedFunction[rowIndex].valueFunction(config).type === 'key'">
208
+ {{ config.data[receivedFunction[rowIndex].valueFunction(config).content] }}
209
+ </template>
210
+ <template v-else-if="receivedFunction[rowIndex].valueFunction(config).type === 'value'">
211
+ {{ receivedFunction[rowIndex].valueFunction(config).content }}
212
+ </template>
213
+ </template>
214
+ <template v-else>
215
+ <template v-if="receivedFunction[rowIndex].valueFunction(config).originalKey">
216
+ <van-input v-model="config.data[receivedFunction[rowIndex].valueFunction(config).originalKey]" />
217
+ </template>
218
+ <template v-else>
219
+ <van-input v-model="config.data[receivedFunction[rowIndex].valueFunction(config).content]" />
220
+ </template>
221
+ </template>
222
+ <template v-if="receivedFunction[rowIndex].valueFunction(config).type === 'img'">
223
+ <template v-for="(img, imgIndex) in receivedFunction[rowIndex].valueFunction(config).content" :key="imgIndex">
224
+ <span class="imgText">
225
+ <van-icon type="link" />
226
+ <span @click="openImgModal(img)">{{ formatImgName(img) }}</span>
227
+ <br>
228
+ </span>
229
+ </template>
230
+ </template>
231
+ </td>
232
+ </tr>
233
+ </template>
234
+ <!-- 数据对象是一个Array -->
235
+ <template v-else-if="row.type === 'jsonArray'">
236
+ <tr v-for="(item, jsonArrayItemIndex) in config.data[row.jsonArrayDataIndex]" :key="`${rowIndex}${jsonArrayItemIndex}`">
237
+ <!-- 表头 -->
238
+ <td
239
+ :class="noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'"
240
+ :style="determineCellStyle(receivedFunction[rowIndex].labelFunction(config, item))"
241
+ colspan="6"
242
+ >
243
+ <template v-if="receivedFunction[rowIndex].labelFunction(config, item).type === 'key'">
244
+ {{ item[receivedFunction[rowIndex].labelFunction(config, item).content] }}
245
+ </template>
246
+ <template v-if="receivedFunction[rowIndex].labelFunction(config, item).type === 'value'">
247
+ {{ receivedFunction[rowIndex].labelFunction(config, item).content }}
248
+ </template>
249
+ </td>
250
+ <!-- 内容 -->
251
+ <td
252
+ :class="noTopBorder ? 'tdWithNoTopBorder' : 'tdWithBorder'"
253
+ :style="determineCellStyle(receivedFunction[rowIndex].valueFunction(config, item))"
254
+ colspan="6"
255
+ >
256
+ <template v-if="displayOnly">
257
+ <template v-if="receivedFunction[rowIndex].valueFunction(config, item).type === 'key'">
258
+ {{ item[receivedFunction[rowIndex].valueFunction(config, item).content] }}
259
+ </template>
260
+ <template v-if="receivedFunction[rowIndex].valueFunction(config, item).type === 'value'">
261
+ {{ receivedFunction[rowIndex].valueFunction(config, item).content }}
262
+ </template>
263
+ <template v-if="receivedFunction[rowIndex].valueFunction(config, item).type === 'imgs'">
264
+ <template v-if="!item.imgs || item.imgs.length === 0">
265
+ <p style="margin: auto">
266
+
267
+ </p>
268
+ </template>
269
+ <template v-else>
270
+ <template v-for="(img, imgIndex) in item.imgs" :key="imgIndex">
271
+ <div>
272
+ <img :src="img.path" style="max-width: 200px; max-height: 200px">
273
+ <p style="margin: auto">
274
+ {{ img.path.substring(img.path.lastIndexOf('/') + 1, img.path.lastIndexOf('.')) }}
275
+ </p>
276
+ </div>
277
+ </template>
278
+ </template>
279
+ </template>
280
+ </template>
281
+ <template v-else>
282
+ <template v-if="receivedFunction[rowIndex].valueFunction(config, item).originalKey">
283
+ <template v-if="receivedFunction[rowIndex].valueFunction(config, item).type === 'imgs'">
284
+ <Upload
285
+ :model="{
286
+ type: 'image',
287
+ accept: ['*'],
288
+ resUploadStock: 1,
289
+ pathKey: 'cs',
290
+ }"
291
+ :outer-container-index="1"
292
+ :img-prefix="imgPrefix"
293
+ :service-name="serverName"
294
+ :images="checkImg(item.imgs)"
295
+ upload-style="simple"
296
+ @set-files="(...args) => { setImages(args, item, config.data) }"
297
+ />
298
+ </template>
299
+ <template v-else>
300
+ <van-input v-model="item[receivedFunction[rowIndex].valueFunction(config, item).originalKey]" />
301
+ </template>
302
+ </template>
303
+ <template v-else>
304
+ <van-input v-model="item[receivedFunction[rowIndex].valueFunction(config, item).content]" />
305
+ </template>
306
+ </template>
307
+ </td>
308
+ </tr>
309
+ </template>
310
+ </template>
311
+ </tbody>
312
+ </table>
313
+ <!-- 图片展示弹框 -->
314
+ <VanDialog
315
+ v-model:show="showImgModal"
316
+ title="图片"
317
+ width="80%"
318
+ :z-index="1001"
319
+ @confirm="handleShowImgOk"
320
+ @cancel="handleShowImgCancel"
321
+ >
322
+ <div style="width: 100%;display: flex;justify-content: center;align-items: center">
323
+ <img :src="showImageSrc" alt="图片">
324
+ </div>
325
+ </VanDialog>
326
+ </div>
327
+ </template>
328
+
329
+ <style scoped lang="less">
330
+ .imgSrc {
331
+ color: rgb( 24,144,255 );
332
+ font-size: 0.9em;
333
+ margin: auto;
334
+ }
335
+ .imgSrc:hover {
336
+ color: rgba(24, 144, 255, 0.8);
337
+ font-size: 0.9em;
338
+ cursor: pointer;
339
+ }
340
+ .reportMain {
341
+ text-align: center;
342
+ margin: 0 auto;
343
+ font-size: 16px;
344
+ color: #000;
345
+ background-color: #fff;
346
+ border-radius: 8px;
347
+ }
348
+
349
+ .reportMainNoPadding {
350
+ text-align: center;
351
+ margin: 0 auto;
352
+ font-size: 16px;
353
+ color: #000;
354
+ background-color: #fff;
355
+ border-radius: 8px;
356
+ }
357
+
358
+ .reportTitle {
359
+ font-weight: bold;
360
+ }
361
+
362
+ .reportTable {
363
+ width: 100%;
364
+ border-collapse: collapse;
365
+ table-layout: fixed;
366
+ word-break: break-all;
367
+ }
368
+
369
+ .tdWithBorder {
370
+ border: 1px solid #000;
371
+ padding: 8px;
372
+ }
373
+
374
+ .imgText:hover {
375
+ color: rgb(24, 144, 255);
376
+ cursor: pointer;
377
+ }
378
+
379
+ .tdWithNoTopBorder {
380
+ border-top-style: none;
381
+ border-left: 1px solid #000;
382
+ border-right: 1px solid #000;
383
+ border-bottom: 1px solid #000;
384
+ padding: 8px;
385
+ }
386
+ </style>