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
5 changes: 4 additions & 1 deletion ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -712,7 +712,10 @@ const roleSettings = defineModel<{ roleId: string; workspaceIds: string[] }[]>({
</MkFormList>
```

`addText` 设置添加按钮文案。删除按钮及第一行与后续行的对齐由组件统一处理。
`addText` 设置添加按钮文案,`showAddButton` 默认为 `true`;添加入口由业务布局单独提供时传入
`:show-add-button="false"`。`firstRowHasLabel` 默认为 `true`:第一行删除按钮使用 `mt-8`,后续行
使用 `mt-0.5`;并列表单项没有 label 时传入 `:first-row-has-label="false"`。删除成功后通过
`remove(item, index)` 返回被删除的行数据和原索引,业务组件可处理关联状态,不需要再次修改列表。

### MkSearchList

Expand Down
4 changes: 2 additions & 2 deletions ui/src/components/mk-dynamics-form/Demo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ const validateForm = async () => {
</div>

<!-- 添加/编辑字段弹窗 -->
<el-dialog
<MkDialog
v-model="dialogVisible"
:title="isEdit ? '编辑字段' : '添加字段'"
width="600px"
Expand All @@ -196,5 +196,5 @@ const validateForm = async () => {
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submitField">确定</el-button>
</template>
</el-dialog>
</MkDialog>
</template>
7 changes: 3 additions & 4 deletions ui/src/components/mk-dynamics-form/FormItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ const emit = defineEmits<{
}>()

const loading = ref(false)
const fieldComponentRef = ref<DynamicFieldComponent>()
const componentFormRef = ref<DynamicFieldComponent>()
const triggerSubscriptions: Array<{
event: string
handler: (value: unknown) => void
Expand Down Expand Up @@ -188,7 +188,7 @@ onBeforeUnmount(() => {

function validate() {
if (props.formField.trigger_type === 'CHILD_FORMS') {
return fieldComponentRef.value?.validate?.() ?? Promise.resolve()
return componentFormRef.value?.validate?.() ?? Promise.resolve()
}
return Promise.resolve()
}
Expand All @@ -203,7 +203,6 @@ defineExpose({ validate })
:style="formItemStyle"
:prop="formField.field"
:rules="validationRules"
:class="formField.required_asterisk ? 'hide-asterisk' : ''"
>
<template v-if="formField.label" #label>
<FormItemLabel v-if="isString(formField.label)" :form-field="formField" />
Expand All @@ -219,7 +218,7 @@ defineExpose({ validate })
<component
:is="getFieldComponent(formField.input_type)"
v-if="getFieldComponent(formField.input_type)"
ref="fieldComponentRef"
ref="componentFormRef"
v-model="itemValue"
:view="view"
:form-field="formField"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,9 @@ const ruleFormRef = ref<FormInstance>()
const componentFormRef = ref<DynamicFormConstructorExpose>()
const rules: FormRules<DynamicFormConstructorState> = {
label: [{ required: true, message: '显示名称 为必填属性' }],
field: [{ required: true, message: '参数 为必填属性' }],
required: [{ required: true, message: '是否必填 为必填属性' }],
input_type: [{ required: true, message: '组建类型 为必填属性' }],
label: [{ required: true, message: '请输入显示名称' }],
field: [{ required: true, message: '请输入参数' }],
input_type: [{ required: true, message: '请选择组件类型' }],
}
const validate = () => (ruleFormRef.value ? ruleFormRef.value.validate() : Promise.resolve())
Expand Down Expand Up @@ -102,7 +101,7 @@ const updateForm = (value: DynamicFormConstructorState) => {
defineExpose({ validate, getData, render })
</script>
<template>
<el-form @submit.prevent ref="ruleFormRef" class="mb-24" label-width="auto" :model="form">
<el-form @submit.prevent ref="ruleFormRef" label-width="auto" :model="form">
<el-form-item label="参数" :required="true" prop="field" :rules="rules.field">
<el-input v-model="form.field" :maxlength="64" placeholder="请输入参数" show-word-limit />
</el-form-item>
Expand All @@ -117,13 +116,7 @@ defineExpose({ validate, getData, render })
placeholder="请输入参数提示说明"
/>
</el-form-item>
<el-form-item
label="是否必填"
:required="true"
prop="required"
:rules="rules.required"
@click.prevent
>
<el-form-item label="是否必填" prop="required" @click.prevent>
<el-switch v-model="form.required" :active-value="true" :inactive-value="false" />
</el-form-item>
<el-form-item label="组件类型" :required="true" prop="input_type" :rules="rules.input_type">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
<script setup lang="ts">
import type { DynamicFormValue } from '../../type'
import { computed, onBeforeMount } from 'vue'
const dateTypeOptions = [
import { dateFormat, datetimeFormat } from '@/utils/time'
import type { DynamicFormConstructorOption, DynamicFormValue } from '../../type'

type DatePickerType = 'year' | 'month' | 'date' | 'datetime'
type DateFormatOption = Pick<DynamicFormConstructorOption, 'value'>

const defaultDatePickerType: DatePickerType = 'datetime'

const dateTypeOptions: DynamicFormConstructorOption[] = [
{
label: '年',
value: 'year',
Expand All @@ -19,28 +26,32 @@ const dateTypeOptions = [
value: 'datetime',
},
]
const dateFormatOptions: DynamicFormValue = {
const dateFormatOptions: Record<DatePickerType, DateFormatOption[]> = {
year: [{ value: 'YYYY' }],
month: [{ value: 'YYYY-MM' }],
date: [{ value: 'YYYY-MM-DD' }],
datetime: [{ value: 'YYYY-MM-DD HH:mm:ss' }],
}

const padDatePart = (value: number) => String(value).padStart(2, '0')
const formatCurrentDate = (format: string) => {
const getCurrentDateValue = (type: DatePickerType) => {
const now = new Date()
return format
.replace('YYYY', String(now.getFullYear()))
.replace('MM', padDatePart(now.getMonth() + 1))
.replace('DD', padDatePart(now.getDate()))
.replace('HH', padDatePart(now.getHours()))
.replace('mm', padDatePart(now.getMinutes()))
.replace('ss', padDatePart(now.getSeconds()))
if (type === 'datetime') {
return datetimeFormat(now) as string
}

const currentDate = dateFormat(now) as string
if (type === 'year') return currentDate.slice(0, 4)
if (type === 'month') return currentDate.slice(0, 7)
return currentDate
}

const handleDateTypeChange = () => {
formValue.value.format = dateFormatOptions[formValue.value.type][0].value
formValue.value.default_value = formatCurrentDate(formValue.value.format)
const datePickerType = formValue.value.type as DatePickerType
const defaultFormat = dateFormatOptions[datePickerType][0]?.value
if (!defaultFormat) return

formValue.value.format = defaultFormat
formValue.value.default_value = getCurrentDateValue(datePickerType)
}
const props = defineProps<{
modelValue: DynamicFormValue
Expand All @@ -55,6 +66,13 @@ const formValue = computed({
},
})

const defaultValueUnselected = computed({
get: () => formValue.value.show_default_value === false,
set: (value: boolean) => {
formValue.value.show_default_value = !value
},
})

const getData = () => {
return {
input_type: 'DatePicker',
Expand All @@ -74,77 +92,77 @@ const render = (formData: DynamicFormValue) => {
}
defineExpose({ getData, render })
onBeforeMount(() => {
formValue.value.type = 'datetime'
formValue.value.type = defaultDatePickerType
formValue.value.format = 'YYYY-MM-DD HH:mm:ss'
formValue.value.default_value = formatCurrentDate(formValue.value.format)
formValue.value.default_value = getCurrentDateValue(defaultDatePickerType)
if (formValue.value.show_default_value === undefined) {
formValue.value.show_default_value = true
}
})
</script>

<template>
<el-form-item label="时间类型" required>
<el-select @change="handleDateTypeChange" v-model="formValue.type" placeholder="请选择时间类型">
<el-option
v-for="inputTypeOption in dateTypeOptions"
:key="inputTypeOption.value"
:label="inputTypeOption.label"
:value="inputTypeOption.value"
/>
</el-select>
</el-form-item>
<el-form-item label="格式" required>
<el-select
v-model="formValue.format"
filterable
default-first-option
allow-create
placeholder="请选择格式"
>
<el-option
v-for="inputTypeOption in dateFormatOptions[formValue.type]"
:key="inputTypeOption.value"
:label="inputTypeOption.value"
:value="inputTypeOption.value"
/>
</el-select>
</el-form-item>
<div class="flex gap-4">
<el-form-item class="min-w-0 flex-1" label="时间类型" required>
<el-select
v-model="formValue.type"
placeholder="请选择时间类型"
@change="handleDateTypeChange"
>
<el-option
v-for="inputTypeOption in dateTypeOptions"
:key="inputTypeOption.value"
:label="inputTypeOption.label"
:value="inputTypeOption.value"
/>
</el-select>
</el-form-item>
<el-form-item class="min-w-0 flex-1" label="格式" required>
<el-select
v-model="formValue.format"
filterable
default-first-option
allow-create
placeholder="请选择格式"
>
<el-option
v-for="inputTypeOption in dateFormatOptions[formValue.type as DatePickerType]"
:key="inputTypeOption.value"
:label="inputTypeOption.value"
:value="inputTypeOption.value"
/>
</el-select>
</el-form-item>
</div>
<el-form-item
class="defaultValueItem"
class="mk-hide-asterisk"
:required="formValue.required"
prop="default_value"
label="默认值"
:rules="
formValue.required
? [
{
required: true,
message: '默认值为必填属性',
message: '请输入默认值',
},
]
: []
"
>
<div class="defaultValueCheckbox">
<el-checkbox v-model="formValue.show_default_value" label="显示默认值" />
</div>
<template #label>
<div class="flex-between">
<span :class="formValue.required ? 'mk-required' : ''">默认值</span>
<el-checkbox v-model="defaultValueUnselected" label="未选中项" />
</div>
</template>
<el-date-picker
v-model="formValue.default_value"
:type="formValue.type"
placeholder="选择日期"
:format="formValue.format"
:value-format="formValue.format"
class="w-full!"
/>
</el-form-item>
</template>
<style lang="scss" scoped>
.defaultValueItem {
position: relative;
.defaultValueCheckbox {
position: absolute;
right: 0;
top: -35px;
}
}
</style>
<style lang="scss" scoped></style>
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const referenceVariableRule = {
required: true,
validator: (_rule: unknown, value: DynamicFormValue, callback: DynamicFormValidatorCallback) => {
if (!(Array.isArray(value) && value.length > 1)) {
callback('引用变量必填')
callback('请输入引用变量')
}
return true
Expand All @@ -99,30 +99,20 @@ onMounted(() => {
</script>

<template>
<el-form-item v-if="getModel">
<template #label>
<div class="flex-between">赋值方式</div>
</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">
{{ item.label }}

<el-row class="w-full">
<el-radio-group v-model="formValue.default_value_assignment_method">
<el-radio
:value="item.value"
size="large"
v-for="(item, index) in assignmentMethodOptions"
:key="index"
>
<span class="flex align-center">
{{ item.label }}

<el-tooltip effect="dark" placement="right" v-if="item.value === 'ref_variables'">
<template #content> 变量的值必须符合: JSON 格式 </template>
<MkIcon name="icon_warning_filled" class="app-warning-icon ml-4"></MkIcon>
</el-tooltip>
</span>
</el-radio>
</el-radio-group>
</el-row>
<el-tooltip placement="right" v-if="item.value === 'ref_variables'">
<template #content> 变量的值必须符合: JSON 格式 </template>
<MkIcon name="icon_info_outlined"></MkIcon>
</el-tooltip>
</span>
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
v-if="formValue.default_value_assignment_method === 'ref_variables'"
Expand All @@ -140,26 +130,20 @@ onMounted(() => {
</el-form-item>

<el-form-item
class="defaultValueItem"
label="默认值"
class="mk-hide-asterisk"
:required="formValue.required"
v-if="formValue.default_value_assignment_method === 'custom'"
prop="default_value"
:rules="[defaultValueRule]"
>
<div class="defaultValueCheckbox">
<el-checkbox v-model="formValue.show_default_value" label="显示默认值" />
</div>
<template #label>
<div class="flex-between">
<span :class="formValue.required ? 'mk-required' : ''">默认值</span>
<el-checkbox v-model="formValue.show_default_value" label="显示默认值" />
</div>
</template>
<JsonInput ref="jsonInputRef" v-model="formValue.default_value"> </JsonInput>
</el-form-item>
</template>
<style lang="scss" scoped>
.defaultValueItem {
position: relative;
.defaultValueCheckbox {
position: absolute;
right: 0;
top: -35px;
}
}
</style>

<style lang="scss" scoped></style>
Loading
Loading