diff --git a/apps/web-antdv-next/src/adapter/component/index.ts b/apps/web-antdv-next/src/adapter/component/index.ts index 068b04b87..470b9e455 100644 --- a/apps/web-antdv-next/src/adapter/component/index.ts +++ b/apps/web-antdv-next/src/adapter/component/index.ts @@ -72,6 +72,7 @@ import { Checkbox as CheckboxComponent, CheckboxGroup as CheckboxGroupComponent, DatePicker as DatePickerComponent, + DateRangePicker as RangePickerComponent, Divider as DividerComponent, Image as ImageComponent, ImagePreviewGroup, @@ -84,7 +85,6 @@ import { notification, Radio as RadioComponent, RadioGroup as RadioGroupComponent, - DateRangePicker as RangePickerComponent, Rate as RateComponent, Select as SelectComponent, Space as SpaceComponent, @@ -279,9 +279,9 @@ async function previewImage( { class: 'hidden', preview: { - open: visible.value, + visible: visible.value, current: currentIndex, - onOpenChange: (value: boolean) => { + onVisibleChange: (value: boolean) => { visible.value = value; if (!value) { setTimeout(() => { @@ -366,7 +366,7 @@ function cropImage(file: File, aspectRatio: string | undefined) { closable: false, cancelText: $t('common.cancel'), okText: $t('ui.crop.confirm'), - destroyOnHidden: true, + destroyOnClose: true, onOk: async () => { const cropper = cropperRef.value; if (!cropper) { @@ -625,7 +625,6 @@ export type ComponentType = | 'Space' | 'Switch' | 'TextArea' - | 'TextArea' | 'TimePicker' | 'TimeRangePicker' | 'TreeSelect' @@ -676,13 +675,13 @@ async function initComponentAdapter() { fieldNames: { label: 'label', value: 'value', children: 'children' }, loadingSlot: 'suffixIcon', modelPropName: 'value', - visibleEvent: 'onOpenChange', + visibleEvent: 'onVisibleChange', }), ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', { component: Select, loadingSlot: 'suffixIcon', modelPropName: 'value', - visibleEvent: 'onOpenChange', + visibleEvent: 'onVisibleChange', }), ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', { component: TreeSelect, @@ -690,7 +689,7 @@ async function initComponentAdapter() { loadingSlot: 'suffixIcon', modelPropName: 'value', optionsPropName: 'treeData', - visibleEvent: 'onOpenChange', + visibleEvent: 'onVisibleChange', }), AutoComplete, Cascader, @@ -744,7 +743,7 @@ async function initComponentAdapter() { copyPreferencesSuccess: (title, content) => { notification.success({ description: content, - title, + message: title, placement: 'bottomRight', }); }, diff --git a/apps/web-antdv-next/src/adapter/form.ts b/apps/web-antdv-next/src/adapter/form.ts index b386c3860..0d5bb167b 100644 --- a/apps/web-antdv-next/src/adapter/form.ts +++ b/apps/web-antdv-next/src/adapter/form.ts @@ -65,5 +65,6 @@ const useVbenForm = useForm; export { initSetupVbenForm, useVbenForm, z }; +export type VbenFormApi = ReturnType[1]; // add by 芋艿:用于 data.ts 表单 schema 内调用 setFieldValue export type VbenFormSchema = FormSchema; export type VbenFormProps = FormProps; diff --git a/apps/web-antdv-next/src/components/form-create/rules/use-area-select-rule.ts b/apps/web-antdv-next/src/components/form-create/rules/use-area-select-rule.ts index b118a1799..75c13a540 100644 --- a/apps/web-antdv-next/src/components/form-create/rules/use-area-select-rule.ts +++ b/apps/web-antdv-next/src/components/form-create/rules/use-area-select-rule.ts @@ -21,7 +21,7 @@ export function useAreaSelectRule() { title: label, info: '', $required: false, - modelField: 'value', // 特殊:ele 里是 model-value,antd 里是 value + modelField: 'value', // Ant Design Vue 组件使用 value;web-ele 自定义组件使用默认 modelValue }; }, props(_: any, { t }: any) { diff --git a/apps/web-antdv-next/src/components/form-create/rules/use-dict-select.ts b/apps/web-antdv-next/src/components/form-create/rules/use-dict-select.ts index 08171a24b..3b77092b7 100644 --- a/apps/web-antdv-next/src/components/form-create/rules/use-dict-select.ts +++ b/apps/web-antdv-next/src/components/form-create/rules/use-dict-select.ts @@ -39,7 +39,7 @@ export function useDictSelectRule() { title: label, info: '', $required: false, - modelField: 'value', // 特殊:ele 里是 model-value,antd 里是 value + modelField: 'value', // Ant Design Vue 组件使用 value;web-ele 自定义组件使用默认 modelValue }; }, props(_: any, { t }: any) { diff --git a/apps/web-antdv-next/src/components/form-create/rules/use-iframe-rule.ts b/apps/web-antdv-next/src/components/form-create/rules/use-iframe-rule.ts index 39d26d766..cb70c0720 100644 --- a/apps/web-antdv-next/src/components/form-create/rules/use-iframe-rule.ts +++ b/apps/web-antdv-next/src/components/form-create/rules/use-iframe-rule.ts @@ -21,7 +21,7 @@ export function useIframeRule() { title: label, info: '', $required: false, - modelField: 'value', // 特殊:ele 里是 model-value,antd 里是 value + modelField: 'value', // Ant Design Vue 组件使用 value;web-ele 自定义组件使用默认 modelValue }; }, props(_: any, { t }: any) { diff --git a/apps/web-antdv-next/src/components/shortcut-date-range-picker/shortcut-date-range-picker.vue b/apps/web-antdv-next/src/components/shortcut-date-range-picker/shortcut-date-range-picker.vue index da1ef99e4..df70a42fb 100644 --- a/apps/web-antdv-next/src/components/shortcut-date-range-picker/shortcut-date-range-picker.vue +++ b/apps/web-antdv-next/src/components/shortcut-date-range-picker/shortcut-date-range-picker.vue @@ -3,7 +3,8 @@ import type { Dayjs } from 'dayjs'; import { onMounted, ref } from 'vue'; -import { Radio, RadioGroup } from 'antdv-next'; +import { DatePicker, Radio, RadioGroup } from 'antdv-next'; +import dayjs from 'dayjs'; import { getRangePickerDefaultProps } from '#/utils/rangePickerProps'; @@ -19,8 +20,20 @@ const times = ref<[Dayjs, Dayjs]>(); // 日期范围 const rangePickerProps = getRangePickerDefaultProps(); const timeRangeOptions = [ rangePickerProps.presets[3]!, // 昨天 - rangePickerProps.presets[1]!, // 最近 7 天 - rangePickerProps.presets[2]!, // 最近 30 天 + { + label: rangePickerProps.presets[1]!.label, + value: [ + dayjs().subtract(7, 'day').startOf('day'), + dayjs().subtract(1, 'day').endOf('day'), + ], + }, + { + label: rangePickerProps.presets[2]!.label, + value: [ + dayjs().subtract(30, 'day').startOf('day'), + dayjs().subtract(1, 'day').endOf('day'), + ], + }, ]; const timeRangeType = ref(timeRangeOptions[1]!.label); // 默认选中第一个选项 @@ -75,7 +88,7 @@ onMounted(() => { {{ option.label }} - import type { UploadFile, UploadProps } from 'antdv-next'; +import type { UploadRequestOption } from 'antdv-next/lib/vc-upload/interface'; import type { FileUploadProps } from './typing'; @@ -16,8 +17,6 @@ import { Button, message, Upload } from 'antdv-next'; import { UploadResultStatus } from './typing'; import { useUpload, useUploadType } from './use-upload'; -type UploadRequestOption = any; - defineOptions({ name: 'FileUpload', inheritAttrs: false }); const props = withDefaults(defineProps(), { @@ -33,6 +32,7 @@ const props = withDefaults(defineProps(), { multiple: false, api: undefined, resultField: '', + returnText: false, showDescription: false, }); const emit = defineEmits([ @@ -148,9 +148,6 @@ function handleUploadError(error: any) { * @returns 是否允许上传 */ async function beforeUpload(file: File) { - const fileContent = await file.text(); - emit('returnText', fileContent); - // 检查文件数量限制 if (fileList.value!.length >= props.maxNumber) { message.error($t('ui.upload.maxNumber', [props.maxNumber])); @@ -177,6 +174,10 @@ async function beforeUpload(file: File) { // 只有在验证通过后才增加计数器 uploadNumber.value++; + if (props.returnText) { + const fileContent = await file.text(); + emit('returnText', fileContent); + } return true; } diff --git a/apps/web-antdv-next/src/components/upload/input-upload.vue b/apps/web-antdv-next/src/components/upload/input-upload.vue index 7fd43320f..0ab67425b 100644 --- a/apps/web-antdv-next/src/components/upload/input-upload.vue +++ b/apps/web-antdv-next/src/components/upload/input-upload.vue @@ -58,6 +58,7 @@ const textareaProps = computed(() => { const fileUploadProps = computed(() => { return { ...props.fileUploadProps, + returnText: true, }; }); diff --git a/apps/web-antdv-next/src/components/upload/typing.ts b/apps/web-antdv-next/src/components/upload/typing.ts index f3c16bc4d..990aa7d8a 100644 --- a/apps/web-antdv-next/src/components/upload/typing.ts +++ b/apps/web-antdv-next/src/components/upload/typing.ts @@ -27,6 +27,7 @@ export interface FileUploadProps { maxSize?: number; // 文件最大多少MB multiple?: boolean; // 是否支持多选 resultField?: string; // support xxx.xxx.xx + returnText?: boolean; // 是否返回文件文本内容 showDescription?: boolean; // 是否显示下面的描述 value?: string | string[]; } diff --git a/apps/web-antdv-next/src/layouts/basic.vue b/apps/web-antdv-next/src/layouts/basic.vue index 7c87e08b1..885ba4024 100644 --- a/apps/web-antdv-next/src/layouts/basic.vue +++ b/apps/web-antdv-next/src/layouts/basic.vue @@ -202,6 +202,31 @@ onMounted(() => { ); }); +const handleClick = (item: NotificationItem) => { + // 如果通知项有链接,点击时跳转 + if (item.link) { + navigateTo(item.link, item.query, item.state); + } +}; + +function navigateTo( + link: string, + query?: Record, + state?: Record, +) { + if (link.startsWith('http://') || link.startsWith('https://')) { + // 外部链接,在新标签页打开 + window.open(link, '_blank'); + } else { + // 内部路由链接,支持 query 参数和 state + router.push({ + path: link, + query: query || {}, + state, + }); + } +} + watch( () => ({ enable: preferences.app.watermark, @@ -264,6 +289,7 @@ watch( @view-all="handleNotificationViewAll" @open="handleNotificationOpen" @read="handleNotificationRead" + @on-click="handleClick" />