|
|
|
@ -18,6 +18,7 @@ import type { |
|
|
|
MentionsProps, |
|
|
|
RadioGroupProps, |
|
|
|
RadioProps, |
|
|
|
RangePickerProps, |
|
|
|
RateProps, |
|
|
|
SelectProps, |
|
|
|
SpaceProps, |
|
|
|
@ -28,8 +29,7 @@ import type { |
|
|
|
UploadChangeParam, |
|
|
|
UploadFile, |
|
|
|
UploadProps, |
|
|
|
} from 'ant-design-vue'; |
|
|
|
import type { RangePickerProps } from 'ant-design-vue/es/date-picker'; |
|
|
|
} from 'antdv-next'; |
|
|
|
|
|
|
|
import type { Component, Ref } from 'vue'; |
|
|
|
|
|
|
|
@ -72,7 +72,7 @@ import { isEmpty } from '@vben/utils'; |
|
|
|
|
|
|
|
import { VbenCollapsibleParams } from '@vben-core/shadcn-ui'; |
|
|
|
|
|
|
|
import { message, Modal, notification } from 'ant-design-vue'; |
|
|
|
import { message, Modal, notification } from 'antdv-next'; |
|
|
|
|
|
|
|
import { upload_file } from '#/api/examples/upload'; |
|
|
|
type AdapterUploadProps = UploadProps & { |
|
|
|
@ -86,60 +86,72 @@ type AdapterUploadProps = UploadProps & { |
|
|
|
}; |
|
|
|
|
|
|
|
const AutoComplete = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/auto-complete'), |
|
|
|
() => import('antdv-next/dist/auto-complete/index'), |
|
|
|
); |
|
|
|
const Button = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/button/index'), |
|
|
|
); |
|
|
|
const Button = defineAsyncComponent(() => import('ant-design-vue/es/button')); |
|
|
|
const Checkbox = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/checkbox'), |
|
|
|
() => import('antdv-next/dist/checkbox/index'), |
|
|
|
); |
|
|
|
const CheckboxGroup = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/checkbox').then((res) => res.CheckboxGroup), |
|
|
|
import('antdv-next/dist/checkbox/index').then((res) => res.CheckboxGroup), |
|
|
|
); |
|
|
|
const DatePicker = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/date-picker'), |
|
|
|
() => import('antdv-next/dist/date-picker/index'), |
|
|
|
); |
|
|
|
const Divider = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/divider/index'), |
|
|
|
); |
|
|
|
const Divider = defineAsyncComponent(() => import('ant-design-vue/es/divider')); |
|
|
|
const Input = defineAsyncComponent(() => import('ant-design-vue/es/input')); |
|
|
|
const Input = defineAsyncComponent(() => import('antdv-next/dist/input/index')); |
|
|
|
const InputNumber = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/input-number'), |
|
|
|
() => import('antdv-next/dist/input-number/index'), |
|
|
|
); |
|
|
|
const InputPassword = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/input').then((res) => res.InputPassword), |
|
|
|
import('antdv-next/dist/input/index').then((res) => res.InputPassword), |
|
|
|
); |
|
|
|
const Mentions = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/mentions'), |
|
|
|
() => import('antdv-next/dist/mentions/index'), |
|
|
|
); |
|
|
|
const Radio = defineAsyncComponent(() => import('ant-design-vue/es/radio')); |
|
|
|
const Radio = defineAsyncComponent(() => import('antdv-next/dist/radio/index')); |
|
|
|
const RadioGroup = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/radio').then((res) => res.RadioGroup), |
|
|
|
import('antdv-next/dist/radio/index').then((res) => res.RadioGroup), |
|
|
|
); |
|
|
|
const RangePicker = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/date-picker').then((res) => res.RangePicker), |
|
|
|
import('antdv-next/dist/date-picker/index').then( |
|
|
|
(res) => res.DateRangePicker, |
|
|
|
), |
|
|
|
); |
|
|
|
const Rate = defineAsyncComponent(() => import('antdv-next/dist/rate/index')); |
|
|
|
const Select = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/select/index'), |
|
|
|
); |
|
|
|
const Rate = defineAsyncComponent(() => import('ant-design-vue/es/rate')); |
|
|
|
const Select = defineAsyncComponent(() => import('ant-design-vue/es/select')); |
|
|
|
const Space = defineAsyncComponent(() => import('ant-design-vue/es/space')); |
|
|
|
const Switch = defineAsyncComponent(() => import('ant-design-vue/es/switch')); |
|
|
|
const Textarea = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/input').then((res) => res.Textarea), |
|
|
|
const Space = defineAsyncComponent(() => import('antdv-next/dist/space/index')); |
|
|
|
const Switch = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/switch/index'), |
|
|
|
); |
|
|
|
const Textarea = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/input/TextArea'), |
|
|
|
); |
|
|
|
const TimePicker = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/time-picker'), |
|
|
|
() => import('antdv-next/dist/time-picker/index'), |
|
|
|
); |
|
|
|
const TreeSelect = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/tree-select'), |
|
|
|
() => import('antdv-next/dist/tree-select/index'), |
|
|
|
); |
|
|
|
const Cascader = defineAsyncComponent( |
|
|
|
() => import('ant-design-vue/es/cascader'), |
|
|
|
() => import('antdv-next/dist/cascader/index'), |
|
|
|
); |
|
|
|
const Upload = defineAsyncComponent( |
|
|
|
() => import('antdv-next/dist/upload/index'), |
|
|
|
); |
|
|
|
const Upload = defineAsyncComponent(() => import('ant-design-vue/es/upload')); |
|
|
|
const Image = defineAsyncComponent(() => import('ant-design-vue/es/image')); |
|
|
|
const Image = defineAsyncComponent(() => import('antdv-next/dist/image/index')); |
|
|
|
const PreviewGroup = defineAsyncComponent(() => |
|
|
|
import('ant-design-vue/es/image').then((res) => res.ImagePreviewGroup), |
|
|
|
import('antdv-next/dist/image/index').then((res) => res.ImagePreviewGroup), |
|
|
|
); |
|
|
|
|
|
|
|
const withDefaultPlaceholder = <T extends Component>( |
|
|
|
component: T, |
|
|
|
const withDefaultPlaceholder = ( |
|
|
|
component: Component, |
|
|
|
type: 'input' | 'select', |
|
|
|
componentProps: Recordable<any> = {}, |
|
|
|
) => { |
|
|
|
@ -242,7 +254,7 @@ function getBase64(file: File): Promise<string> { |
|
|
|
*/ |
|
|
|
async function previewImage( |
|
|
|
file: UploadFile, |
|
|
|
visible: Ref<boolean>, |
|
|
|
open: Ref<boolean>, |
|
|
|
fileList: Ref<UploadProps['fileList']>, |
|
|
|
) { |
|
|
|
// 非图片文件直接打开链接
|
|
|
|
@ -250,6 +262,8 @@ async function previewImage( |
|
|
|
const url = file.url || file.preview; |
|
|
|
if (url) { |
|
|
|
window.open(url, '_blank'); |
|
|
|
} else if (file.preview) { |
|
|
|
window.open(file.preview, '_blank'); |
|
|
|
} else { |
|
|
|
message.error($t('ui.formRules.previewWarning')); |
|
|
|
} |
|
|
|
@ -285,10 +299,10 @@ async function previewImage( |
|
|
|
{ |
|
|
|
class: 'hidden', |
|
|
|
preview: { |
|
|
|
visible: visible.value, |
|
|
|
open: open.value, |
|
|
|
current: currentIndex, |
|
|
|
onVisibleChange: (value: boolean) => { |
|
|
|
visible.value = value; |
|
|
|
onOpenChange: (value: boolean) => { |
|
|
|
open.value = value; |
|
|
|
if (!value) { |
|
|
|
setTimeout(() => { |
|
|
|
if (!isUnmounted && container) { |
|
|
|
@ -330,7 +344,7 @@ function cropImage(file: File, aspectRatio: string | undefined) { |
|
|
|
const open = ref<boolean>(true); |
|
|
|
const cropperRef = ref<InstanceType<typeof VCropper> | null>(null); |
|
|
|
|
|
|
|
const closeModal = () => { |
|
|
|
function closeModal() { |
|
|
|
open.value = false; |
|
|
|
setTimeout(() => { |
|
|
|
if (!isUnmounted && container) { |
|
|
|
@ -342,7 +356,7 @@ function cropImage(file: File, aspectRatio: string | undefined) { |
|
|
|
container.remove(); |
|
|
|
} |
|
|
|
}, 300); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const CropperWrapper = { |
|
|
|
setup() { |
|
|
|
@ -416,7 +430,7 @@ function cropImage(file: File, aspectRatio: string | undefined) { |
|
|
|
/** |
|
|
|
* 带预览功能的上传组件 |
|
|
|
*/ |
|
|
|
const withPreviewUpload = () => { |
|
|
|
function withPreviewUpload() { |
|
|
|
return defineComponent({ |
|
|
|
name: Upload.name, |
|
|
|
emits: ['update:modelValue'], |
|
|
|
@ -436,10 +450,10 @@ const withPreviewUpload = () => { |
|
|
|
() => attrs?.aspectRatio ?? attrs?.['aspect-ratio'], |
|
|
|
); |
|
|
|
|
|
|
|
const handleBeforeUpload = async ( |
|
|
|
async function handleBeforeUpload( |
|
|
|
file: UploadFile, |
|
|
|
originFileList: Array<File>, |
|
|
|
) => { |
|
|
|
) { |
|
|
|
// 文件大小限制
|
|
|
|
if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) { |
|
|
|
message.error($t('ui.formRules.sizeLimit', [maxSize.value])); |
|
|
|
@ -463,9 +477,9 @@ const withPreviewUpload = () => { |
|
|
|
} |
|
|
|
|
|
|
|
return attrs.beforeUpload?.(file) ?? true; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const handleChange = (event: UploadChangeParam) => { |
|
|
|
function handleChange(event: UploadChangeParam) { |
|
|
|
try { |
|
|
|
attrs.handleChange?.(event); |
|
|
|
attrs.onHandleChange?.(event); |
|
|
|
@ -479,19 +493,19 @@ const withPreviewUpload = () => { |
|
|
|
'update:modelValue', |
|
|
|
event.fileList?.length ? fileList.value : undefined, |
|
|
|
); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
const handlePreview = async (file: UploadFile) => { |
|
|
|
function handlePreview(file: UploadFile) { |
|
|
|
previewVisible.value = true; |
|
|
|
await previewImage(file, previewVisible, fileList); |
|
|
|
}; |
|
|
|
return previewImage(file, previewVisible, fileList); |
|
|
|
} |
|
|
|
|
|
|
|
const renderUploadButton = () => { |
|
|
|
function renderUploadButton() { |
|
|
|
if (attrs.disabled) return null; |
|
|
|
return isEmpty(slots) |
|
|
|
? createDefaultUploadSlots(listType, placeholder) |
|
|
|
: slots; |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 拖拽排序
|
|
|
|
const draggable = computed( |
|
|
|
@ -600,7 +614,7 @@ const withPreviewUpload = () => { |
|
|
|
); |
|
|
|
}, |
|
|
|
}); |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
|
|
|
|
export type ComponentType = |
|
|
|
@ -681,13 +695,13 @@ async function initComponentAdapter() { |
|
|
|
fieldNames: { label: 'label', value: 'value', children: 'children' }, |
|
|
|
loadingSlot: 'suffixIcon', |
|
|
|
modelPropName: 'value', |
|
|
|
visibleEvent: 'onVisibleChange', |
|
|
|
visibleEvent: 'onOpenChange', |
|
|
|
}), |
|
|
|
ApiSelect: withDefaultPlaceholder(ApiComponent, 'select', { |
|
|
|
component: Select, |
|
|
|
loadingSlot: 'suffixIcon', |
|
|
|
modelPropName: 'value', |
|
|
|
visibleEvent: 'onVisibleChange', |
|
|
|
visibleEvent: 'onOpenChange', |
|
|
|
}), |
|
|
|
ApiTreeSelect: withDefaultPlaceholder(ApiComponent, 'select', { |
|
|
|
component: TreeSelect, |
|
|
|
@ -695,7 +709,7 @@ async function initComponentAdapter() { |
|
|
|
loadingSlot: 'suffixIcon', |
|
|
|
modelPropName: 'value', |
|
|
|
optionsPropName: 'treeData', |
|
|
|
visibleEvent: 'onVisibleChange', |
|
|
|
visibleEvent: 'onOpenChange', |
|
|
|
}), |
|
|
|
AutoComplete, |
|
|
|
Cascader, |
|
|
|
@ -764,7 +778,7 @@ async function initComponentAdapter() { |
|
|
|
copyPreferencesSuccess: (title, content) => { |
|
|
|
notification.success({ |
|
|
|
description: content, |
|
|
|
message: title, |
|
|
|
title, |
|
|
|
placement: 'bottomRight', |
|
|
|
}); |
|
|
|
}, |
|
|
|
|