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
Ryan Wang 2023-05-25 22:38:19 +08:00 committed by GitHub
parent 537d511cc0
commit 6dd98d2c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 3 deletions

View File

@ -16,6 +16,9 @@
- 参数
1. accepts允许上传的文件类型`image/*`
- `repeater`: 定义一个对象集合,可以让使用者可视化的操作集合。
- 参数
1. min: 最小数量,默认为 `0`
2. max: 最大数量,默认为 `Infinity`,即无限制。
- `menuCheckbox`:选择一组菜单
- `menuRadio`:选择一个菜单
- `menuItemSelect`:选择菜单项

View File

@ -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>

View File

@ -23,6 +23,7 @@ export const repeater: FormKitTypeDefinition = {
messages(message("$message.value"))
),
type: "list",
props: ["min", "max"],
library: {
Repeater: Repeater,
},