@epxing/business 5.3.0-beta.2 → 5.3.0-beta.4
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/API.md +115 -111
- package/README.md +44 -44
- package/dist/src/base/AiSkillEditor.js +1 -1
- package/dist/src/base/AiSkillEditor.vue.js +2 -0
- package/dist/src/base/AppConfigFormItem.js +1 -3
- package/dist/src/base/AppConfigFormItem.vue.js +210 -85
- package/dist/src/base/CommonFieldList.js +1 -1
- package/dist/src/base/CommonFieldList.vue.js +2 -1
- package/dist/src/base/ConfigModuleIndex.js +38 -1
- package/dist/src/base/ManageAppNav.js +1 -1
- package/dist/src/base/ManageMenu.js +1 -1
- package/dist/src/base/RoleBindTrace.js +253 -0
- package/dist/src/base/RoleGroupManage.js +1037 -0
- package/dist/src/base/ServiceMenu.js +7 -6
- package/dist/src/components/AiList.js +1278 -3
- package/dist/src/components/EntityCheckboxFind.vue.js +14 -10
- package/dist/src/components/EntityRightFormItem.js +1 -5
- package/dist/src/components/EntityRightFormItem.vue.js +3 -1
- package/dist/src/components/EntitySystemEr.js +492 -0
- package/dist/src/components/HallNav.vue.js +7 -36
- package/dist/src/components/IconFontLibrary.js +22 -1
- package/dist/src/components/IconFontList.js +21 -1
- package/dist/src/components/PrintFormList.js +2 -1
- package/dist/src/components/PrintFormList.vue.js +3 -1
- package/dist/src/components/WikiWorkbench.js +153 -129
- package/dist/src/components/authorization/AuthorizationInterface.js +3 -1
- package/dist/src/components/custom-bpmn/PropertiesView.js +1991 -1942
- package/dist/src/components/icon-gallery/IconGallery.js +193 -0
- package/dist/src/components/icon-gallery/mixin.js +150 -0
- package/dist/src/components/wiki-workbench/WikiIntake.js +86 -93
- package/dist/src/components/wiki-workbench/WikiIntake.vue.js +153 -73
- package/dist/src/index.js +26 -20
- package/dist/src/public-components.js +16 -14
- package/dist/src/route-components.js +5 -5
- package/dist/src/system.component.index.js +1 -1
- package/dist/src/system.component.js +8 -3
- package/dist/src/system.component.lazy.js +1 -1
- package/dist/src/views/Add.js +1 -1
- package/dist/src/views/Add.vue.js +8 -3
- package/dist/src/views/AiToolManager.js +792 -317
- package/dist/src/views/App.js +3 -45
- package/dist/src/views/AppRoleSelect.js +3 -230
- package/dist/src/views/Error.js +3 -207
- package/dist/src/views/ExcelDesign.js +326 -316
- package/dist/src/views/JvmMemoryMonitor.js +463 -0
- package/dist/src/views/Module.js +3 -170
- package/dist/src/views/WikiBinding.js +88 -25
- package/dist/style.css +2867 -1487
- package/package.json +12 -6
- package/src/base/AiSkillEditor.vue +2 -0
- package/src/base/AppConfigFormItem.vue +211 -145
- package/src/base/CommonFieldList.vue +9 -6
- package/src/base/ConfigModuleIndex.vue +37 -1
- package/src/base/ManageAppNav.vue +1188 -1188
- package/src/base/ManageMenu.vue +933 -933
- package/src/base/RoleBindTrace.vue +364 -0
- package/src/base/RoleGroupManage.vue +1160 -0
- package/src/base/ServiceMenu.vue +6 -5
- package/src/components/AiList.vue +439 -113
- package/src/components/EntityCheckboxFind.vue +12 -8
- package/src/components/EntityRightFormItem.vue +9 -10
- package/src/components/EntitySystemEr.vue +517 -0
- package/src/components/HallNav.vue +6 -33
- package/src/components/IconFontLibrary.vue +27 -60
- package/src/components/IconFontList.vue +13 -64
- package/src/components/PrintFormList.vue +33 -27
- package/src/components/WikiWorkbench.vue +90 -60
- package/src/components/authorization/AuthorizationInterface.vue +2 -0
- package/src/components/custom-bpmn/CustomPalette.js +1 -1
- package/src/components/custom-bpmn/CustomRenderer.js +1 -1
- package/src/components/custom-bpmn/PropertiesView.vue +35 -4
- package/src/components/custom-bpmn/index.js +1 -1
- package/src/components/icon-gallery/IconGallery.vue +130 -0
- package/src/components/icon-gallery/mixin.jsx +109 -0
- package/src/components/wiki-workbench/WikiIntake.vue +178 -104
- package/src/index.js +24 -20
- package/src/public-components.js +1 -0
- package/src/route-components.js +4 -4
- package/src/system.component.index.js +1 -1
- package/src/views/Add.vue +8 -5
- package/src/views/AiToolManager.vue +326 -4
- package/src/views/App.vue +4 -53
- package/src/views/AppRoleSelect.vue +4 -334
- package/src/views/Error.vue +4 -63
- package/src/views/ExcelDesign.vue +24 -7
- package/src/views/JvmMemoryMonitor.vue +284 -0
- package/src/views/Module.vue +4 -210
- package/src/views/WikiBinding.vue +42 -0
- package/types/app.d.ts +1 -0
- package/types/dept-find.d.ts +1 -1
- package/types/index.d.ts +15 -14
- package/types/popup.d.ts +2 -2
- package/types/route-components.d.ts +1 -1
- package/types/user-find.d.ts +1 -1
- package/dist/assets/role_select-DTqRlFNz.webp +0 -0
- package/dist/src/components/AiList.vue.js +0 -93
- package/dist/src/components/IconFontLibrary.vue.js +0 -67
- package/dist/src/components/IconFontList.vue.js +0 -79
|
@@ -125,6 +125,17 @@
|
|
|
125
125
|
</epx-table-form-item>
|
|
126
126
|
</div>
|
|
127
127
|
</li>
|
|
128
|
+
<li class="attribute-item">
|
|
129
|
+
<div class="bpmn-node-properties__attribute-input">
|
|
130
|
+
<label class="bpmn-node-properties__attribute-input__label">申请查看页面参数</label>
|
|
131
|
+
<epx-visual-config-params
|
|
132
|
+
:value="elementValues['camunda:applyViewPageParams']"
|
|
133
|
+
:treeFieldStore="treeFieldStore"
|
|
134
|
+
:showParamsType="['str', 'field']"
|
|
135
|
+
@change-configs="v=> (elementValues['camunda:applyViewPageParams'] = v)"
|
|
136
|
+
></epx-visual-config-params>
|
|
137
|
+
</div>
|
|
138
|
+
</li>
|
|
128
139
|
<li class="attribute-item">
|
|
129
140
|
<div class="bpmn-node-properties__attribute-input">
|
|
130
141
|
<label class="bpmn-node-properties__attribute-input__label">办理页面</label>
|
|
@@ -2960,13 +2971,13 @@
|
|
|
2960
2971
|
<div class="bpmn-node-properties__attribute-input-type">
|
|
2961
2972
|
<el-select v-model="revertScopeType" placeholder="请选择" @change="v=> {
|
|
2962
2973
|
elementValues['camunda:revertScopeType']=v
|
|
2963
|
-
if(v==='1'){
|
|
2964
2974
|
this.revertScope =''
|
|
2975
|
+
this.revertScopeList =[]
|
|
2965
2976
|
elementValues['camunda:revertScope']=''
|
|
2966
|
-
}
|
|
2967
2977
|
}" >
|
|
2968
2978
|
<el-option label="上个节点" value="1"></el-option>
|
|
2969
2979
|
<el-option label="指定节点" value="2"></el-option>
|
|
2980
|
+
<el-option label="办理人自选" value="3"></el-option>
|
|
2970
2981
|
</el-select>
|
|
2971
2982
|
</div>
|
|
2972
2983
|
<div v-if="revertScopeType==='2'" class="bpmn-node-properties__attribute-input-type">
|
|
@@ -2989,6 +3000,21 @@
|
|
|
2989
3000
|
</el-option>
|
|
2990
3001
|
</el-select>
|
|
2991
3002
|
</div>
|
|
3003
|
+
<div v-if="revertScopeType==='3'" class="bpmn-node-properties__attribute-input-type">
|
|
3004
|
+
<el-select style="width:220px" multiple collapse-tags v-model="revertScopeList" placeholder="不限(所有已审节点)" @change="v=> {
|
|
3005
|
+
elementValues['camunda:revertScope']=(v || []).join(',')
|
|
3006
|
+
}"
|
|
3007
|
+
clearable
|
|
3008
|
+
>
|
|
3009
|
+
<el-option
|
|
3010
|
+
v-for="item in revertNodeParamList"
|
|
3011
|
+
:key="item.code"
|
|
3012
|
+
:label="item.name"
|
|
3013
|
+
:value="item.code"
|
|
3014
|
+
>
|
|
3015
|
+
</el-option>
|
|
3016
|
+
</el-select>
|
|
3017
|
+
</div>
|
|
2992
3018
|
</div>
|
|
2993
3019
|
</li>
|
|
2994
3020
|
<li class="attribute-item">
|
|
@@ -3947,6 +3973,8 @@ export default {
|
|
|
3947
3973
|
selectOperate: {},
|
|
3948
3974
|
revertScopeType: '',
|
|
3949
3975
|
revertScope: '',
|
|
3976
|
+
// 办理人自选退回时的候选节点白名单,与 revertScope 逗号串互转
|
|
3977
|
+
revertScopeList: [],
|
|
3950
3978
|
revertNodeParamList: [],
|
|
3951
3979
|
linkEntityList: [],
|
|
3952
3980
|
editFieldScopeDialog: false,
|
|
@@ -4418,6 +4446,7 @@ export default {
|
|
|
4418
4446
|
'camunda:repealStatus': $attrs['camunda:repealStatus'],
|
|
4419
4447
|
'camunda:repealDeleteProcessData': $attrs['camunda:repealDeleteProcessData'] || '0',
|
|
4420
4448
|
'camunda:applyViewPage': $attrs['camunda:applyViewPage'],
|
|
4449
|
+
'camunda:applyViewPageParams': $attrs['camunda:applyViewPageParams'] ? JSON.parse($attrs['camunda:applyViewPageParams']) : {},
|
|
4421
4450
|
'camunda:assigneeFinishShowStyle': $attrs['camunda:assigneeFinishShowStyle'] || 'default',
|
|
4422
4451
|
'camunda:repealStatus#': $attrs['camunda:repealStatus#'],
|
|
4423
4452
|
'camunda:applyViewPage-name': $attrs['camunda:applyViewPage-name'],
|
|
@@ -4467,7 +4496,7 @@ export default {
|
|
|
4467
4496
|
}
|
|
4468
4497
|
if (key.includes('.i18n') && v[key]) {
|
|
4469
4498
|
params[key] = JSON.stringify(v[key])
|
|
4470
|
-
} else if (key === 'camunda:assigneePageParams' && v[key]) {
|
|
4499
|
+
} else if ((key === 'camunda:assigneePageParams' || key === 'camunda:applyViewPageParams') && v[key]) {
|
|
4471
4500
|
params[key] = JSON.stringify(v[key])
|
|
4472
4501
|
}
|
|
4473
4502
|
if (this.element.type === 'bpmn:SequenceFlow' && key === 'camunda:conditionRule') {
|
|
@@ -6465,6 +6494,8 @@ export default {
|
|
|
6465
6494
|
this.revertScopeType = revertScopeType
|
|
6466
6495
|
const { 'camunda:revertScope': revertScope = '' } = this.elementValues
|
|
6467
6496
|
this.revertScope = revertScope
|
|
6497
|
+
// 自选退回的候选白名单以逗号串存储,回显时拆成数组供多选控件使用
|
|
6498
|
+
this.revertScopeList = revertScope ? revertScope.split(',') : []
|
|
6468
6499
|
} else if (this.element.type.includes('Flow')) {
|
|
6469
6500
|
const { 'camunda:flowOperate': flowOperate = '' } = this.elementValues
|
|
6470
6501
|
this.flowOperate = flowOperate
|
|
@@ -7039,7 +7070,7 @@ export default {
|
|
|
7039
7070
|
<style lang="scss">
|
|
7040
7071
|
.bpmn-node-properties__attribute-list{
|
|
7041
7072
|
padding: 0 16px;
|
|
7042
|
-
// &::v-deep{
|
|
7073
|
+
// &::v-deep {
|
|
7043
7074
|
// EP 的输入框盒子是 .el-input__wrapper,.el-input__inner 只是里面的裸 <input>
|
|
7044
7075
|
// (element-ui 时代反过来)。高度打在 __inner 上 → 实际框高 = 值 + wrapper 上下各 1px,
|
|
7045
7076
|
// 且 --el-input-height 仍停在默认 32px,__prefix/__suffix/清除按钮的行高都按它算。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { default } from '@epxing/components/src/progress-chart/vendor/custom-bpmn/index'
|
|
1
|
+
export { default } from '@epxing/components/src/progress-chart/vendor/custom-bpmn/index'
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="epx-remix-gallery">
|
|
3
|
+
<aside class="epx-remix-gallery__nav" aria-label="图标分类">
|
|
4
|
+
<h3>图标分类</h3>
|
|
5
|
+
<el-input v-model="categoryKeyword" placeholder="搜索分类" clearable aria-label="搜索分类" />
|
|
6
|
+
<button type="button" :class="{ active: !category }" @click="category = ''">全部分类</button>
|
|
7
|
+
<button v-for="item in navigation" :key="item.code" type="button" :class="{ active: category === item.code }" @click="category = item.code">{{ item.name }}</button>
|
|
8
|
+
</aside>
|
|
9
|
+
<main class="epx-remix-gallery__main">
|
|
10
|
+
<header class="epx-remix-gallery__header">
|
|
11
|
+
<div><h2>Remix Icon</h2><span>{{ loading ? '正在加载图标…' : `${filteredIcons.length} 个图标 · ${actionLabel}` }}</span></div>
|
|
12
|
+
<el-input v-model="keyword" placeholder="搜索名称、编号或关键词" clearable aria-label="搜索图标" />
|
|
13
|
+
</header>
|
|
14
|
+
<div v-if="error" class="epx-remix-gallery__state" role="alert"><p>{{ error }}</p><el-button @click="$emit('reload')">重新加载</el-button></div>
|
|
15
|
+
<div v-else-if="loading" class="epx-remix-gallery__state" role="status">正在加载完整图标库…</div>
|
|
16
|
+
<div v-else ref="content" class="epx-remix-gallery__content">
|
|
17
|
+
<div v-if="!groups.length" class="epx-remix-gallery__state">未找到匹配的图标,请更换分类或关键词</div>
|
|
18
|
+
<section v-for="group in groups" :key="group.code" class="epx-remix-gallery__section" :aria-label="group.name">
|
|
19
|
+
<h3>{{ group.name }} <span>{{ group.icons.length }}</span></h3>
|
|
20
|
+
<div class="epx-remix-gallery__grid">
|
|
21
|
+
<button v-for="icon in group.icons" :key="icon.CODE" type="button" class="epx-remix-gallery__icon" :class="{ selected: selectedCodes.includes(icon.CODE) }" :title="icon.CODE" :aria-label="`${actionLabel} ${icon.CODE}`" :aria-pressed="selectedCodes.includes(icon.CODE)" @click="$emit('select', icon)">
|
|
22
|
+
<i :class="icon.CODE" aria-hidden="true"></i><span>{{ icon.NAME || icon.CODE }}</span>
|
|
23
|
+
</button>
|
|
24
|
+
</div>
|
|
25
|
+
</section>
|
|
26
|
+
</div>
|
|
27
|
+
<footer v-if="$slots.footer" class="epx-remix-gallery__footer"><slot name="footer"></slot></footer>
|
|
28
|
+
</main>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script>
|
|
33
|
+
import { ensureIcons } from '@epxing/icons/src/runtime.mjs'
|
|
34
|
+
|
|
35
|
+
export default {
|
|
36
|
+
name: 'epx-remix-gallery',
|
|
37
|
+
props: {
|
|
38
|
+
icons: { type: Array, default: () => [] },
|
|
39
|
+
categories: { type: Array, default: () => [] },
|
|
40
|
+
selectedCodes: { type: Array, default: () => [] },
|
|
41
|
+
loading: Boolean,
|
|
42
|
+
error: { type: String, default: '' },
|
|
43
|
+
actionLabel: { type: String, default: '点击复制编号' }
|
|
44
|
+
},
|
|
45
|
+
emits: ['select', 'reload'],
|
|
46
|
+
data () {
|
|
47
|
+
return { keyword: '', category: '', categoryKeyword: '' }
|
|
48
|
+
},
|
|
49
|
+
computed: {
|
|
50
|
+
remixIcons () {
|
|
51
|
+
return this.icons.filter(icon => icon.CODE && icon.CODE.startsWith('ri-'))
|
|
52
|
+
},
|
|
53
|
+
categoryNames () {
|
|
54
|
+
return Object.fromEntries(this.categories.map(item => [item.code, item.name.replace(/^Remix\s*·\s*/, '')]))
|
|
55
|
+
},
|
|
56
|
+
navigation () {
|
|
57
|
+
const keyword = this.categoryKeyword.trim().toLowerCase()
|
|
58
|
+
return this.categories.map(item => ({ code: item.code, name: this.categoryNames[item.code] }))
|
|
59
|
+
.filter(item => `${item.code} ${item.name}`.toLowerCase().includes(keyword))
|
|
60
|
+
},
|
|
61
|
+
filteredIcons () {
|
|
62
|
+
const words = this.keyword.trim().toLowerCase().split(/\s+/).filter(Boolean)
|
|
63
|
+
return this.remixIcons.filter(icon => {
|
|
64
|
+
if (this.category && icon.TYPE !== this.category) return false
|
|
65
|
+
const text = `${icon.CODE} ${icon.NAME || ''} ${icon.KEY_WORDS || ''} ${this.categoryNames[icon.TYPE] || ''}`.toLowerCase()
|
|
66
|
+
return words.every(word => text.includes(word))
|
|
67
|
+
})
|
|
68
|
+
},
|
|
69
|
+
groups () {
|
|
70
|
+
const groups = new Map(this.categories.map(item => [item.code, { code: item.code, name: this.categoryNames[item.code], icons: [] }]))
|
|
71
|
+
this.filteredIcons.forEach(icon => {
|
|
72
|
+
const code = icon.TYPE || 'ri_others'
|
|
73
|
+
if (!groups.has(code)) groups.set(code, { code, name: '其他', icons: [] })
|
|
74
|
+
groups.get(code).icons.push(icon)
|
|
75
|
+
})
|
|
76
|
+
return [...groups.values()].filter(group => group.icons.length)
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
watch: {
|
|
80
|
+
icons: {
|
|
81
|
+
immediate: true,
|
|
82
|
+
handler (icons) {
|
|
83
|
+
// 批量补齐动态图标,避免为数千个卡片各建一个加载组件。
|
|
84
|
+
ensureIcons(icons.filter(icon => icon.CODE && icon.CODE.startsWith('ri-')).map(icon => icon.CODE))
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
keyword: 'resetScroll',
|
|
88
|
+
category: 'resetScroll'
|
|
89
|
+
},
|
|
90
|
+
methods: {
|
|
91
|
+
resetScroll () {
|
|
92
|
+
if (this.$refs.content) this.$refs.content.scrollTop = 0
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<style scoped>
|
|
99
|
+
.epx-remix-gallery { display: flex; box-sizing: border-box; width: 100%; height: 100%; min-height: 0; max-height: calc(100vh - 120px); overflow: hidden; color: var(--el-text-color-primary, #202124); background: var(--el-bg-color, #fff); border: 1px solid var(--el-border-color-light, #e5e7eb); border-radius: 6px; }
|
|
100
|
+
/* 选择弹窗默认距顶部 15vh,预留上下留白及标题、页面容器的空间。 */
|
|
101
|
+
.epx-remix-gallery--selectable { height: min(600px, calc(70vh - 140px)); }
|
|
102
|
+
.epx-remix-gallery__nav { flex: 0 0 180px; min-height: 0; padding: 20px 12px; overflow-y: auto; background: var(--el-fill-color-light, #f7f8fa); border-right: 1px solid var(--el-border-color-light, #e5e7eb); }
|
|
103
|
+
.epx-remix-gallery h3 { margin: 0 0 16px; font-size: 15px; }
|
|
104
|
+
.epx-remix-gallery__nav .el-input { margin-bottom: 12px; }
|
|
105
|
+
.epx-remix-gallery__nav button { display: block; width: 100%; padding: 10px 12px; margin-bottom: 3px; border: 0; border-radius: 6px; color: inherit; background: transparent; text-align: left; cursor: pointer; }
|
|
106
|
+
.epx-remix-gallery__nav button:hover, .epx-remix-gallery__nav button.active { color: var(--el-color-primary, #4080ff); background: var(--el-color-primary-light-9, #eef4ff); }
|
|
107
|
+
.epx-remix-gallery__main { display: flex; flex: 1; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }
|
|
108
|
+
.epx-remix-gallery__header { display: flex; flex-shrink: 0; align-items: center; justify-content: space-between; gap: 24px; padding: 20px 24px; border-bottom: 1px solid var(--el-border-color-light, #e5e7eb); }
|
|
109
|
+
.epx-remix-gallery__header h2 { margin: 0 0 6px; font-size: 22px; font-weight: 600; }
|
|
110
|
+
.epx-remix-gallery__header span, .epx-remix-gallery__section h3 span { color: var(--el-text-color-secondary, #8b8f98); font-size: 12px; font-weight: normal; }
|
|
111
|
+
.epx-remix-gallery__header .el-input { width: 320px; max-width: 50%; }
|
|
112
|
+
.epx-remix-gallery__content { flex: 1; min-height: 0; padding: 24px; overflow-y: auto; }
|
|
113
|
+
.epx-remix-gallery__section { margin-bottom: 32px; content-visibility: auto; contain-intrinsic-size: auto 500px; }
|
|
114
|
+
.epx-remix-gallery__section h3 span { margin-left: 8px; }
|
|
115
|
+
.epx-remix-gallery__grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; }
|
|
116
|
+
.epx-remix-gallery__icon { display: flex; min-width: 0; height: 104px; align-items: center; justify-content: center; flex-direction: column; gap: 14px; padding: 12px 6px; border: 1px solid transparent; border-radius: 6px; color: inherit; background: transparent; cursor: pointer; }
|
|
117
|
+
.epx-remix-gallery__icon i { font-size: 28px; line-height: 1; }
|
|
118
|
+
.epx-remix-gallery__icon span { width: 100%; overflow: hidden; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
|
|
119
|
+
.epx-remix-gallery__icon:hover, .epx-remix-gallery__icon.selected { color: var(--el-color-primary, #4080ff); background: var(--el-fill-color-light, #f7f8fa); border-color: var(--el-color-primary-light-7, #c9dcff); }
|
|
120
|
+
.epx-remix-gallery button:focus-visible { outline: 2px solid var(--el-color-primary, #4080ff); outline-offset: -2px; }
|
|
121
|
+
.epx-remix-gallery__state { flex: 1; padding: 60px 24px; text-align: center; color: var(--el-text-color-secondary, #8b8f98); }
|
|
122
|
+
.epx-remix-gallery__footer { flex-shrink: 0; padding: 12px 20px; text-align: right; border-top: 1px solid var(--el-border-color-light, #e5e7eb); }
|
|
123
|
+
@media (max-width: 640px) {
|
|
124
|
+
.epx-remix-gallery__nav { flex-basis: 112px; padding: 12px 6px; }
|
|
125
|
+
.epx-remix-gallery__header { flex-direction: column; align-items: stretch; gap: 12px; padding: 16px; }
|
|
126
|
+
.epx-remix-gallery__header .el-input { width: 100%; max-width: none; }
|
|
127
|
+
.epx-remix-gallery__content { padding: 16px; }
|
|
128
|
+
.epx-remix-gallery__grid { grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); }
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import IconGallery from './IconGallery.vue'
|
|
2
|
+
|
|
3
|
+
// 分页读完当前范围;校验完整性,不能把固定条数上限当作完整图标库。
|
|
4
|
+
export async function loadAllIcons (http, params, isCurrent = () => true) {
|
|
5
|
+
const icons = []
|
|
6
|
+
const codes = new Set()
|
|
7
|
+
let total = 0
|
|
8
|
+
for (let page = 1; page === 1 || icons.length < total; page++) {
|
|
9
|
+
const result = await http.list({ ...params, page, limit: 500, order_field: 'CODE', order_mode: 'asc' })
|
|
10
|
+
if (!isCurrent()) return null
|
|
11
|
+
total = Number(result.total)
|
|
12
|
+
const batch = result.entitys || []
|
|
13
|
+
if (!Number.isFinite(total) || total < 0 || (!batch.length && icons.length < total)) throw new Error('图标数据未加载完整,请重新加载')
|
|
14
|
+
for (const icon of batch) {
|
|
15
|
+
if (!icon.CODE || codes.has(icon.CODE)) throw new Error('图标分页数据重复,请重新加载')
|
|
16
|
+
codes.add(icon.CODE)
|
|
17
|
+
icons.push(icon)
|
|
18
|
+
}
|
|
19
|
+
if (icons.length > total) throw new Error('图标数据发生变化,请重新加载')
|
|
20
|
+
}
|
|
21
|
+
return icons.filter(icon => icon.CODE.startsWith('ri-'))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export default {
|
|
25
|
+
components: { IconGallery },
|
|
26
|
+
data () {
|
|
27
|
+
return {
|
|
28
|
+
galleryCategories: [],
|
|
29
|
+
galleryError: '',
|
|
30
|
+
// 请求代次阻止已取消或已卸载组件的旧结果覆盖当前数据。
|
|
31
|
+
galleryRequest: 0
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
beforeUnmount () {
|
|
35
|
+
this.galleryRequest++
|
|
36
|
+
},
|
|
37
|
+
methods: {
|
|
38
|
+
initComponent () {
|
|
39
|
+
if (!this.showFlag) return
|
|
40
|
+
// 图标墙使用同一套字段权限与取数流程,不走父类的移动端列表分流。
|
|
41
|
+
this.listType = this.$configs.type
|
|
42
|
+
this.getDefaultOperates()
|
|
43
|
+
this.getFields()
|
|
44
|
+
},
|
|
45
|
+
// 分类与搜索由图标墙统一呈现,不再加载父类的分类树。
|
|
46
|
+
getCategoryMeta () {},
|
|
47
|
+
getCategoryTreeData () {},
|
|
48
|
+
async getData (current, cb) {
|
|
49
|
+
if (!this.$metaId) return
|
|
50
|
+
const request = ++this.galleryRequest
|
|
51
|
+
const isCurrent = () => request === this.galleryRequest
|
|
52
|
+
this.cancelGetData = () => { this.galleryRequest++ }
|
|
53
|
+
this.loading = true
|
|
54
|
+
this.galleryError = ''
|
|
55
|
+
try {
|
|
56
|
+
const scope = JSON.parse(this.params.scopeParams || '[]').map(item => ({ ...item }))
|
|
57
|
+
if (scope.length) {
|
|
58
|
+
scope[0].lb = '(' + (scope[0].lb || '')
|
|
59
|
+
scope[scope.length - 1].rb = (scope[scope.length - 1].rb || '') + ')'
|
|
60
|
+
scope[scope.length - 1].link = 'and'
|
|
61
|
+
}
|
|
62
|
+
scope.push({ field: 'CODE', mode: 'like', values: 'ri-%', link: 'and' })
|
|
63
|
+
const field = this.$meta.getAllFieldConfigs().find(item => item.attriName === 'TYPE')
|
|
64
|
+
const [categories, icons] = await Promise.all([
|
|
65
|
+
this.$http.getCodes({ key: (field && field.codeKey) || 'ICON_TYPE' }),
|
|
66
|
+
loadAllIcons(this.$http, {
|
|
67
|
+
...this.params,
|
|
68
|
+
entityId: this.$metaId,
|
|
69
|
+
scopeParams: JSON.stringify(scope),
|
|
70
|
+
columnFields: ['CODE', 'NAME', 'TYPE', 'KEY_WORDS'].map(attriName => ({ attriName }))
|
|
71
|
+
}, isCurrent)
|
|
72
|
+
])
|
|
73
|
+
if (!isCurrent()) return
|
|
74
|
+
this.galleryCategories = (categories || []).filter(item => item.code && item.code.startsWith('ri_'))
|
|
75
|
+
this.data = icons
|
|
76
|
+
this.total = icons.length
|
|
77
|
+
this.initData = true
|
|
78
|
+
this.getAllDataMap(icons)
|
|
79
|
+
if (this.afterData) this.afterData(icons)
|
|
80
|
+
if (cb) cb(icons)
|
|
81
|
+
if (this.$component) {
|
|
82
|
+
const result = { id: this.$component.id, total: this.total, entitys: icons }
|
|
83
|
+
this.$dispatchPage('listData', [result])
|
|
84
|
+
this.$emit('listData', result)
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if (!isCurrent()) return
|
|
88
|
+
this.galleryError = (err && (err.msg || err.message)) || '图标库加载失败,请重新加载'
|
|
89
|
+
this.$message.error(this.galleryError)
|
|
90
|
+
} finally {
|
|
91
|
+
if (isCurrent()) this.loading = false
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
renderGallery (selectable = false) {
|
|
95
|
+
return (
|
|
96
|
+
<IconGallery class={{ 'epx-remix-gallery--selectable': selectable }} icons={this.data} categories={this.galleryCategories} selectedCodes={selectable ? this.selectionIds : []} style={this.showFlag === false ? { display: 'none' } : {}}
|
|
97
|
+
loading={!this.initData || this.loading} error={this.galleryError} actionLabel={selectable ? '点击选择图标' : '点击复制编号'}
|
|
98
|
+
onSelect={this.chooseIcon} onReload={() => this.getData()} v-slots={selectable && this.mode === 'confirm' ? {
|
|
99
|
+
footer: () => (
|
|
100
|
+
<div>
|
|
101
|
+
<el-button onClick={this.cancel}>取消</el-button>
|
|
102
|
+
<el-button type="primary" onClick={this.confirm}>确定</el-button>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
} : {}} />
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|