Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ui/src/assets/workflow/icon_form.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,11 @@ const formValue = ref<Dict<DynamicFormValue>>({})
`enableVisibility` 和 `leftOptions`,其中 `leftOptions` 使用 `VisibilityFieldOption[]`;公开
`validate()`、`getData()` 与 `render()`。

启用显隐设置时,配置器将 Tabs 导航与内容分开,只继承容器的最大高度,内容较少时自然撑开。
`el-scrollbar` 及其内部滚动容器使用可收缩的 Flex 布局,并覆盖默认的百分比高度;达到最大高度后
仅内容区滚动,Tabs 保持固定。普通 `MkDialog` 已提供内容最大高度,调用方不需要设置固定高度。
两个表单通过 `v-show` 切换并保持挂载,确保未选中的页签也能回填、取值和校验。

字段配置中的动态校验器和表格行表达式属于受信任的服务端协议,只允许加载可信配置;普通业务
输入不得作为脚本传入。

Expand Down
9 changes: 8 additions & 1 deletion ui/src/components/global/markdown-editor/MdEditorMagnify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@ async function submitEditorDialog() {
</MdEditor>

<MkDialog v-model="dialogVisible" :title="title" align-center>
<MdEditor v-model="dialogContent" :preview="false" :toolbars="[]" :footers="[]" class="magnify-dialog-editor" />
<MdEditor
v-model="dialogContent"
:preview="false"
:toolbars="[]"
:footers="[]"
style="height: calc(100vh - 350px)"
class="magnify-dialog-editor"
/>

<template #footer>
<el-button type="primary" @click="submitEditorDialog">确定</el-button>
Expand Down
2 changes: 0 additions & 2 deletions ui/src/components/mk-dynamics-form/Demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ const validateForm = async () => {
v-model="currentField"
:enable-visibility="true"
:left-options="visibilityFieldOptions"
label-position="top"
require-asterisk-position="right"
/>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
Expand Down
13 changes: 13 additions & 0 deletions ui/src/components/mk-dynamics-form/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,16 @@ export const dynamicFormTypeOptions = [

export type DynamicFormInputType = (typeof dynamicFormTypeOptions)[number]['value']
export type DynamicFormTypeOption = (typeof dynamicFormTypeOptions)[number]

// 引用变量为选择类字段提供选项时的格式说明。
export const referenceOptionsHelp = `变量的值必须符合:
[
{
"label": "xx",
"value": "xx",
"default": false
}
]
label: 标签 必填
value: 值 必填
default: 是否为默认值`
45 changes: 34 additions & 11 deletions ui/src/components/mk-dynamics-form/constructor/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { onMounted, ref, nextTick } from 'vue'
import { dynamicFormTypeOptions } from '@/components/mk-dynamics-form/constant'
import VisibilityConstructor from './visibility/index.vue'
import BasicInfoConstructor from './BasicInfoConstructor.vue'
import type { DynamicFormConstructorExpose, DynamicFormConstructorOption, DynamicFormConstructorState, FormField, VisibilityFieldOption, VisibilityRules } from '../type'
import type {
DynamicFormConstructorExpose,
DynamicFormConstructorOption,
DynamicFormConstructorState,
FormField,
VisibilityFieldOption,
VisibilityRules,
} from '../type'

interface VisibilityConstructorExpose {
getData: () => VisibilityRules | null
Expand All @@ -17,8 +24,20 @@ defineOptions({ name: 'MkDynamicsFormConstructor', inheritAttrs: false })
defineEmits<{ (event: 'update:modelValue', value: Partial<FormField>): void }>()

const props = withDefaults(
defineProps<{ modelValue?: Partial<FormField>; fieldTypeOptions?: DynamicFormConstructorOption[]; enableVisibility?: boolean; leftOptions?: VisibilityFieldOption[] }>(),
{ enableVisibility: false, fieldTypeOptions: () => dynamicFormTypeOptions.map((item) => ({ label: item.label, value: `${item.value}Constructor` })) },
defineProps<{
modelValue?: Partial<FormField>
// “基本信息”中可选的组件类型;不传时使用全部默认类型,value 使用带 Constructor 后缀的配置器名称。
fieldTypeOptions?: DynamicFormConstructorOption[]
// 是否展示“显隐设置”页签,默认关闭。
enableVisibility?: boolean
// “显隐设置”中条件左侧可引用的变量,启用显隐设置时使用;变量类型和选项用于匹配比较方式及值输入控件。
// 由调用方提供可引用范围,例如上游节点字段、当前字段之前的表单字段,不控制可选的组件类型。
leftOptions?: VisibilityFieldOption[]
}>(),
{
enableVisibility: false,
fieldTypeOptions: () => dynamicFormTypeOptions.map((item) => ({ label: item.label, value: `${item.value}Constructor` })),
},
)

const activeTab = ref('basic')
Expand Down Expand Up @@ -68,14 +87,18 @@ defineExpose({ getData, validate, render })
</script>

<template>
<el-tabs v-if="enableVisibility" v-model="activeTab">
<el-tab-pane label="基本信息" name="basic">
<BasicInfoConstructor ref="basicRef" v-model="formData" :input-type-list="fieldTypeOptions" v-bind="$attrs" />
</el-tab-pane>
<el-tab-pane label="显隐设置" name="visibility">
<VisibilityConstructor ref="visibilityRef" :initial-value="visibilityRules" :left-options="leftOptions" />
</el-tab-pane>
</el-tabs>
<div v-if="enableVisibility" class="flex max-h-[inherit] min-h-0 flex-col">
<el-tabs v-model="activeTab" class="shrink-0">
<el-tab-pane label="基本信息" name="basic" />
<el-tab-pane label="显隐设置" name="visibility" />
</el-tabs>

<!-- 导航固定,内容独立滚动;两个表单保持挂载,供统一回填、取值和校验。 -->
<el-scrollbar class="mk-scrollbar-right mt-4 flex h-auto! min-h-0 flex-auto flex-col" wrap-class="h-auto! min-h-0 flex-auto">
<BasicInfoConstructor v-show="activeTab === 'basic'" ref="basicRef" v-model="formData" :input-type-list="fieldTypeOptions" v-bind="$attrs" />
<VisibilityConstructor v-show="activeTab === 'visibility'" ref="visibilityRef" :initial-value="visibilityRules" :left-options="leftOptions" />
</el-scrollbar>
</div>

<BasicInfoConstructor v-else ref="basicRef" v-model="formData" :input-type-list="fieldTypeOptions" v-bind="$attrs" />
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,25 @@ onMounted(() => {

<template>
<el-form-item v-if="getModel" label="赋值方式">
<!-- // TODO 赋值方式待调整 -->
<el-radio-group v-model="formValue.default_value_assignment_method">
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content> 变量的值必须符合: JSON 格式 </template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item v-if="formValue.default_value_assignment_method === 'ref_variables'" :required="true" prop="default_value" :rules="[referenceVariableRule]">
<el-form-item
v-if="formValue.default_value_assignment_method === 'ref_variables'"
:required="true"
prop="default_value"
:rules="[referenceVariableRule]"
>
<NodeCascader ref="nodeCascaderRef" :nodeModel="model" placeholder="请选择变量" v-model="formValue.option_list" />
</el-form-item>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { referenceOptionsHelp } from '../../constant'
import { computed, onMounted, inject } from 'vue'
import MultiRow from '@/components/mk-dynamics-form/items/MultiRow.vue'
import MkFormList from '@/components/mk-form-list/index.vue'
Expand Down Expand Up @@ -86,27 +87,15 @@ onMounted(() => {

<template>
<el-form-item v-if="getModel" label="赋值方式">
<!-- // TODO 赋值方式待调整 -->
<el-radio-group @change="formValue.option_list = []" v-model="formValue.assignment_method">
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content>
变量的值必须符合:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: 标签 必填<br />
value: 值 必填<br />
default: 是否为默认值
<div class="whitespace-pre-wrap">{{ referenceOptionsHelp }}</div>
</template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { referenceOptionsHelp } from '../../constant'
import { computed, onMounted, inject } from 'vue'
import MkFormList from '@/components/mk-form-list/index.vue'
import NodeCascader from '@/workflow-canvas/core/NodeCascader.vue'
Expand Down Expand Up @@ -99,27 +100,16 @@ onMounted(() => {

<template>
<el-form-item v-if="getModel" label="赋值方式">
<!-- // TODO 赋值方式待调整 -->
<el-radio-group @change="resetOptions" v-model="formValue.assignment_method">
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content>
变量的值必须符合:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: 标签 必填<br />
value: 值 必填<br />
default: 是否为默认值
<div class="whitespace-pre-wrap">{{ referenceOptionsHelp }}</div>
</template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { referenceOptionsHelp } from '../../constant'
import { computed, onMounted, inject } from 'vue'
import RadioCard from '@/components/mk-dynamics-form/items/radio/RadioCard.vue'
import MkFormList from '@/components/mk-form-list/index.vue'
Expand Down Expand Up @@ -101,27 +102,16 @@ onMounted(() => {

<template>
<el-form-item v-if="getModel" label="赋值方式">
<!-- // TODO 赋值方式待调整 -->
<el-radio-group @change="resetOptions" v-model="formValue.assignment_method">
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content>
变量的值必须符合:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: 标签 必填<br />
value: 值 必填<br />
default: 是否为默认值
<div class="whitespace-pre-wrap">{{ referenceOptionsHelp }}</div>
</template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { referenceOptionsHelp } from '../../constant'
import { computed, onMounted, inject } from 'vue'
import RadioRow from '@/components/mk-dynamics-form/items/radio/RadioRow.vue'
import MkFormList from '@/components/mk-form-list/index.vue'
Expand Down Expand Up @@ -87,27 +88,16 @@ onMounted(() => {

<template>
<el-form-item v-if="getModel" label="赋值方式">
<!-- // TODO 赋值方式待调整 -->
<el-radio-group @change="formValue.option_list = []" v-model="formValue.assignment_method">
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content>
变量的值必须符合:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: 标签 必填<br />
value: 值 必填<br />
default: 是否为默认值
<div class="whitespace-pre-wrap">{{ referenceOptionsHelp }}</div>
</template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { referenceOptionsHelp } from '../../constant'
import type { DynamicFormConstructorOption, DynamicFormValidatorCallback, DynamicFormValue } from '../../type'
import { computed, onMounted, inject } from 'vue'
import MkFormList from '@/components/mk-form-list/index.vue'
Expand Down Expand Up @@ -101,26 +102,15 @@ onMounted(() => {
<template>
<el-form-item v-if="getModel" label="赋值方式">
<el-radio-group @change="resetOptions" v-model="formValue.assignment_method">
<!-- // TODO 赋值方式待调整 -->
<el-radio :value="item.value" v-for="(item, index) in assignmentMethodOptions" :key="index">
<span class="flex align-center">
<span class="flex items-center gap-1">
{{ item.label }}

<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content>
变量的值必须符合:<br />
[<br />
{<br />
"label": "xx",<br />
"value": "xx",<br />
"default": false<br />
}<br />
]<br />
label: 标签 必填<br />
value: 值 必填<br />
default: 是否为默认值
<div class="whitespace-pre-wrap">{{ referenceOptionsHelp }}</div>
</template>
<MkIcon name="icon_info_outlined"></MkIcon>
<MkIcon name="icon_info_outlined" class="text-N600!"></MkIcon>
</el-tooltip>
</span>
</el-radio>
Expand All @@ -143,7 +133,7 @@ onMounted(() => {
<el-form-item
:label="index === 0 ? '标签' : ''"
:prop="`option_list.${index}.label`"
:rules="[{ required: formValue.required, message: '请输入标签', trigger: ['blur', 'change'] }]"
:rules="[{ required: formValue.required, message: '请输入标签', trigger: ['blur', 'change'] }]"
class="flex-1 small"
>
<el-input v-model="option.label" placeholder="请输入标签" />
Expand Down
Loading
Loading