From d441e4731e1a19df6abb44fc4701c38004d71ce4 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Mon, 24 Apr 2023 15:45:44 +0800 Subject: [PATCH] feat: add accepts and min,max props for attachment selector modal component (#3827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind feature /area console /milestone 2.5.x #### What this PR does / why we need it: 附件选择组件(AttachmentSelectorModal)支持 accepts、min、max 参数用来限定文件格式和数量。同时也为 FormKit 的 attachment 类型添加同样的参数。 另外,Console 的部分表单也跟着做了修改,包括:文章/页面设置中的封面图、系统设置中的 Favicon 和 Logo、分类/标签编辑表单中的封面图、用户资料的头像。 FormKit 中使用: 1. Component ```vue ``` 2. Schema ```yaml - $formkit: attachment name: cover accepts: - 'image/*' ``` #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3800 #### Special notes for your reviewer: 测试方式: 1. 按照上述 FormKit 中的使用方式,自行在主题或者插件配置文件中测试。 2. 测试 Console 中修改的表单:文章/页面设置中的封面图、系统设置中的 Favicon 和 Logo、分类/标签编辑表单中的封面图、用户资料的头像。(均设置为仅允许选择图片(image/*)和最多选择一个(max=1))。 #### Does this PR introduce a user-facing change? ```release-note Console 端的附件选择组件支持 accepts、min、max 参数用来限定文件格式和数量。 ``` --- .../resources/extensions/system-setting.yaml | 4 ++ console/docs/custom-formkit-input/README.md | 2 + .../inputs/attachment/AttachmentInput.vue | 3 + .../src/formkit/inputs/attachment/index.ts | 2 +- .../components/AttachmentFileTypeIcon.vue | 2 +- .../components/AttachmentSelectorModal.vue | 58 ++++++++++++++----- .../CoreSelectorProvider.vue | 28 ++++++++- .../components/SinglePageSettingModal.vue | 1 + .../components/CategoryEditingModal.vue | 1 + .../posts/components/PostSettingModal.vue | 1 + .../posts/tags/components/TagEditingModal.vue | 1 + .../users/components/UserEditingModal.vue | 1 + .../src/utils/__tests__/media-type.spec.ts | 44 ++++++++++++++ console/src/utils/media-type.ts | 9 +++ 14 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 console/src/utils/__tests__/media-type.spec.ts create mode 100644 console/src/utils/media-type.ts diff --git a/application/src/main/resources/extensions/system-setting.yaml b/application/src/main/resources/extensions/system-setting.yaml index cd7aa58aa..f287d1274 100644 --- a/application/src/main/resources/extensions/system-setting.yaml +++ b/application/src/main/resources/extensions/system-setting.yaml @@ -17,9 +17,13 @@ spec: - $formkit: attachment label: Logo name: logo + accepts: + - 'image/*' - $formkit: attachment label: Favicon name: favicon + accepts: + - 'image/*' - group: post label: 文章设置 formSchema: diff --git a/console/docs/custom-formkit-input/README.md b/console/docs/custom-formkit-input/README.md index 39d1084ca..7a54ec6ab 100644 --- a/console/docs/custom-formkit-input/README.md +++ b/console/docs/custom-formkit-input/README.md @@ -13,6 +13,8 @@ 1. language: 目前支持 `yaml`, `html`, `css`, `javascript`, `json` 2. height: 编辑器高度,如:`100px` - `attachment`: 附件选择 + - 参数 + 1. accepts:允许上传的文件类型,如:`image/*` - `repeater`: 定义一个对象集合,可以让使用者可视化的操作集合。 - `menuCheckbox`:选择一组菜单 - `menuRadio`:选择一个菜单 diff --git a/console/src/formkit/inputs/attachment/AttachmentInput.vue b/console/src/formkit/inputs/attachment/AttachmentInput.vue index 53acbecad..15e694262 100644 --- a/console/src/formkit/inputs/attachment/AttachmentInput.vue +++ b/console/src/formkit/inputs/attachment/AttachmentInput.vue @@ -56,6 +56,9 @@ const onAttachmentSelect = (attachments: AttachmentLike[]) => { diff --git a/console/src/formkit/inputs/attachment/index.ts b/console/src/formkit/inputs/attachment/index.ts index bdc7253ed..ba74535ed 100644 --- a/console/src/formkit/inputs/attachment/index.ts +++ b/console/src/formkit/inputs/attachment/index.ts @@ -4,7 +4,7 @@ import AttachmentInput from "./AttachmentInput.vue"; export const attachment = createInput(AttachmentInput, { type: "input", - props: [], + props: ["accepts"], forceTypeProp: "text", features: [initialValue], }); diff --git a/console/src/modules/contents/attachments/components/AttachmentFileTypeIcon.vue b/console/src/modules/contents/attachments/components/AttachmentFileTypeIcon.vue index fd54e6b5c..125b58a17 100644 --- a/console/src/modules/contents/attachments/components/AttachmentFileTypeIcon.vue +++ b/console/src/modules/contents/attachments/components/AttachmentFileTypeIcon.vue @@ -109,7 +109,7 @@ const iconClass = computed(() => { {{ getExtname }} diff --git a/console/src/modules/contents/attachments/components/AttachmentSelectorModal.vue b/console/src/modules/contents/attachments/components/AttachmentSelectorModal.vue index ef411f811..8005c917b 100644 --- a/console/src/modules/contents/attachments/components/AttachmentSelectorModal.vue +++ b/console/src/modules/contents/attachments/components/AttachmentSelectorModal.vue @@ -1,6 +1,6 @@ diff --git a/console/src/modules/contents/attachments/components/selector-providers/CoreSelectorProvider.vue b/console/src/modules/contents/attachments/components/selector-providers/CoreSelectorProvider.vue index 64322478e..f5291e72b 100644 --- a/console/src/modules/contents/attachments/components/selector-providers/CoreSelectorProvider.vue +++ b/console/src/modules/contents/attachments/components/selector-providers/CoreSelectorProvider.vue @@ -22,13 +22,20 @@ import AttachmentUploadModal from "../AttachmentUploadModal.vue"; import AttachmentFileTypeIcon from "../AttachmentFileTypeIcon.vue"; import AttachmentDetailModal from "../AttachmentDetailModal.vue"; import AttachmentGroupList from "../AttachmentGroupList.vue"; +import { matchMediaTypes } from "@/utils/media-type"; -withDefaults( +const props = withDefaults( defineProps<{ selected: AttachmentLike[]; + accepts?: string[]; + min?: number; + max?: number; }>(), { selected: () => [], + accepts: () => ["*/*"], + min: undefined, + max: undefined, } ); @@ -66,6 +73,23 @@ const handleOpenDetail = (attachment: Attachment) => { selectedAttachment.value = attachment; detailVisible.value = true; }; + +const isDisabled = (attachment: Attachment) => { + const isMatchMediaType = matchMediaTypes( + attachment.spec.mediaType || "*/*", + props.accepts + ); + + if ( + props.max !== undefined && + props.max <= selectedAttachments.value.size && + !isChecked(attachment) + ) { + return true; + } + + return !isMatchMediaType; +};