feat(permission): replace OA roles with post-bound roles and assignee posts
Unify effective roles via post-role bindings, remove dedicated OA role UI, and update OA assignee resolution plus related SQL/docs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
a3c73d76bb
commit
06db3bc966
66 files changed
+55337
-38647
No files matched your search
@@ -228,7 +228,7 @@
|
||||
function resolveSourceText(src: string) {
|
||||
const map: Record<string, string> = {
|
||||
users: '指定成员',
|
||||
oa_roles: '工作流角色',
|
||||
posts: '职位',
|
||||
dept_leader: '部门负责人',
|
||||
direct_supervisor: '直属主管',
|
||||
supervisor_fallback_dept_leader: '部门负责人(主管回退)',
|
||||
|
||||
@@ -83,72 +83,78 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field">
|
||||
<label class="oa-trip-leg__label">开始日期</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.startDate || '—' }}</span>
|
||||
</template>
|
||||
<el-date-picker
|
||||
v-else
|
||||
:model-value="leg.startDate || undefined"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择日期"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'startDate', v || '')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field">
|
||||
<label class="oa-trip-leg__label">开始时段</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.startHalf || '—' }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
v-else
|
||||
:model-value="leg.startHalf"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'startHalf', String(v || ''))"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in halfOpts"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
<div class="oa-trip-leg__row">
|
||||
<div class="oa-trip-leg__field oa-trip-leg__field--date">
|
||||
<label class="oa-trip-leg__label">开始日期</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.startDate || '—' }}</span>
|
||||
</template>
|
||||
<el-date-picker
|
||||
v-else
|
||||
:model-value="leg.startDate || undefined"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择日期"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'startDate', v || '')"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field oa-trip-leg__field--half">
|
||||
<label class="oa-trip-leg__label">开始时段</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.startHalf || '—' }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
v-else
|
||||
class="oa-trip-leg__half-select"
|
||||
:model-value="leg.startHalf"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'startHalf', String(v || ''))"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in halfOpts"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field">
|
||||
<label class="oa-trip-leg__label">结束日期</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.endDate || '—' }}</span>
|
||||
</template>
|
||||
<el-date-picker
|
||||
v-else
|
||||
:model-value="leg.endDate || undefined"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择日期"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'endDate', v || '')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field">
|
||||
<label class="oa-trip-leg__label">结束时段</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.endHalf || '—' }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
v-else
|
||||
:model-value="leg.endHalf"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'endHalf', String(v || ''))"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in halfOpts"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
<div class="oa-trip-leg__row">
|
||||
<div class="oa-trip-leg__field oa-trip-leg__field--date">
|
||||
<label class="oa-trip-leg__label">结束日期</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.endDate || '—' }}</span>
|
||||
</template>
|
||||
<el-date-picker
|
||||
v-else
|
||||
:model-value="leg.endDate || undefined"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="选择日期"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'endDate', v || '')"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field oa-trip-leg__field--half">
|
||||
<label class="oa-trip-leg__label">结束时段</label>
|
||||
<template v-if="disabled">
|
||||
<span class="oa-trip-leg__readonly">{{ leg.endHalf || '—' }}</span>
|
||||
</template>
|
||||
<el-select
|
||||
v-else
|
||||
class="oa-trip-leg__half-select"
|
||||
:model-value="leg.endHalf"
|
||||
@update:model-value="(v) => onScheduleChange(idx, 'endHalf', String(v || ''))"
|
||||
>
|
||||
<el-option
|
||||
v-for="opt in halfOpts"
|
||||
:key="opt.value"
|
||||
:label="opt.label"
|
||||
:value="opt.value"
|
||||
/>
|
||||
</el-select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oa-trip-leg__field oa-trip-leg__field--duration">
|
||||
@@ -383,16 +389,28 @@
|
||||
|
||||
.oa-trip-leg__grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px 16px;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.oa-trip-leg__row {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
align-items: flex-start;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.oa-trip-leg__field {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.oa-trip-leg__field--duration {
|
||||
grid-column: 1 / -1;
|
||||
.oa-trip-leg__field--date {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.oa-trip-leg__field--half {
|
||||
flex: 0 0 120px;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.oa-trip-leg__label {
|
||||
@@ -443,18 +461,13 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.oa-trip-leg__half-select {
|
||||
width: 120px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.oa-trip-leg :deep(.el-input__wrapper),
|
||||
.oa-trip-leg :deep(.el-select__wrapper) {
|
||||
min-height: 36px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.oa-trip-leg__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.oa-trip-leg__field--duration {
|
||||
grid-column: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -156,109 +156,77 @@
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="showRolesPicker">
|
||||
<el-form-item v-if="showPostsPicker">
|
||||
<template #label>
|
||||
工作流角色
|
||||
<span class="form-label-tip">可多选,已选角色成员将作为本节点{{ editing.type === 'cc' ? '抄送' : '审批' }}人</span>
|
||||
职位
|
||||
<span class="form-label-tip">可多选,已选职位关联用户将作为本节点{{ editing.type === 'cc' ? '抄送' : '审批' }}人</span>
|
||||
</template>
|
||||
<div v-loading="roleLoading" class="member-picker">
|
||||
<div v-loading="postLoading" class="member-picker">
|
||||
<el-select
|
||||
v-model="rolePickBuffer"
|
||||
v-model="postPickBuffer"
|
||||
filterable
|
||||
clearable
|
||||
:loading="roleLoading"
|
||||
placeholder="搜索角色名称 / 编码,点击添加"
|
||||
:loading="postLoading"
|
||||
placeholder="搜索职位名称 / 编码,点击添加"
|
||||
style="width: 100%"
|
||||
popper-class="oa-flow-member-select-popper"
|
||||
@change="onRolePick"
|
||||
@change="onPostPick"
|
||||
>
|
||||
<el-option-group v-if="presetRoles.length" label="预置">
|
||||
<el-option
|
||||
v-for="r in presetRoles"
|
||||
:key="r.id"
|
||||
:label="roleOptionLabel(r)"
|
||||
:value="r.id"
|
||||
:disabled="(cfg.oaRoleIds || []).includes(r.id)"
|
||||
>
|
||||
<div class="member-option">
|
||||
<span class="member-avatar" :style="{ background: avatarColor(r.id) }">
|
||||
{{ avatarInitial(r.roleName) }}
|
||||
<el-option
|
||||
v-for="p in postOptions"
|
||||
:key="p.id"
|
||||
:label="postOptionLabel(p)"
|
||||
:value="p.id"
|
||||
:disabled="(cfg.postIds || []).includes(p.id)"
|
||||
>
|
||||
<div class="member-option">
|
||||
<span class="member-avatar" :style="{ background: avatarColor(p.id) }">
|
||||
{{ avatarInitial(p.postName) }}
|
||||
</span>
|
||||
<span class="member-option__meta">
|
||||
<span class="member-option__name">{{ p.postName || '未命名' }}</span>
|
||||
<span v-if="p.postCode" class="member-option__sub">
|
||||
编码 {{ p.postCode }}
|
||||
</span>
|
||||
<span class="member-option__meta">
|
||||
<span class="member-option__name">{{ r.roleName || '未命名' }}</span>
|
||||
<span v-if="r.roleCode" class="member-option__sub">
|
||||
编码 {{ r.roleCode }}
|
||||
</span>
|
||||
</span>
|
||||
<el-tag
|
||||
v-if="(cfg.oaRoleIds || []).includes(r.id)"
|
||||
size="small"
|
||||
type="info"
|
||||
effect="plain"
|
||||
class="member-option__tag"
|
||||
>
|
||||
已选
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
<el-option-group v-if="customRoles.length" label="自定义">
|
||||
<el-option
|
||||
v-for="r in customRoles"
|
||||
:key="r.id"
|
||||
:label="roleOptionLabel(r)"
|
||||
:value="r.id"
|
||||
:disabled="(cfg.oaRoleIds || []).includes(r.id)"
|
||||
>
|
||||
<div class="member-option">
|
||||
<span class="member-avatar" :style="{ background: avatarColor(r.id) }">
|
||||
{{ avatarInitial(r.roleName) }}
|
||||
</span>
|
||||
<span class="member-option__meta">
|
||||
<span class="member-option__name">{{ r.roleName || '未命名' }}</span>
|
||||
<span v-if="r.roleCode" class="member-option__sub">
|
||||
编码 {{ r.roleCode }}
|
||||
</span>
|
||||
</span>
|
||||
<el-tag
|
||||
v-if="(cfg.oaRoleIds || []).includes(r.id)"
|
||||
size="small"
|
||||
type="info"
|
||||
effect="plain"
|
||||
class="member-option__tag"
|
||||
>
|
||||
已选
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-option-group>
|
||||
</span>
|
||||
<el-tag
|
||||
v-if="(cfg.postIds || []).includes(p.id)"
|
||||
size="small"
|
||||
type="info"
|
||||
effect="plain"
|
||||
class="member-option__tag"
|
||||
>
|
||||
已选
|
||||
</el-tag>
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
|
||||
<div
|
||||
class="member-chips"
|
||||
:class="{ 'is-empty': !(cfg.oaRoleIds && cfg.oaRoleIds.length) }"
|
||||
:class="{ 'is-empty': !(cfg.postIds && cfg.postIds.length) }"
|
||||
>
|
||||
<template v-if="cfg.oaRoleIds && cfg.oaRoleIds.length">
|
||||
<span v-for="id in cfg.oaRoleIds" :key="id" class="member-chip">
|
||||
<template v-if="cfg.postIds && cfg.postIds.length">
|
||||
<span v-for="id in cfg.postIds" :key="id" class="member-chip">
|
||||
<span class="member-avatar member-avatar--sm" :style="{ background: avatarColor(id) }">
|
||||
{{ avatarInitial(resolveRole(id)?.roleName) }}
|
||||
{{ avatarInitial(resolvePost(id)?.postName) }}
|
||||
</span>
|
||||
<span class="member-chip__name" :title="roleChipTitle(id)">
|
||||
{{ resolveRole(id)?.roleName || id }}
|
||||
<span class="member-chip__name" :title="postChipTitle(id)">
|
||||
{{ resolvePost(id)?.postName || id }}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
class="member-chip__rm"
|
||||
:aria-label="`移除 ${resolveRole(id)?.roleName || id}`"
|
||||
@click="removeRole(id)"
|
||||
:aria-label="`移除 ${resolvePost(id)?.postName || id}`"
|
||||
@click="removePost(id)"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<template v-else>暂未选择角色,请从上方搜索添加</template>
|
||||
<template v-else>暂未选择职位,请从上方搜索添加</template>
|
||||
</div>
|
||||
<p class="member-picked-count">已选 {{ cfg.oaRoleIds?.length || 0 }} 个角色</p>
|
||||
<p class="member-picked-count">已选 {{ cfg.postIds?.length || 0 }} 个职位</p>
|
||||
</div>
|
||||
</el-form-item>
|
||||
|
||||
@@ -330,8 +298,7 @@
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Close, Check, UserFilled } from '@element-plus/icons-vue'
|
||||
import { fetchUserList } from '@/api/admin'
|
||||
import { fetchOaRoleList } from '@/api/oaApproval'
|
||||
import { fetchUserList, fetchPostList } from '@/api/admin'
|
||||
import { MAX_ADMIN_LIST_PAGE_SIZE } from '@/utils/fetch-paged-list'
|
||||
import type { ConditionCandidate } from '@/components/oa-approval/oa-condition-fields'
|
||||
import ConditionRuleEditor from './ConditionRuleEditor.vue'
|
||||
@@ -396,13 +363,13 @@
|
||||
assigneeType: 'dept_leader',
|
||||
assigneeTypes: [],
|
||||
userIds: [],
|
||||
oaRoleIds: [],
|
||||
postIds: [],
|
||||
signMode: 'or'
|
||||
})
|
||||
|
||||
const assigneeTypeOptions: Array<{ label: string; value: AssigneeType }> = [
|
||||
{ label: '指定成员', value: 'users' },
|
||||
{ label: '工作流角色', value: 'oa_roles' },
|
||||
{ label: '职位', value: 'posts' },
|
||||
{ label: '部门负责人', value: 'dept_leader' },
|
||||
{ label: '发起人主管', value: 'direct_supervisor' },
|
||||
{ label: '发起人自选', value: 'initiator_select' }
|
||||
@@ -412,9 +379,9 @@
|
||||
if (editing.value?.type === 'cc') return (cfg.assigneeTypes || []).includes('users')
|
||||
return cfg.assigneeType === 'users'
|
||||
})
|
||||
const showRolesPicker = computed(() => {
|
||||
if (editing.value?.type === 'cc') return (cfg.assigneeTypes || []).includes('oa_roles')
|
||||
return cfg.assigneeType === 'oa_roles'
|
||||
const showPostsPicker = computed(() => {
|
||||
if (editing.value?.type === 'cc') return (cfg.assigneeTypes || []).includes('posts')
|
||||
return cfg.assigneeType === 'posts'
|
||||
})
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
@@ -435,19 +402,13 @@
|
||||
return '配置流程节点'
|
||||
})
|
||||
|
||||
const roleLoading = ref(false)
|
||||
const postLoading = ref(false)
|
||||
const userLoading = ref(false)
|
||||
const roleOptions = ref<any[]>([])
|
||||
type PostOption = { id: string; postName: string; postCode: string }
|
||||
const postOptions = ref<PostOption[]>([])
|
||||
const userOptions = ref<UserOption[]>([])
|
||||
const memberPickBuffer = ref('')
|
||||
const rolePickBuffer = ref('')
|
||||
|
||||
const presetRoles = computed(() =>
|
||||
roleOptions.value.filter((r) => r.roleKind === 'preset' || ['GM', 'CHAIRMAN'].includes(r.roleCode))
|
||||
)
|
||||
const customRoles = computed(() =>
|
||||
roleOptions.value.filter((r) => r.roleKind !== 'preset' && !['GM', 'CHAIRMAN'].includes(r.roleCode))
|
||||
)
|
||||
const postPickBuffer = ref('')
|
||||
|
||||
function avatarColor(id: string) {
|
||||
let hash = 0
|
||||
@@ -464,8 +425,8 @@
|
||||
return userOptions.value.find((u) => u.id === id)
|
||||
}
|
||||
|
||||
function resolveRole(id: string) {
|
||||
return roleOptions.value.find((r) => r.id === id)
|
||||
function resolvePost(id: string) {
|
||||
return postOptions.value.find((p) => p.id === id)
|
||||
}
|
||||
|
||||
function chipTitle(id: string) {
|
||||
@@ -473,16 +434,16 @@
|
||||
return u ? memberOptionLabel(u) : id
|
||||
}
|
||||
|
||||
function roleOptionLabel(r: { roleName?: string; roleCode?: string }) {
|
||||
const name = (r.roleName || '').trim() || '未命名'
|
||||
const code = (r.roleCode || '').trim()
|
||||
function postOptionLabel(p: { postName?: string; postCode?: string }) {
|
||||
const name = (p.postName || '').trim() || '未命名'
|
||||
const code = (p.postCode || '').trim()
|
||||
if (code && code !== name) return `${name}(${code})`
|
||||
return name
|
||||
}
|
||||
|
||||
function roleChipTitle(id: string) {
|
||||
const r = resolveRole(id)
|
||||
return r ? roleOptionLabel(r) : id
|
||||
function postChipTitle(id: string) {
|
||||
const p = resolvePost(id)
|
||||
return p ? postOptionLabel(p) : id
|
||||
}
|
||||
|
||||
function memberOptionLabel(u: UserOption) {
|
||||
@@ -514,18 +475,18 @@
|
||||
cfg.userIds = cfg.userIds.filter((x) => x !== id)
|
||||
}
|
||||
|
||||
function onRolePick(id: string) {
|
||||
function onPostPick(id: string) {
|
||||
if (!id) return
|
||||
if (!cfg.oaRoleIds) cfg.oaRoleIds = []
|
||||
if (!cfg.oaRoleIds.includes(id)) cfg.oaRoleIds.push(id)
|
||||
if (!cfg.postIds) cfg.postIds = []
|
||||
if (!cfg.postIds.includes(id)) cfg.postIds.push(id)
|
||||
nextTick(() => {
|
||||
rolePickBuffer.value = ''
|
||||
postPickBuffer.value = ''
|
||||
})
|
||||
}
|
||||
|
||||
function removeRole(id: string) {
|
||||
if (!cfg.oaRoleIds) return
|
||||
cfg.oaRoleIds = cfg.oaRoleIds.filter((x) => x !== id)
|
||||
function removePost(id: string) {
|
||||
if (!cfg.postIds) return
|
||||
cfg.postIds = cfg.postIds.filter((x) => x !== id)
|
||||
}
|
||||
|
||||
async function setAssigneeType(type: AssigneeType) {
|
||||
@@ -542,19 +503,33 @@
|
||||
cfg.assigneeTypes = cur
|
||||
if (cur[0]) cfg.assigneeType = cur[0]
|
||||
if (cur.includes('users')) await loadUsers()
|
||||
if (cur.includes('oa_roles')) await loadRoles()
|
||||
if (cur.includes('posts')) await loadPosts()
|
||||
return
|
||||
}
|
||||
await setAssigneeType(type)
|
||||
}
|
||||
|
||||
async function loadRoles() {
|
||||
roleLoading.value = true
|
||||
async function loadPosts() {
|
||||
postLoading.value = true
|
||||
try {
|
||||
const res = await fetchOaRoleList({ status: '1' })
|
||||
roleOptions.value = res?.list || []
|
||||
const pageSize = MAX_ADMIN_LIST_PAGE_SIZE
|
||||
const raw: any[] = []
|
||||
let page = 1
|
||||
for (;;) {
|
||||
const res = await fetchPostList({ page, pageSize })
|
||||
const list = (res?.list || []).filter((p: any) => p.status === '1')
|
||||
raw.push(...list)
|
||||
if ((res?.list || []).length < pageSize) break
|
||||
if (typeof res?.total === 'number' && raw.length >= res.total) break
|
||||
page += 1
|
||||
}
|
||||
postOptions.value = raw.map((p) => ({
|
||||
id: p.id,
|
||||
postName: p.postName || '',
|
||||
postCode: p.postCode || ''
|
||||
}))
|
||||
} finally {
|
||||
roleLoading.value = false
|
||||
postLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,18 +659,18 @@
|
||||
cfg.assigneeType = ac.assigneeType || 'dept_leader'
|
||||
}
|
||||
cfg.userIds = [...(ac.userIds || [])]
|
||||
cfg.oaRoleIds = [...(ac.oaRoleIds || [])]
|
||||
cfg.postIds = [...(ac.postIds || [])]
|
||||
cfg.signMode = ac.signMode || 'or'
|
||||
memberPickBuffer.value = ''
|
||||
rolePickBuffer.value = ''
|
||||
if (showUsersPicker.value) await loadUsers()
|
||||
if (showRolesPicker.value) await loadRoles()
|
||||
if (showPostsPicker.value) await loadPosts()
|
||||
drawerVisible.value = true
|
||||
}
|
||||
|
||||
async function onAssigneeTypeChange() {
|
||||
if (cfg.assigneeType === 'users' && !userOptions.value.length) await loadUsers()
|
||||
if (cfg.assigneeType === 'oa_roles' && !roleOptions.value.length) await loadRoles()
|
||||
if (cfg.assigneeType === 'posts' && !postOptions.value.length) await loadPosts()
|
||||
}
|
||||
|
||||
function onDefaultChange(idx: number, v: boolean) {
|
||||
@@ -750,21 +725,21 @@
|
||||
ElMessage.warning('已勾选指定成员,请选择至少一名成员')
|
||||
return
|
||||
}
|
||||
if (types.includes('oa_roles') && !(cfg.oaRoleIds || []).length) {
|
||||
ElMessage.warning('已勾选工作流角色,请选择至少一个角色')
|
||||
if (types.includes('posts') && !(cfg.postIds || []).length) {
|
||||
ElMessage.warning('已勾选职位,请选择至少一个职位')
|
||||
return
|
||||
}
|
||||
live.approverConfig = {
|
||||
assigneeTypes: types,
|
||||
assigneeType: types[0],
|
||||
userIds: [...(cfg.userIds || [])],
|
||||
oaRoleIds: [...(cfg.oaRoleIds || [])]
|
||||
postIds: [...(cfg.postIds || [])]
|
||||
}
|
||||
} else if (live.type === 'approval') {
|
||||
live.approverConfig = {
|
||||
assigneeType: cfg.assigneeType,
|
||||
userIds: cfg.assigneeType === 'users' ? [...(cfg.userIds || [])] : undefined,
|
||||
oaRoleIds: cfg.assigneeType === 'oa_roles' ? [...(cfg.oaRoleIds || [])] : undefined,
|
||||
postIds: cfg.assigneeType === 'posts' ? [...(cfg.postIds || [])] : undefined,
|
||||
signMode: cfg.signMode || 'or'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ export type FlowNodeType = 'start' | 'approval' | 'cc' | 'condition' | 'end'
|
||||
|
||||
export type AssigneeType =
|
||||
| 'users'
|
||||
| 'oa_roles'
|
||||
| 'posts'
|
||||
| 'dept_leader'
|
||||
| 'direct_supervisor'
|
||||
| 'initiator_select'
|
||||
@@ -13,8 +13,7 @@ export interface ApproverConfig {
|
||||
/** 抄送人:多选选人方式(优先)。审批人:不使用 */
|
||||
assigneeTypes?: AssigneeType[]
|
||||
userIds?: string[]
|
||||
oaRoleIds?: string[]
|
||||
oaRoleCodes?: string[]
|
||||
postIds?: string[]
|
||||
signMode?: 'or' | 'and'
|
||||
}
|
||||
|
||||
@@ -126,7 +125,7 @@ export function ensureFlowRoot(raw: unknown): FlowNode {
|
||||
|
||||
const VALID_ASSIGNEE: AssigneeType[] = [
|
||||
'users',
|
||||
'oa_roles',
|
||||
'posts',
|
||||
'dept_leader',
|
||||
'direct_supervisor',
|
||||
'initiator_select'
|
||||
@@ -134,7 +133,7 @@ const VALID_ASSIGNEE: AssigneeType[] = [
|
||||
|
||||
const ASSIGNEE_LABEL: Record<AssigneeType, string> = {
|
||||
users: '指定成员',
|
||||
oa_roles: '工作流角色',
|
||||
posts: '职位',
|
||||
dept_leader: '发起人部门负责人',
|
||||
direct_supervisor: '发起人的主管',
|
||||
initiator_select: '发起人自选'
|
||||
@@ -170,8 +169,8 @@ export function summarizeApprover(cfg?: ApproverConfig, nodeType?: FlowNodeType)
|
||||
const n = cfg?.userIds?.length || 0
|
||||
return n ? `${base}(${n}人)` : `${base}(未选)`
|
||||
}
|
||||
if (t === 'oa_roles') {
|
||||
const n = (cfg?.oaRoleIds?.length || 0) + (cfg?.oaRoleCodes?.length || 0)
|
||||
if (t === 'posts') {
|
||||
const n = cfg?.postIds?.length || 0
|
||||
return n ? `${base}(已选${n})` : `${base}(未选)`
|
||||
}
|
||||
return base
|
||||
@@ -185,8 +184,8 @@ export function summarizeApprover(cfg?: ApproverConfig, nodeType?: FlowNodeType)
|
||||
const n = cfg.userIds?.length || 0
|
||||
return n ? `${base}(${n}人)` : `${base}(未选)`
|
||||
}
|
||||
if (cfg.assigneeType === 'oa_roles') {
|
||||
const n = (cfg.oaRoleIds?.length || 0) + (cfg.oaRoleCodes?.length || 0)
|
||||
if (cfg.assigneeType === 'posts') {
|
||||
const n = cfg.postIds?.length || 0
|
||||
return n ? `${base}(已选${n})` : `${base}(未选)`
|
||||
}
|
||||
const sign =
|
||||
|
||||
Reference in new issue
Block a user