@ebiz/designer-components 0.1.111 → 0.1.113
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/dist/designer-components.css +1 -1
- package/dist/index.mjs +11235 -11188
- package/package.json +1 -1
- package/src/components/EbizApprovalDetail.vue +41 -8
- package/src/components/EbizApprovalForm.vue +2 -2
- package/src/components/EbizTreeSelector.vue +25 -9
- package/src/components/senior/EbizApprovalList/ApprovalList.vue +127 -0
- package/src/components/senior/EbizSForm/item.vue +14 -1
package/package.json
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class='ebiz-approval-container'>
|
|
3
3
|
<div class='detail-container'>
|
|
4
|
-
<div class="title">{{ approvalDetail.variables?.startUserName + '的' + approvalDetail.processDefinitionName }}
|
|
4
|
+
<div class="title">{{ approvalDetail.variables?.startUserName + '的' + approvalDetail.processDefinitionName }}
|
|
5
|
+
<ebiz-tag
|
|
6
|
+
variant="light"
|
|
7
|
+
size="medium"
|
|
8
|
+
class="component-base-style"
|
|
9
|
+
:theme="themeMap[approvalDetail?.state]"
|
|
10
|
+
:content="approvalDetail.stateDesc || '-'"
|
|
11
|
+
></ebiz-tag>
|
|
12
|
+
</div>
|
|
5
13
|
<!-- 区块详情 -->
|
|
6
14
|
<div class="block-detail">
|
|
7
15
|
<slot name="block"></slot>
|
|
16
|
+
<ebiz-s-approval-process ref="approvalprocessRef" :businessKey="businessKey" :type="type"></ebiz-s-approval-process>
|
|
8
17
|
</div>
|
|
9
18
|
<!-- 审批区域 -->
|
|
10
19
|
<div class="approval-area">
|
|
11
|
-
<ebiz-s-approval-process ref="approvalprocessRef" :businessKey="businessKey"
|
|
12
|
-
:type="type"></ebiz-s-approval-process>
|
|
13
|
-
|
|
14
20
|
<ebiz-approval-form v-if="isAssignee" :taskId="currTask.id" :businessKey="businessKey"
|
|
15
21
|
:taskDefinitionKey="currTask.taskDefinitionKey" :approvalDetail="approvalDetail" @pass="refresh"
|
|
16
22
|
@reject="refresh" @refresh="refresh"></ebiz-approval-form>
|
|
@@ -22,7 +28,7 @@
|
|
|
22
28
|
<script lang='ts' setup>
|
|
23
29
|
|
|
24
30
|
import { ref, onMounted } from 'vue';
|
|
25
|
-
import { dataService, EbizSApprovalProcess, EbizApprovalForm } from '../index'
|
|
31
|
+
import { dataService, EbizSApprovalProcess, EbizApprovalForm, EbizTag } from '../index'
|
|
26
32
|
import { MessagePlugin as message, LoadingPlugin as loading } from 'tdesign-vue-next'
|
|
27
33
|
|
|
28
34
|
const props = defineProps({
|
|
@@ -36,6 +42,8 @@ const props = defineProps({
|
|
|
36
42
|
}
|
|
37
43
|
})
|
|
38
44
|
|
|
45
|
+
const emit = defineEmits(['loaded'])
|
|
46
|
+
|
|
39
47
|
// 审批流程组件实例
|
|
40
48
|
const approvalprocessRef = ref(null)
|
|
41
49
|
|
|
@@ -51,9 +59,22 @@ const currTask = ref({})
|
|
|
51
59
|
// 是否为当前任务的审批人
|
|
52
60
|
const isAssignee = ref(false)
|
|
53
61
|
|
|
62
|
+
// 加载状态
|
|
63
|
+
const isLoading = ref(false)
|
|
64
|
+
|
|
65
|
+
const themeMap = {
|
|
66
|
+
CANCELED: 'default',
|
|
67
|
+
REJECTED: 'danger',
|
|
68
|
+
APPROVED: 'success',
|
|
69
|
+
ACTIVE: 'primary',
|
|
70
|
+
COMPLETED: 'success',
|
|
71
|
+
SUSPENDED: 'warning'
|
|
72
|
+
}
|
|
73
|
+
|
|
54
74
|
// 获取审批详情
|
|
55
75
|
const getApprovalDetail = () => {
|
|
56
76
|
loading(true)
|
|
77
|
+
isLoading.value = true
|
|
57
78
|
dataService.fetch(
|
|
58
79
|
{
|
|
59
80
|
businessKey: props.businessKey,
|
|
@@ -72,8 +93,13 @@ const getApprovalDetail = () => {
|
|
|
72
93
|
isAssignee.value = false
|
|
73
94
|
}
|
|
74
95
|
loading(false)
|
|
96
|
+
isLoading.value = false
|
|
97
|
+
emit('loaded', res)
|
|
75
98
|
}).catch((err) => {
|
|
76
99
|
message.error(err.message)
|
|
100
|
+
loading(false)
|
|
101
|
+
isLoading.value = false
|
|
102
|
+
emit('loaded', err)
|
|
77
103
|
})
|
|
78
104
|
}
|
|
79
105
|
|
|
@@ -96,6 +122,13 @@ const refresh = () => {
|
|
|
96
122
|
onMounted(() => {
|
|
97
123
|
init()
|
|
98
124
|
})
|
|
125
|
+
|
|
126
|
+
defineExpose({
|
|
127
|
+
refresh,
|
|
128
|
+
currTask,
|
|
129
|
+
isLoading,
|
|
130
|
+
isAssignee
|
|
131
|
+
})
|
|
99
132
|
</script>
|
|
100
133
|
|
|
101
134
|
<style lang='less' scoped>
|
|
@@ -109,7 +142,7 @@ onMounted(() => {
|
|
|
109
142
|
position: absolute;
|
|
110
143
|
top: 0;
|
|
111
144
|
left: 0;
|
|
112
|
-
padding:
|
|
145
|
+
padding: 4px 12px;
|
|
113
146
|
color: #000000;
|
|
114
147
|
font-size: 18px;
|
|
115
148
|
font-weight: 600;
|
|
@@ -118,8 +151,8 @@ onMounted(() => {
|
|
|
118
151
|
.detail-container {
|
|
119
152
|
position: relative;
|
|
120
153
|
display: flex;
|
|
121
|
-
width:
|
|
122
|
-
padding:
|
|
154
|
+
width: 900px;
|
|
155
|
+
padding: 30px 12px;
|
|
123
156
|
background-color: #ffffff;
|
|
124
157
|
border-radius: 4px;
|
|
125
158
|
box-sizing: border-box;
|
|
@@ -29,13 +29,13 @@
|
|
|
29
29
|
</t-button>
|
|
30
30
|
</t-dropdown>
|
|
31
31
|
</div>
|
|
32
|
-
<div>
|
|
32
|
+
<div style="display: flex;">
|
|
33
33
|
<t-button theme="primary" type="submit" content="通过" @click="handlePass">
|
|
34
34
|
<template #icon>
|
|
35
35
|
<t-icon name="check" size="large" class="component-base-style"></t-icon>
|
|
36
36
|
</template>
|
|
37
37
|
</t-button>
|
|
38
|
-
<t-button content="拒绝" the type="reset" style="margin-left: 10px" @click="handleReject">
|
|
38
|
+
<t-button theme="danger" content="拒绝" the type="reset" style="margin-left: 10px" @click="handleReject">
|
|
39
39
|
<template #icon>
|
|
40
40
|
<t-icon name="close" size="large" class="component-base-style"></t-icon>
|
|
41
41
|
</template>
|
|
@@ -67,7 +67,8 @@
|
|
|
67
67
|
<span class="selected-label">{{ item.label }}</span>
|
|
68
68
|
<t-icon name="close-circle" class="remove-icon" @click="removePreviewItem(item)" />
|
|
69
69
|
</div>
|
|
70
|
-
<div v-if="[...selectPreview, ...selectPreviewPost, ...selectPreviewUser].length === 0"
|
|
70
|
+
<div v-if="[...selectPreview, ...selectPreviewPost, ...selectPreviewUser].length === 0"
|
|
71
|
+
class="no-selection">
|
|
71
72
|
<t-icon name="info-circle" />
|
|
72
73
|
<span style="user-select: none">请在左侧选择部门或成员</span>
|
|
73
74
|
</div>
|
|
@@ -148,13 +149,18 @@ const postTree = ref()
|
|
|
148
149
|
const fetchApiData = async () => {
|
|
149
150
|
loading.value = true
|
|
150
151
|
try {
|
|
152
|
+
// 加载部门
|
|
151
153
|
dataService.fetch(
|
|
152
154
|
{ keyWord: activeTab.value === 'organization' ? searchText.value : '' },
|
|
153
155
|
{},
|
|
154
156
|
'/appdata/execute/plugin?key=organizational_structure'
|
|
155
157
|
).then(res => {
|
|
156
158
|
organizationData.value = res || []
|
|
159
|
+
checkedNodes.value = props.modelValue.filter(i => i.type === 'DEPT').map((item) => item.bindid);
|
|
160
|
+
console.log("checkedNodes: {}", checkedNodes)
|
|
157
161
|
})
|
|
162
|
+
|
|
163
|
+
// 加载用户
|
|
158
164
|
dataService.fetch(
|
|
159
165
|
{ postEnable: true, keyWord: activeTab.value === 'employee' ? searchText.value : '' },
|
|
160
166
|
{},
|
|
@@ -165,7 +171,10 @@ const fetchApiData = async () => {
|
|
|
165
171
|
bindid: i.id,
|
|
166
172
|
type: 'employee'
|
|
167
173
|
}));
|
|
174
|
+
checkedUserNodes.value = props.modelValue.filter(i => i.type === 'employee').map((item) => item.bindid);
|
|
168
175
|
})
|
|
176
|
+
|
|
177
|
+
// 加载岗位
|
|
169
178
|
dataService.fetch({
|
|
170
179
|
apiKey: 'all_active_post',
|
|
171
180
|
queryParams: {
|
|
@@ -179,6 +188,7 @@ const fetchApiData = async () => {
|
|
|
179
188
|
bindid: i.id,
|
|
180
189
|
type: 'GW'
|
|
181
190
|
}))
|
|
191
|
+
checkedPostNodes.value = props.modelValue.filter(i => i.type === 'GW').map(item => item.bindid);
|
|
182
192
|
})
|
|
183
193
|
console.log(postData.value)
|
|
184
194
|
} catch (error) {
|
|
@@ -203,9 +213,9 @@ function showDialog() {
|
|
|
203
213
|
// 获取API数据
|
|
204
214
|
fetchApiData()
|
|
205
215
|
// 重置选中的节点
|
|
206
|
-
checkedNodes.value = props.modelValue.filter(i => i.type === 'DEPT').map((item) => item.bindid);
|
|
207
|
-
checkedUserNodes.value = props.modelValue.filter(i => i.type === 'employee').map((item) => item.bindid);
|
|
208
|
-
checkedPostNodes.value = props.modelValue.filter(i => i.type === 'GW').map(item => item.bindid);
|
|
216
|
+
// checkedNodes.value = props.modelValue.filter(i => i.type === 'DEPT').map((item) => item.bindid);
|
|
217
|
+
// checkedUserNodes.value = props.modelValue.filter(i => i.type === 'employee').map((item) => item.bindid);
|
|
218
|
+
// checkedPostNodes.value = props.modelValue.filter(i => i.type === 'GW').map(item => item.bindid);
|
|
209
219
|
dialogVisible.value = true
|
|
210
220
|
}
|
|
211
221
|
|
|
@@ -262,16 +272,21 @@ watch(
|
|
|
262
272
|
checkedNodes,
|
|
263
273
|
(newValues) => {
|
|
264
274
|
if (!organizationTree.value?.treeRef) return
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
275
|
+
console.log("部门选择变化", organizationTree.value.treeRef.getItem, newValues)
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
selectPreview.value = (newValues.map(organizationTree.value.treeRef.getItem) ?? []).map((i) => ({
|
|
278
|
+
label: i?.label,
|
|
279
|
+
type: i?.data?.type || i?.type,
|
|
280
|
+
bindid: i?.value
|
|
281
|
+
}))
|
|
282
|
+
}, 200)
|
|
283
|
+
|
|
270
284
|
},
|
|
271
285
|
{ deep: true }
|
|
272
286
|
)
|
|
273
287
|
watch(checkedUserNodes, nVal => {
|
|
274
288
|
// 获取新选中的用户数据
|
|
289
|
+
console.log("用户选择变化")
|
|
275
290
|
const newSelectedUsers = employeeData.value.filter(i => nVal.includes(i.bindid))
|
|
276
291
|
// 获取现有用户的bindid列表,避免重复添加
|
|
277
292
|
const existingBindIds = selectPreviewUser.value.map(user => user.bindid)
|
|
@@ -281,6 +296,7 @@ watch(checkedUserNodes, nVal => {
|
|
|
281
296
|
selectPreviewUser.value = [...selectPreviewUser.value, ...usersToAdd]
|
|
282
297
|
}, { deep: true })
|
|
283
298
|
watch(checkedPostNodes, nVal => {
|
|
299
|
+
console.log("岗位选择变化")
|
|
284
300
|
selectPreviewPost.value = postData.value.filter(i => nVal.includes(i.bindid))
|
|
285
301
|
}, { deep: true })
|
|
286
302
|
// 监听modelValue变化,同步到选中节点
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div color="#999">
|
|
3
|
+
<div class="card">
|
|
4
|
+
<div class="header">
|
|
5
|
+
<ebiz-tag size="medium" variant="dark" class="component-base-style" :content="{
|
|
6
|
+
REJECTED: '已驳回',
|
|
7
|
+
APPROVED: '已通过',
|
|
8
|
+
ACTIVE: '进行中',
|
|
9
|
+
CANCELED: '已取消'
|
|
10
|
+
}[status] || '未知状态'
|
|
11
|
+
" :theme="{
|
|
12
|
+
REJECTED: 'danger',
|
|
13
|
+
APPROVED: 'success',
|
|
14
|
+
ACTIVE: 'primary',
|
|
15
|
+
CANCELED: 'default'
|
|
16
|
+
}[status] || 'default'
|
|
17
|
+
"></ebiz-tag>
|
|
18
|
+
<span style="display: inline-block; font-size: 14px">{{ typeDesc || '未知' }}</span>
|
|
19
|
+
<span style="display: inline-block; font-size: 14px; color: #666; margin-left: auto"
|
|
20
|
+
class="component-base-style">{{ utils.calcTime(date, 'y/M/d') }}</span>
|
|
21
|
+
</div>
|
|
22
|
+
<div v-if="fields.length">
|
|
23
|
+
<div class="body">
|
|
24
|
+
<div v-for="(item, index) in fields.sort((a, b) => a.sort - b.sort)" class="component-base-style"
|
|
25
|
+
:key="index">
|
|
26
|
+
<span style="display: inline-block" class="label">{{ item.label + ':' }}</span>
|
|
27
|
+
<span v-if="item.value_type == 'text' || item.value_type == 'textarea'" style="display: inline-block"
|
|
28
|
+
class="value">{{ item.actual_value }}</span>
|
|
29
|
+
<ebiz-file-list v-if="item.value_type == 'files' || item.value_type == 'images'" displayMode="grid"
|
|
30
|
+
:showActions="true" :showFileSize="true" size="mini" class="component-base-style"
|
|
31
|
+
:files="item.actual_value || []"></ebiz-file-list>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div v-if="!fields.length" style="
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: center;
|
|
39
|
+
gap: 15px;
|
|
40
|
+
height: 100px;
|
|
41
|
+
flex-direction: column;
|
|
42
|
+
" class="component-base-style">
|
|
43
|
+
<ebiz-tdesign-icon name="data-error" size="large" color="#999" style="font-size: 40px"
|
|
44
|
+
class="component-base-style"></ebiz-tdesign-icon>
|
|
45
|
+
<span style="display: inline-block; color: #999" class="component-base-style">字段未配置</span>
|
|
46
|
+
</div>
|
|
47
|
+
<div v-if="btns?.length" class="footer">
|
|
48
|
+
<ebiz-tdesign-button v-for="(item, index) in btns ?? []" size="medium" :content="item.label"
|
|
49
|
+
:theme="item.theme || 'primary'" :disabled="item.disabled" :key="index" :class="item.hidden ? 'hidden' : ''"
|
|
50
|
+
@click="(...eventArgs) => btnClick(eventArgs, index, item)"></ebiz-tdesign-button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<script setup>
|
|
57
|
+
import { EbizTag, EbizTdesignIcon, EbizTdesignButton, EbizFileList } from ''
|
|
58
|
+
import * as vue from 'vue'
|
|
59
|
+
import { defineProps, defineEmits } from 'vue'
|
|
60
|
+
import { I18nInjectionKey } from 'vue-i18n'
|
|
61
|
+
|
|
62
|
+
const props = defineProps({
|
|
63
|
+
status: { type: String, default: '' },
|
|
64
|
+
type: { type: String, default: '' },
|
|
65
|
+
typeDesc: { type: String, default: '' },
|
|
66
|
+
date: { type: String, default: '' },
|
|
67
|
+
fields: { type: Array, default: () => [] },
|
|
68
|
+
btns: { type: Array, default: () => [] },
|
|
69
|
+
mode: { type: String, default: 'ing' },
|
|
70
|
+
item: { type: Object, default: () => ({}) }
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
const emit = defineEmits(['btn-click'])
|
|
74
|
+
const { t, lowcodeWrap, stores } = vue.inject(I18nInjectionKey).lowcode()
|
|
75
|
+
const wrap = lowcodeWrap(props, { emit })
|
|
76
|
+
wrap({ stores })
|
|
77
|
+
|
|
78
|
+
const { utils } = wrap(function () {
|
|
79
|
+
return this
|
|
80
|
+
})()
|
|
81
|
+
const state = vue.reactive({})
|
|
82
|
+
wrap({ state })
|
|
83
|
+
|
|
84
|
+
const btnClick = wrap(function btnClick(event, args0, args1) {
|
|
85
|
+
this.emit('btnClick', args0, args1)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
wrap({ btnClick })
|
|
89
|
+
</script>
|
|
90
|
+
<style scoped>
|
|
91
|
+
.card {
|
|
92
|
+
padding: 12px;
|
|
93
|
+
border-radius: 15px;
|
|
94
|
+
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.05), 0 4px 5px rgba(0, 0, 0, 0.08), 0 2px 4px -1px rgba(0, 0, 0, 0.12);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.header {
|
|
98
|
+
display: flex;
|
|
99
|
+
align-items: center;
|
|
100
|
+
gap: 10px;
|
|
101
|
+
margin-bottom: 10px;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.body {}
|
|
105
|
+
|
|
106
|
+
.label {
|
|
107
|
+
color: #666;
|
|
108
|
+
min-width: 100px;
|
|
109
|
+
font-size: 14px;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.value {
|
|
113
|
+
color: #666;
|
|
114
|
+
font-size: 14px;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.footer {
|
|
118
|
+
margin-top: 10px;
|
|
119
|
+
display: flex;
|
|
120
|
+
justify-content: flex-end;
|
|
121
|
+
gap: 10px;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.hidden {
|
|
125
|
+
display: none !important;
|
|
126
|
+
}
|
|
127
|
+
</style>
|
|
@@ -73,6 +73,18 @@
|
|
|
73
73
|
:clearable="clearable" :format="timeFormat || 'HH:mm:ss'" @change="handleChange" />
|
|
74
74
|
</template>
|
|
75
75
|
|
|
76
|
+
<!-- 范围日期选择器 -->
|
|
77
|
+
<template v-else-if="type === 'date-range'">
|
|
78
|
+
<t-date-range-picker v-model="computedModelValue" :placeholder="placeholder || '请选择日期范围'" :disabled="disabled"
|
|
79
|
+
:clearable="clearable" :format="dateFormat || 'YYYY-MM-DD'" :mode="dateMode || 'date'" @change="handleChange" />
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<!-- 范围日期时间选择器 -->
|
|
83
|
+
<template v-else-if="type === 'datetime-range'">
|
|
84
|
+
<t-date-range-picker v-model="computedModelValue" :placeholder="placeholder || '请选择日期时间范围'" :disabled="disabled"
|
|
85
|
+
:clearable="clearable" format="YYYY-MM-DD HH:mm:ss" :mode="dateMode || 'date'" enable-time-picker @change="handleChange" />
|
|
86
|
+
</template>
|
|
87
|
+
|
|
76
88
|
<!-- 单选框组 -->
|
|
77
89
|
<template v-else-if="type === 'radio'">
|
|
78
90
|
<t-radio-group v-model="computedModelValue" :disabled="disabled" :options="options"
|
|
@@ -305,7 +317,8 @@ import {
|
|
|
305
317
|
ColorPicker as TColorPicker,
|
|
306
318
|
Table as TTable,
|
|
307
319
|
Button as TButton,
|
|
308
|
-
Space as TSpace
|
|
320
|
+
Space as TSpace,
|
|
321
|
+
DateRangePicker as TDateRangePicker
|
|
309
322
|
} from 'tdesign-vue-next';
|
|
310
323
|
import EbizRemoteSelect from '../../EbizRemoteSelect.vue';
|
|
311
324
|
import EbizEmployeeSelector from '../../EbizEmployeeSelector.vue';
|