提交
This commit is contained in:
1 parent
417d6c9c51
commit
c8fe0cdc20
102 files changed
+19847
-12224
No files matched your search
@@ -1,6 +1,6 @@
|
||||
<!-- 协议附件 — 迷你缩略图只读(卡片列表用) -->
|
||||
<template>
|
||||
<div class="protocol-attachment-mini">
|
||||
<div class="protocol-attachment-mini" :class="{ 'is-multi': files.length > 1 }">
|
||||
<div v-if="label" class="protocol-attachment-mini__label">{{ label }}</div>
|
||||
<span v-if="!files.length" class="protocol-attachment-mini__empty">{{ emptyText }}</span>
|
||||
<div v-else class="protocol-attachment-mini__list">
|
||||
@@ -22,12 +22,12 @@
|
||||
</template>
|
||||
<template v-else-if="isVideoFile(file)">
|
||||
<div class="protocol-attachment-mini__icon protocol-attachment-mini__icon--video">
|
||||
<el-icon :size="20"><VideoPlay /></el-icon>
|
||||
<el-icon :size="files.length > 1 ? 14 : 20"><VideoPlay /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="protocol-attachment-mini__icon protocol-attachment-mini__icon--doc">
|
||||
<el-icon :size="20"><Document /></el-icon>
|
||||
<el-icon :size="files.length > 1 ? 14 : 20"><Document /></el-icon>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -219,4 +219,42 @@
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* 多附件时缩小缩略图,便于在卡片内并排展示 */
|
||||
.protocol-attachment-mini.is-multi {
|
||||
.protocol-attachment-mini__list {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__item {
|
||||
width: 48px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__preview {
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__footer {
|
||||
padding: 2px 3px;
|
||||
gap: 1px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__name {
|
||||
font-size: 9px;
|
||||
}
|
||||
|
||||
.protocol-attachment-mini__download {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
font-size: 9px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!-- 运行时栅格行:对齐设计器 FcRow(._fd-row flex),间距由 oa-fc-runtime.scss 提供 -->
|
||||
<template>
|
||||
<div class="_fd-row el-row" v-bind="$attrs">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'FcRow', inheritAttrs: false })
|
||||
</script>
|
||||
@@ -1,11 +1,14 @@
|
||||
<!-- 发起审批 · 表单底部审批流预览(对齐 docs/mockups/oa-approval-start-flow-preview-demo.html) -->
|
||||
<template>
|
||||
<div class="oa-flow-preview">
|
||||
<div v-loading="loading" class="oa-flow-preview">
|
||||
<div class="oa-flow-preview__title">
|
||||
<span>审批流程</span>
|
||||
<span v-if="hint" class="oa-flow-preview__hint">{{ hint }}</span>
|
||||
<span v-if="resolved && hint" class="oa-flow-preview__hint">{{ hint }}</span>
|
||||
</div>
|
||||
<div v-loading="loading" class="oa-flow-preview__chain">
|
||||
<div v-if="!resolved" class="oa-flow-preview__pending">
|
||||
{{ pendingMessage || '必填信息填写后,流程将自动显示' }}
|
||||
</div>
|
||||
<div v-else class="oa-flow-preview__chain">
|
||||
<div v-if="!loading && !steps.length" class="oa-flow-preview__empty">暂无流程配置</div>
|
||||
<div v-for="(s, idx) in steps" :key="s.id || idx" class="oa-flow-step">
|
||||
<div class="oa-flow-rail">
|
||||
@@ -49,15 +52,20 @@
|
||||
steps?: OaFlowPreviewStep[]
|
||||
loading?: boolean
|
||||
hint?: string
|
||||
resolved?: boolean
|
||||
pendingMessage?: string
|
||||
}>(),
|
||||
{
|
||||
steps: () => [],
|
||||
loading: false,
|
||||
hint: '按当前发起人解析审批人'
|
||||
hint: '按当前发起人解析审批人',
|
||||
resolved: true,
|
||||
pendingMessage: '必填信息填写后,流程将自动显示'
|
||||
}
|
||||
)
|
||||
|
||||
const steps = computed(() => props.steps || [])
|
||||
const resolved = computed(() => props.resolved !== false)
|
||||
|
||||
function signBadge(s: OaFlowPreviewStep) {
|
||||
if (s.type === 'cc' || s.signMode === 'cc') return 'cc'
|
||||
@@ -105,6 +113,14 @@
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.oa-flow-preview__pending {
|
||||
padding: 16px 8px 20px;
|
||||
color: var(--mint-text-muted, #94a3b8);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.oa-flow-preview__empty {
|
||||
padding: 8px 0;
|
||||
color: var(--mint-text-muted, #94a3b8);
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
const frameRef = ref<HTMLIFrameElement | null>(null)
|
||||
const frameReady = ref(false)
|
||||
let reqSeq = 0
|
||||
/** 最近一次推入 iframe 的 schema JSON,用于避免保存回写后重复 setRule 清空画布 */
|
||||
let lastPushedJson = ''
|
||||
const pending = new Map<
|
||||
number,
|
||||
{ resolve: (v: { rule: unknown; option: unknown }) => void; reject: (e: Error) => void }
|
||||
@@ -62,6 +64,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
function schemaJson(schema: unknown) {
|
||||
return JSON.stringify(toPlainSchema(schema))
|
||||
}
|
||||
|
||||
function postToFrame(payload: Record<string, unknown>) {
|
||||
try {
|
||||
frameRef.value?.contentWindow?.postMessage(payload, '*')
|
||||
@@ -70,11 +76,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
function pushSchemaToFrame() {
|
||||
/** force=true 时即使内容相同也重新 setRule(用于切回表单 Tab 强制回显) */
|
||||
function pushSchemaToFrame(force = false) {
|
||||
if (!frameReady.value) return
|
||||
const schema = toPlainSchema(props.modelValue)
|
||||
const json = JSON.stringify(schema)
|
||||
if (!force && json === lastPushedJson) return
|
||||
lastPushedJson = json
|
||||
postToFrame({
|
||||
type: MSG.SET,
|
||||
schema: toPlainSchema(props.modelValue)
|
||||
schema
|
||||
})
|
||||
}
|
||||
|
||||
@@ -88,7 +99,7 @@
|
||||
|
||||
function onFrameLoad() {
|
||||
if (frameReady.value) {
|
||||
pushSchemaToFrame()
|
||||
pushSchemaToFrame(true)
|
||||
pushFlowRefs()
|
||||
}
|
||||
}
|
||||
@@ -98,11 +109,13 @@
|
||||
if (!data || typeof data !== 'object') return
|
||||
if (data.type === MSG.READY) {
|
||||
frameReady.value = true
|
||||
pushSchemaToFrame()
|
||||
lastPushedJson = ''
|
||||
pushSchemaToFrame(true)
|
||||
pushFlowRefs()
|
||||
// 宿主刚就绪时再补推一次,避免 setRule 早于内部 dragForm 初始化
|
||||
window.setTimeout(() => pushSchemaToFrame(), 50)
|
||||
window.setTimeout(() => pushSchemaToFrame(), 200)
|
||||
// 宿主刚就绪时再补推,避免 setRule 早于内部 dragForm / 菜单初始化
|
||||
window.setTimeout(() => pushSchemaToFrame(true), 50)
|
||||
window.setTimeout(() => pushSchemaToFrame(true), 200)
|
||||
window.setTimeout(() => pushSchemaToFrame(true), 500)
|
||||
return
|
||||
}
|
||||
if (data.type === MSG.SCHEMA && typeof data.requestId === 'number') {
|
||||
@@ -110,6 +123,8 @@
|
||||
if (!wait) return
|
||||
pending.delete(data.requestId)
|
||||
const schema = toPlainSchema(data.schema)
|
||||
// 与父级即将回写的内容对齐,避免 watch 再次 setRule
|
||||
lastPushedJson = JSON.stringify(schema)
|
||||
wait.resolve(schema)
|
||||
}
|
||||
}
|
||||
@@ -136,12 +151,17 @@
|
||||
})
|
||||
}
|
||||
|
||||
/** 切回「表单设计」Tab 时强制把父级 schema 灌回画布 */
|
||||
function reapplySchema() {
|
||||
pushSchemaToFrame(true)
|
||||
pushFlowRefs()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
() => schemaJson(props.modelValue),
|
||||
() => {
|
||||
pushSchemaToFrame()
|
||||
},
|
||||
{ deep: true }
|
||||
pushSchemaToFrame(false)
|
||||
}
|
||||
)
|
||||
|
||||
watch(
|
||||
@@ -162,7 +182,7 @@
|
||||
pending.clear()
|
||||
})
|
||||
|
||||
defineExpose({ fetchSchema })
|
||||
defineExpose({ fetchSchema, reapplySchema })
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
<div v-if="!items.length" class="oa-flow-preview__empty">暂无任务记录</div>
|
||||
<div v-for="(item, idx) in items" :key="item.key" class="oa-flow-step">
|
||||
<div class="oa-flow-rail">
|
||||
<div
|
||||
class="oa-flow-dot"
|
||||
:class="dotClass(item)"
|
||||
/>
|
||||
<div class="oa-flow-dot" :class="dotClass(item)" />
|
||||
<div v-if="idx < items.length - 1" class="oa-flow-line" />
|
||||
</div>
|
||||
<div class="oa-flow-card">
|
||||
@@ -20,7 +17,11 @@
|
||||
<span v-if="statusBadge(item)" class="oa-flow-badge" :class="statusBadge(item)">
|
||||
{{ statusText(item.status) }}
|
||||
</span>
|
||||
<span v-if="item.taskType === 'cc'" class="oa-flow-badge cc">抄送</span>
|
||||
<span v-if="signBadge(item)" class="oa-flow-badge" :class="signBadge(item)">
|
||||
{{ signBadgeText(item) }}
|
||||
</span>
|
||||
<span v-else-if="item.taskType === 'cc'" class="oa-flow-badge cc">抄送</span>
|
||||
<span v-else-if="item.taskType === 'end'" class="oa-flow-badge mute">结束</span>
|
||||
<template v-if="item.timestamp">
|
||||
<span class="oa-flow-card__sep">·</span>
|
||||
<span class="oa-flow-card__meta" :title="item.timestamp">{{ item.timestamp }}</span>
|
||||
@@ -32,12 +33,21 @@
|
||||
</span>
|
||||
</template>
|
||||
<span
|
||||
v-if="item.assignee && item.kind !== 'pending_node' && item.kind !== 'terminal'"
|
||||
v-if="displayPeople(item).length && item.kind !== 'terminal'"
|
||||
class="oa-flow-card__people"
|
||||
>
|
||||
<span class="oa-person-chip">
|
||||
<span class="oa-person-chip__dot">{{ avatarChar(item.assignee) }}</span>
|
||||
{{ item.assignee }}
|
||||
<span
|
||||
v-for="p in displayPeople(item)"
|
||||
:key="p.id || p.nickName"
|
||||
class="oa-person-chip"
|
||||
:class="personChipClass(p.status)"
|
||||
:title="personTitle(p)"
|
||||
>
|
||||
<span class="oa-person-chip__dot">{{ avatarChar(p.nickName) }}</span>
|
||||
{{ p.nickName }}
|
||||
<span v-if="personStatusHint(p.status)" class="oa-person-chip__st">
|
||||
{{ personStatusHint(p.status) }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -53,6 +63,15 @@
|
||||
<script setup lang="ts">
|
||||
defineOptions({ name: 'OaProgressChain' })
|
||||
|
||||
export type OaProgressPerson = {
|
||||
id?: string
|
||||
nickName?: string
|
||||
status?: string
|
||||
timestamp?: string
|
||||
commentText?: string
|
||||
taskId?: string
|
||||
}
|
||||
|
||||
export type OaProgressChainItem = {
|
||||
key: string
|
||||
title: string
|
||||
@@ -63,6 +82,8 @@
|
||||
commentText?: string
|
||||
taskType?: string
|
||||
kind?: string
|
||||
signMode?: string
|
||||
people?: OaProgressPerson[]
|
||||
}
|
||||
|
||||
withDefaults(
|
||||
@@ -100,6 +121,59 @@
|
||||
return ''
|
||||
}
|
||||
|
||||
function signBadge(item: OaProgressChainItem) {
|
||||
if (item.taskType === 'cc' || item.signMode === 'cc') return 'cc'
|
||||
if (item.signMode === 'and') return 'and'
|
||||
if (item.signMode === 'or') return 'or'
|
||||
return ''
|
||||
}
|
||||
|
||||
function signBadgeText(item: OaProgressChainItem) {
|
||||
const k = signBadge(item)
|
||||
if (k === 'cc') return '抄送'
|
||||
if (k === 'and') return '会签'
|
||||
if (k === 'or') return '或签'
|
||||
return ''
|
||||
}
|
||||
|
||||
function displayPeople(item: OaProgressChainItem): OaProgressPerson[] {
|
||||
const list = Array.isArray(item.people) ? item.people.filter((p) => p?.nickName || p?.id) : []
|
||||
if (list.length) {
|
||||
return list.map((p) => ({
|
||||
...p,
|
||||
nickName: (p.nickName || p.id || '').trim()
|
||||
}))
|
||||
}
|
||||
const name = (item.assignee || '').trim()
|
||||
if (!name) return []
|
||||
return [{ nickName: name, status: item.status }]
|
||||
}
|
||||
|
||||
function personChipClass(status?: string) {
|
||||
const s = status || ''
|
||||
if (s === 'approved' || s === 'completed') return 'is-ok'
|
||||
if (s === 'pending' || s === 'running') return 'is-pending'
|
||||
if (s === 'rejected' || s === 'returned' || s === 'cancelled') return 'is-danger'
|
||||
if (s === 'done' || s === 'not_reached') return 'is-mute'
|
||||
return ''
|
||||
}
|
||||
|
||||
function personStatusHint(status?: string) {
|
||||
const s = status || ''
|
||||
if (s === 'approved') return '已同意'
|
||||
if (s === 'rejected') return '已拒绝'
|
||||
if (s === 'returned') return '已打回'
|
||||
if (s === 'pending' || s === 'running') return '待处理'
|
||||
if (s === 'done') return '无需处理'
|
||||
if (s === 'not_reached') return '未到达'
|
||||
return ''
|
||||
}
|
||||
|
||||
function personTitle(p: OaProgressPerson) {
|
||||
const parts = [p.nickName || '', statusText(p.status || ''), p.timestamp || ''].filter(Boolean)
|
||||
return parts.join(' · ')
|
||||
}
|
||||
|
||||
function dotClass(item: OaProgressChainItem) {
|
||||
const s = item.status || ''
|
||||
if (s === 'approved' || s === 'completed' || s === 'done' || s === 'submitted') return 'ok'
|
||||
@@ -275,6 +349,42 @@
|
||||
white-space: nowrap;
|
||||
background: #f1f5f9;
|
||||
border-radius: 999px;
|
||||
|
||||
&.is-ok {
|
||||
color: #059669;
|
||||
background: #ecfdf5;
|
||||
|
||||
.oa-person-chip__dot {
|
||||
background: var(--primary, #10b981);
|
||||
}
|
||||
}
|
||||
|
||||
&.is-pending {
|
||||
color: #d97706;
|
||||
background: #fff7ed;
|
||||
|
||||
.oa-person-chip__dot {
|
||||
background: #d97706;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-danger {
|
||||
color: #dc2626;
|
||||
background: #fef2f2;
|
||||
|
||||
.oa-person-chip__dot {
|
||||
background: #ef4444;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-mute {
|
||||
color: #94a3b8;
|
||||
background: #f8fafc;
|
||||
|
||||
.oa-person-chip__dot {
|
||||
background: #94a3b8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.oa-person-chip__dot {
|
||||
@@ -289,6 +399,12 @@
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.oa-person-chip__st {
|
||||
margin-left: 2px;
|
||||
font-size: 10px;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
.oa-flow-badge {
|
||||
flex-shrink: 0;
|
||||
padding: 0 5px;
|
||||
@@ -308,6 +424,11 @@
|
||||
background: #fff7ed;
|
||||
}
|
||||
|
||||
&.and {
|
||||
color: #2563eb;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
&.danger {
|
||||
color: #dc2626;
|
||||
background: #fef2f2;
|
||||
|
||||
@@ -68,6 +68,16 @@
|
||||
:disabled="disabled"
|
||||
@update:model-value="(v) => onValueChange(idx, coerceValue(rule.field, v))"
|
||||
/>
|
||||
<el-button
|
||||
class="cond-rule-editor__del"
|
||||
text
|
||||
type="danger"
|
||||
:disabled="disabled || localRules.length <= 1"
|
||||
title="删除条件"
|
||||
@click="removeRule(idx)"
|
||||
>
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-if="idx < localRules.length - 1" class="cond-rule-editor__and">且(AND)</div>
|
||||
</div>
|
||||
@@ -86,7 +96,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, watch } from 'vue'
|
||||
import { Plus } from '@element-plus/icons-vue'
|
||||
import { Delete, Plus } from '@element-plus/icons-vue'
|
||||
import {
|
||||
opsForFieldType,
|
||||
type ConditionCandidate,
|
||||
@@ -207,6 +217,12 @@
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
function removeRule(idx: number) {
|
||||
if (localRules.value.length <= 1) return
|
||||
const next = localRules.value.filter((_, i) => i !== idx)
|
||||
emitRules(next)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@@ -230,11 +246,16 @@
|
||||
|
||||
.cond-rule-editor__row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
grid-template-columns: 1fr auto 1fr auto;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.cond-rule-editor__del {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.cond-rule-editor__and {
|
||||
margin: 0 0 6px;
|
||||
color: var(--mint-text-muted, #94a3b8);
|
||||
|
||||
@@ -36,8 +36,23 @@
|
||||
<div class="flow-cond-col__title" @click.stop="emit('edit', node)">
|
||||
{{ branchTitle(g, idx) }}
|
||||
</div>
|
||||
<!-- 分支仅有结束节点时,先露出「+」才能往分支内插入 -->
|
||||
<el-dropdown
|
||||
v-if="!g.child || g.child.type === 'end'"
|
||||
trigger="click"
|
||||
@command="(cmd: string) => onAddInGroup(idx, cmd)"
|
||||
>
|
||||
<button type="button" class="flow-plus" title="在本分支添加节点">+</button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="approval">审批人</el-dropdown-item>
|
||||
<el-dropdown-item command="cc">抄送人</el-dropdown-item>
|
||||
<el-dropdown-item command="condition">条件分支</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<FlowBranch
|
||||
v-if="g.child"
|
||||
v-if="g.child && g.child.type !== 'end'"
|
||||
:node="g.child"
|
||||
:depth="depth + 1"
|
||||
:candidates="candidates"
|
||||
@@ -48,6 +63,28 @@
|
||||
<div v-else class="flow-end">流程结束</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 条件分支汇合后继续主链 -->
|
||||
<el-dropdown trigger="click" @command="(cmd: string) => onAdd(cmd)">
|
||||
<button type="button" class="flow-plus" title="在条件分支后添加节点">+</button>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="approval">审批人</el-dropdown-item>
|
||||
<el-dropdown-item command="cc">抄送人</el-dropdown-item>
|
||||
<el-dropdown-item command="condition">条件分支</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
<FlowBranch
|
||||
v-if="node.child"
|
||||
:node="node.child"
|
||||
:depth="depth"
|
||||
:candidates="candidates"
|
||||
@edit="(n) => emit('edit', n)"
|
||||
@remove="(id) => emit('remove', id)"
|
||||
@add="(payload) => emit('add', payload)"
|
||||
/>
|
||||
<div v-else class="flow-end">流程结束</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
@@ -102,7 +139,14 @@
|
||||
const emit = defineEmits<{
|
||||
edit: [node: FlowNode]
|
||||
remove: [nodeId: string]
|
||||
add: [payload: { parentId: string; type: 'approval' | 'cc' | 'condition' }]
|
||||
add: [
|
||||
payload: {
|
||||
parentId: string
|
||||
type: 'approval' | 'cc' | 'condition'
|
||||
/** 写入条件节点的第 N 个分支;缺省则写入 parent.child(汇合后主链) */
|
||||
groupIndex?: number
|
||||
}
|
||||
]
|
||||
}>()
|
||||
|
||||
function typeLabel(t: string) {
|
||||
@@ -134,6 +178,12 @@
|
||||
emit('add', { parentId: props.node.id, type: cmd })
|
||||
}
|
||||
}
|
||||
|
||||
function onAddInGroup(groupIndex: number, cmd: string) {
|
||||
if (cmd === 'approval' || cmd === 'cc' || cmd === 'condition') {
|
||||
emit('add', { parentId: props.node.id, type: cmd, groupIndex })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -459,10 +459,35 @@
|
||||
return null
|
||||
}
|
||||
|
||||
function onAdd(payload: { parentId: string; type: 'approval' | 'cc' | 'condition' }) {
|
||||
function onAdd(payload: {
|
||||
parentId: string
|
||||
type: 'approval' | 'cc' | 'condition'
|
||||
groupIndex?: number
|
||||
}) {
|
||||
const parent = findNode(root.value, payload.parentId)
|
||||
if (!parent) return
|
||||
const neu = createNode(payload.type)
|
||||
|
||||
// 写入条件节点的某一分支
|
||||
if (
|
||||
parent.type === 'condition' &&
|
||||
typeof payload.groupIndex === 'number' &&
|
||||
parent.conditionGroups?.[payload.groupIndex]
|
||||
) {
|
||||
const g = parent.conditionGroups[payload.groupIndex]
|
||||
const old = g.child || createEndNode()
|
||||
if (payload.type === 'condition') {
|
||||
const groups = neu.conditionGroups || []
|
||||
const def = groups.find((x) => x.isDefault) || groups[groups.length - 1]
|
||||
if (def) def.child = old
|
||||
} else {
|
||||
neu.child = old
|
||||
}
|
||||
g.child = neu
|
||||
commit()
|
||||
return
|
||||
}
|
||||
|
||||
const old = parent.child || createEndNode()
|
||||
if (payload.type === 'condition') {
|
||||
const groups = neu.conditionGroups || []
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** 允许「参与流程条件分支」的 FormCreate type */
|
||||
export const CONDITION_ELIGIBLE_TYPES = new Set([
|
||||
'input',
|
||||
'inputNumber',
|
||||
'number',
|
||||
'money',
|
||||
@@ -20,6 +21,7 @@ export interface ConditionCandidate {
|
||||
}
|
||||
|
||||
export function opsForFieldType(type: string): Array<{ value: ConditionOp; label: string }> {
|
||||
// 单选/下拉为离散选项,仅等于/不等于;输入框常填数字参与区间比较,与数字/金额/日期同套运算符
|
||||
if (type === 'radio' || type === 'select') {
|
||||
return [
|
||||
{ value: '==', label: '等于' },
|
||||
|
||||
Reference in new issue
Block a user