mirror of https://github.com/halo-dev/halo
feat: add min and max props for repeater input (#3965)
#### What type of PR is this? /area console /kind feature /milestone 2.6.x #### What this PR does / why we need it: Console 端的 FormKit Repeater 输入框支持 min 和 max 参数用于限制项目数量。 <img width="630" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/541da770-0439-4731-a796-a58277c33e05"> #### Which issue(s) this PR fixes: Fixes #3449 #### Special notes for your reviewer: 定义方式: ```yaml - $formkit: repeater name: test_repeater label: 测试 Repeater min: 2 max: 3 children: - $formkit: text name: test_text label: 测试 Text - $formkit: select name: test_select label: 测试 Select options: - value: prose-gray label: prose-gray - value: prose-slate label: prose-slate - value: prose-zinc label: prose-zinc - value: prose-neutral label: prose-neutral - value: prose-stone label: prose-stone ``` #### Does this PR introduce a user-facing change? ```release-note Console 端的 FormKit Repeater 输入框支持 min 和 max 参数用于限制项目数量。 ```pull/3983/head^2
parent
537d511cc0
commit
6dd98d2c0c
|
@ -16,6 +16,9 @@
|
|||
- 参数
|
||||
1. accepts:允许上传的文件类型,如:`image/*`
|
||||
- `repeater`: 定义一个对象集合,可以让使用者可视化的操作集合。
|
||||
- 参数
|
||||
1. min: 最小数量,默认为 `0`
|
||||
2. max: 最大数量,默认为 `Infinity`,即无限制。
|
||||
- `menuCheckbox`:选择一组菜单
|
||||
- `menuRadio`:选择一个菜单
|
||||
- `menuItemSelect`:选择菜单项
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
import type { FormKitFrameworkContext } from "@formkit/core";
|
||||
import { group } from "@formkit/inputs";
|
||||
import type { PropType } from "vue";
|
||||
import { onMounted } from "vue";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
|
||||
const props = defineProps({
|
||||
|
@ -18,6 +19,9 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
const min = Number(props.context.min) || 0;
|
||||
const max = Number(props.context.max) || Infinity;
|
||||
|
||||
const handleAppend = (index: number) => {
|
||||
const value = cloneDeep(props.context._value);
|
||||
value.splice(index + 1, 0, {});
|
||||
|
@ -25,6 +29,10 @@ const handleAppend = (index: number) => {
|
|||
};
|
||||
|
||||
const handleRemove = (index: number) => {
|
||||
if (props.context._value?.length <= min) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = cloneDeep(props.context._value);
|
||||
value.splice(index, 1);
|
||||
props.context.node.input(value);
|
||||
|
@ -49,6 +57,18 @@ const handleMoveDown = (index: number) => {
|
|||
value.splice(index + 1, 0, value.splice(index, 1)[0]);
|
||||
props.context.node.input(value);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
const value = cloneDeep(props.context._value);
|
||||
const differenceCount = min - value?.length || 0;
|
||||
|
||||
if (differenceCount > 0) {
|
||||
for (let i = 0; i < differenceCount; i++) {
|
||||
value.push({});
|
||||
}
|
||||
props.context.node.input(value);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -73,7 +93,8 @@ const handleMoveDown = (index: number) => {
|
|||
<li
|
||||
class="cursor-pointer text-gray-500 transition-all hover:text-primary"
|
||||
:class="{
|
||||
'cursor-not-allowed opacity-50 hover:!text-gray-500': index === 0,
|
||||
'!cursor-not-allowed opacity-50 hover:!text-gray-500':
|
||||
index === 0,
|
||||
}"
|
||||
>
|
||||
<IconArrowUpCircleLine
|
||||
|
@ -83,6 +104,10 @@ const handleMoveDown = (index: number) => {
|
|||
</li>
|
||||
<li
|
||||
class="cursor-pointer text-gray-500 transition-all hover:text-primary"
|
||||
:class="{
|
||||
'!cursor-not-allowed opacity-50 hover:!text-gray-500':
|
||||
context._value?.length <= min,
|
||||
}"
|
||||
>
|
||||
<IconCloseCircle class="h-5 w-5" @click="handleRemove(index)" />
|
||||
</li>
|
||||
|
@ -94,7 +119,7 @@ const handleMoveDown = (index: number) => {
|
|||
<li
|
||||
class="cursor-pointer text-gray-500 transition-all hover:text-primary"
|
||||
:class="{
|
||||
'cursor-not-allowed opacity-50 hover:!text-gray-500':
|
||||
'!cursor-not-allowed opacity-50 hover:!text-gray-500':
|
||||
index === context._value.length - 1,
|
||||
}"
|
||||
>
|
||||
|
@ -108,7 +133,11 @@ const handleMoveDown = (index: number) => {
|
|||
</li>
|
||||
</ul>
|
||||
<div :class="context.classes.add">
|
||||
<VButton type="secondary" @click="handleAppend(context._value.length)">
|
||||
<VButton
|
||||
:disabled="context._value?.length >= max"
|
||||
type="secondary"
|
||||
@click="handleAppend(context._value.length)"
|
||||
>
|
||||
<template #icon>
|
||||
<IconAddCircle class="h-full w-full" />
|
||||
</template>
|
||||
|
|
|
@ -23,6 +23,7 @@ export const repeater: FormKitTypeDefinition = {
|
|||
messages(message("$message.value"))
|
||||
),
|
||||
type: "list",
|
||||
props: ["min", "max"],
|
||||
library: {
|
||||
Repeater: Repeater,
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue