feat: image upload component
This commit is contained in:
parent
55ae01c536
commit
41fda26248
@ -26,6 +26,7 @@
|
|||||||
"#/*": "./src/*"
|
"#/*": "./src/*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/icons-vue": "^7.0.1",
|
||||||
"@tinymce/tinymce-vue": "^6.0.1",
|
"@tinymce/tinymce-vue": "^6.0.1",
|
||||||
"@vben/access": "workspace:*",
|
"@vben/access": "workspace:*",
|
||||||
"@vben/common-ui": "workspace:*",
|
"@vben/common-ui": "workspace:*",
|
||||||
|
@ -36,6 +36,7 @@ import {
|
|||||||
import { isArray } from 'lodash-es';
|
import { isArray } from 'lodash-es';
|
||||||
|
|
||||||
import { Tinymce as RichTextarea } from '#/components/tinymce';
|
import { Tinymce as RichTextarea } from '#/components/tinymce';
|
||||||
|
import { ImageUpload } from '#/components/upload';
|
||||||
|
|
||||||
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
|
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
|
||||||
export type FormComponentType =
|
export type FormComponentType =
|
||||||
@ -44,6 +45,7 @@ export type FormComponentType =
|
|||||||
| 'CheckboxGroup'
|
| 'CheckboxGroup'
|
||||||
| 'DatePicker'
|
| 'DatePicker'
|
||||||
| 'Divider'
|
| 'Divider'
|
||||||
|
| 'ImageUpload'
|
||||||
| 'Input'
|
| 'Input'
|
||||||
| 'InputNumber'
|
| 'InputNumber'
|
||||||
| 'InputPassword'
|
| 'InputPassword'
|
||||||
@ -104,6 +106,7 @@ setupVbenForm<FormComponentType>({
|
|||||||
TimePicker,
|
TimePicker,
|
||||||
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
|
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
|
||||||
Upload,
|
Upload,
|
||||||
|
ImageUpload,
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
// ant design vue组件库默认都是 v-model:value
|
// ant design vue组件库默认都是 v-model:value
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { requestClient } from '#/api/request';
|
import { requestClient } from '#/api/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过单文件上传接口
|
||||||
|
* @param file 上传的文件
|
||||||
|
* @returns 上传结果
|
||||||
|
*/
|
||||||
export function uploadApi(file: Blob | File) {
|
export function uploadApi(file: Blob | File) {
|
||||||
return requestClient.upload('/resource/oss/upload', file);
|
console.log('uploadApi', file);
|
||||||
|
return requestClient.upload('/resource/oss/upload', { file });
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 默认上传结果
|
* 默认上传结果
|
||||||
|
1
apps/web-antd/src/components/upload/index.ts
Normal file
1
apps/web-antd/src/components/upload/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default as ImageUpload } from './src/image-upload.vue';
|
32
apps/web-antd/src/components/upload/src/helper.ts
Normal file
32
apps/web-antd/src/components/upload/src/helper.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
export function checkFileType(file: File, accepts: string[]) {
|
||||||
|
let reg;
|
||||||
|
if (!accepts || accepts.length === 0) {
|
||||||
|
reg = /.(?:jpg|jpeg|png|gif|webp)$/i;
|
||||||
|
} else {
|
||||||
|
const newTypes = accepts.join('|');
|
||||||
|
reg = new RegExp(`${String.raw`\.(` + newTypes})$`, 'i');
|
||||||
|
}
|
||||||
|
return reg.test(file.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkImgType(file: File) {
|
||||||
|
return isImgTypeByName(file.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isImgTypeByName(name: string) {
|
||||||
|
return /\.(?:jpg|jpeg|png|gif|webp)$/i.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBase64WithFile(file: File) {
|
||||||
|
return new Promise<{
|
||||||
|
file: File;
|
||||||
|
result: string;
|
||||||
|
}>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.addEventListener('load', () =>
|
||||||
|
resolve({ result: reader.result as string, file }),
|
||||||
|
);
|
||||||
|
reader.addEventListener('error', (error) => reject(error));
|
||||||
|
});
|
||||||
|
}
|
261
apps/web-antd/src/components/upload/src/image-upload.vue
Normal file
261
apps/web-antd/src/components/upload/src/image-upload.vue
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import type { Recordable } from '@vben/types';
|
||||||
|
import type { UploadFile, UploadProps } from 'ant-design-vue';
|
||||||
|
import type { UploadRequestOption } from 'ant-design-vue/lib/vc-upload/interface';
|
||||||
|
|
||||||
|
import { ref, toRefs, watch } from 'vue';
|
||||||
|
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { message, Modal, Upload } from 'ant-design-vue';
|
||||||
|
import { isArray, isFunction, isObject, isString } from 'lodash-es';
|
||||||
|
|
||||||
|
import { uploadApi } from '#/api';
|
||||||
|
|
||||||
|
import { checkFileType } from './helper';
|
||||||
|
import { UploadResultStatus } from './typing';
|
||||||
|
import { useUploadType } from './use-upload';
|
||||||
|
|
||||||
|
defineOptions({ name: 'ImageUpload' });
|
||||||
|
|
||||||
|
const props = withDefaults(
|
||||||
|
defineProps<{
|
||||||
|
/**
|
||||||
|
* 建议使用拓展名(不带.)
|
||||||
|
* 或者文件头 image/png等(测试判断不准确) 不支持image/*类似的写法
|
||||||
|
* 需自行改造 ./helper/checkFileType方法
|
||||||
|
*/
|
||||||
|
accept?: string[];
|
||||||
|
api?: (...args: any[]) => Promise<any>;
|
||||||
|
disabled?: boolean;
|
||||||
|
filename?: null | string;
|
||||||
|
helpText?: string;
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
listType?: ListType;
|
||||||
|
// 最大数量的文件,Infinity不限制
|
||||||
|
maxNumber?: number;
|
||||||
|
// 文件最大多少MB
|
||||||
|
maxSize?: number;
|
||||||
|
multiple?: boolean;
|
||||||
|
name?: string;
|
||||||
|
// support xxx.xxx.xx
|
||||||
|
resultField?: string;
|
||||||
|
uploadParams?: Recordable<any>;
|
||||||
|
value?: string[];
|
||||||
|
}>(),
|
||||||
|
{
|
||||||
|
value: () => [],
|
||||||
|
disabled: false,
|
||||||
|
listType: 'picture-card',
|
||||||
|
helpText: '',
|
||||||
|
maxSize: 2,
|
||||||
|
maxNumber: 1,
|
||||||
|
accept: () => [],
|
||||||
|
multiple: false,
|
||||||
|
uploadParams: () => ({}),
|
||||||
|
api: uploadApi,
|
||||||
|
name: 'file',
|
||||||
|
filename: null,
|
||||||
|
resultField: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const emit = defineEmits(['change', 'update:value', 'delete']);
|
||||||
|
type ListType = 'picture' | 'picture-card' | 'text';
|
||||||
|
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
|
||||||
|
const isInnerOperate = ref<boolean>(false);
|
||||||
|
const { getStringAccept } = useUploadType({
|
||||||
|
acceptRef: accept,
|
||||||
|
helpTextRef: helpText,
|
||||||
|
maxNumberRef: maxNumber,
|
||||||
|
maxSizeRef: maxSize,
|
||||||
|
});
|
||||||
|
const previewOpen = ref<boolean>(false);
|
||||||
|
const previewImage = ref<string>('');
|
||||||
|
const previewTitle = ref<string>('');
|
||||||
|
|
||||||
|
const fileList = ref<UploadProps['fileList']>([]);
|
||||||
|
const isLtMsg = ref<boolean>(true);
|
||||||
|
const isActMsg = ref<boolean>(true);
|
||||||
|
const isFirstRender = ref<boolean>(true);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(v) => {
|
||||||
|
if (isInnerOperate.value) {
|
||||||
|
isInnerOperate.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let value: string[] = [];
|
||||||
|
if (v) {
|
||||||
|
if (isArray(v)) {
|
||||||
|
value = v;
|
||||||
|
} else {
|
||||||
|
value.push(v);
|
||||||
|
}
|
||||||
|
fileList.value = value.map((item, i) => {
|
||||||
|
if (item && isString(item)) {
|
||||||
|
return {
|
||||||
|
uid: `${-i}`,
|
||||||
|
name: item.slice(Math.max(0, item.lastIndexOf('/') + 1)),
|
||||||
|
status: 'done',
|
||||||
|
url: item,
|
||||||
|
};
|
||||||
|
} else if (item && isObject(item)) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}) as UploadProps['fileList'];
|
||||||
|
}
|
||||||
|
emit('update:value', value);
|
||||||
|
if (!isFirstRender.value) {
|
||||||
|
emit('change', value);
|
||||||
|
isFirstRender.value = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
function getBase64<T extends ArrayBuffer | null | string>(file: File) {
|
||||||
|
return new Promise<T>((resolve, reject) => {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
reader.addEventListener('load', () => {
|
||||||
|
resolve(reader.result as T);
|
||||||
|
});
|
||||||
|
reader.addEventListener('error', (error) => reject(error));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePreview = async (file: UploadFile) => {
|
||||||
|
if (!file.url && !file.preview) {
|
||||||
|
file.preview = await getBase64<string>(file.originFileObj!);
|
||||||
|
}
|
||||||
|
previewImage.value = file.url || file.preview || '';
|
||||||
|
previewOpen.value = true;
|
||||||
|
previewTitle.value =
|
||||||
|
file.name ||
|
||||||
|
previewImage.value.slice(
|
||||||
|
Math.max(0, previewImage.value.lastIndexOf('/') + 1),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemove = async (file: UploadFile) => {
|
||||||
|
if (fileList.value) {
|
||||||
|
const index = fileList.value.findIndex((item) => item.uid === file.uid);
|
||||||
|
index !== -1 && fileList.value.splice(index, 1);
|
||||||
|
const value = getValue();
|
||||||
|
isInnerOperate.value = true;
|
||||||
|
emit('update:value', value);
|
||||||
|
emit('change', value);
|
||||||
|
emit('delete', file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
previewOpen.value = false;
|
||||||
|
previewTitle.value = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
const beforeUpload = (file: File) => {
|
||||||
|
const { maxSize, accept } = props;
|
||||||
|
const isAct = checkFileType(file, accept);
|
||||||
|
if (!isAct) {
|
||||||
|
message.error($t('component.upload.acceptUpload', [accept]));
|
||||||
|
isActMsg.value = false;
|
||||||
|
// 防止弹出多个错误提示
|
||||||
|
setTimeout(() => (isActMsg.value = true), 1000);
|
||||||
|
}
|
||||||
|
const isLt = file.size / 1024 / 1024 > maxSize;
|
||||||
|
if (isLt) {
|
||||||
|
message.error($t('component.upload.maxSizeMultiple', [maxSize]));
|
||||||
|
isLtMsg.value = false;
|
||||||
|
// 防止弹出多个错误提示
|
||||||
|
setTimeout(() => (isLtMsg.value = true), 1000);
|
||||||
|
}
|
||||||
|
return (isAct && !isLt) || Upload.LIST_IGNORE;
|
||||||
|
};
|
||||||
|
|
||||||
|
async function customRequest(info: UploadRequestOption<any>) {
|
||||||
|
const { api } = props;
|
||||||
|
if (!api || !isFunction(api)) {
|
||||||
|
console.warn('upload api must exist and be a function');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const res = await api?.(info.file);
|
||||||
|
/**
|
||||||
|
* 由getValue处理 传对象过去
|
||||||
|
* 直接传string(id)会被转为Number
|
||||||
|
*/
|
||||||
|
info.onSuccess!(res);
|
||||||
|
// 获取
|
||||||
|
const value = getValue();
|
||||||
|
isInnerOperate.value = true;
|
||||||
|
emit('update:value', value);
|
||||||
|
emit('change', value);
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error);
|
||||||
|
info.onError!(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValue() {
|
||||||
|
const list = (fileList.value || [])
|
||||||
|
.filter((item) => item?.status === UploadResultStatus.DONE)
|
||||||
|
.map((item: any) => {
|
||||||
|
if (item?.response && props?.resultField) {
|
||||||
|
return item?.response?.[props.resultField];
|
||||||
|
}
|
||||||
|
// 注意这里取的key为 url
|
||||||
|
return item?.response?.url;
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Upload
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-model:file-list="fileList"
|
||||||
|
:accept="getStringAccept"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:custom-request="customRequest"
|
||||||
|
:disabled="disabled"
|
||||||
|
:list-type="listType"
|
||||||
|
:max-count="maxNumber"
|
||||||
|
:multiple="multiple"
|
||||||
|
@preview="handlePreview"
|
||||||
|
@remove="handleRemove"
|
||||||
|
>
|
||||||
|
<div v-if="fileList && fileList.length < maxNumber">
|
||||||
|
<PlusOutlined />
|
||||||
|
<div style="margin-top: 8px">{{ $t('component.upload.upload') }}</div>
|
||||||
|
</div>
|
||||||
|
</Upload>
|
||||||
|
<Modal
|
||||||
|
:footer="null"
|
||||||
|
:open="previewOpen"
|
||||||
|
:title="previewTitle"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<img :src="previewImage" alt="" style="width: 100%" />
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.ant-upload-select-picture-card i {
|
||||||
|
color: #999;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-upload-select-picture-card .ant-upload-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
</style>
|
37
apps/web-antd/src/components/upload/src/typing.ts
Normal file
37
apps/web-antd/src/components/upload/src/typing.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import type { Recordable } from '@vben/types';
|
||||||
|
|
||||||
|
export enum UploadResultStatus {
|
||||||
|
DONE = 'done',
|
||||||
|
ERROR = 'error',
|
||||||
|
SUCCESS = 'success',
|
||||||
|
UPLOADING = 'uploading',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileItem {
|
||||||
|
thumbUrl?: string;
|
||||||
|
name: string;
|
||||||
|
size: number | string;
|
||||||
|
type?: string;
|
||||||
|
percent: number;
|
||||||
|
file: File;
|
||||||
|
status?: UploadResultStatus;
|
||||||
|
response?: { fileName: string; ossId: string; url: string } | Recordable<any>;
|
||||||
|
uuid: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Wrapper {
|
||||||
|
record: FileItem;
|
||||||
|
uidKey: string;
|
||||||
|
valueKey: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BaseFileItem {
|
||||||
|
uid: number | string;
|
||||||
|
url: string;
|
||||||
|
name?: string;
|
||||||
|
}
|
||||||
|
export interface PreviewFileItem {
|
||||||
|
url: string;
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
}
|
60
apps/web-antd/src/components/upload/src/use-upload.ts
Normal file
60
apps/web-antd/src/components/upload/src/use-upload.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { computed, unref } from 'vue';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import { $t } from '@vben/locales';
|
||||||
|
|
||||||
|
export function useUploadType({
|
||||||
|
acceptRef,
|
||||||
|
helpTextRef,
|
||||||
|
maxNumberRef,
|
||||||
|
maxSizeRef,
|
||||||
|
}: {
|
||||||
|
acceptRef: Ref<string[]>;
|
||||||
|
helpTextRef: Ref<string>;
|
||||||
|
maxNumberRef: Ref<number>;
|
||||||
|
maxSizeRef: Ref<number>;
|
||||||
|
}) {
|
||||||
|
// 文件类型限制
|
||||||
|
const getAccept = computed(() => {
|
||||||
|
const accept = unref(acceptRef);
|
||||||
|
if (accept && accept.length > 0) {
|
||||||
|
return accept;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
});
|
||||||
|
const getStringAccept = computed(() => {
|
||||||
|
return unref(getAccept)
|
||||||
|
.map((item) => {
|
||||||
|
return item.indexOf('/') > 0 || item.startsWith('.')
|
||||||
|
? item
|
||||||
|
: `.${item}`;
|
||||||
|
})
|
||||||
|
.join(',');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 支持jpg、jpeg、png格式,不超过2M,最多可选择10张图片,。
|
||||||
|
const getHelpText = computed(() => {
|
||||||
|
const helpText = unref(helpTextRef);
|
||||||
|
if (helpText) {
|
||||||
|
return helpText;
|
||||||
|
}
|
||||||
|
const helpTexts: string[] = [];
|
||||||
|
|
||||||
|
const accept = unref(acceptRef);
|
||||||
|
if (accept.length > 0) {
|
||||||
|
helpTexts.push($t('component.upload.accept', [accept.join(',')]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxSize = unref(maxSizeRef);
|
||||||
|
if (maxSize) {
|
||||||
|
helpTexts.push($t('component.upload.maxSize', [maxSize]));
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxNumber = unref(maxNumberRef);
|
||||||
|
if (maxNumber && maxNumber !== Infinity) {
|
||||||
|
helpTexts.push($t('component.upload.maxNumber', [maxNumber]));
|
||||||
|
}
|
||||||
|
return helpTexts.join(',');
|
||||||
|
});
|
||||||
|
return { getAccept, getStringAccept, getHelpText };
|
||||||
|
}
|
@ -29,6 +29,35 @@
|
|||||||
"notice": {
|
"notice": {
|
||||||
"title": "Notice",
|
"title": "Notice",
|
||||||
"received": "You have received a new message"
|
"received": "You have received a new message"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"save": "Save",
|
||||||
|
"upload": "Upload",
|
||||||
|
"imgUpload": "ImageUpload",
|
||||||
|
"uploaded": "Uploaded",
|
||||||
|
"operating": "Operating",
|
||||||
|
"del": "Delete",
|
||||||
|
"download": "download",
|
||||||
|
"saveWarn": "Please wait for the file to upload and save!",
|
||||||
|
"saveError": "There is no file successfully uploaded and cannot be saved!",
|
||||||
|
"preview": "Preview",
|
||||||
|
"choose": "Select the file",
|
||||||
|
"accept": "Support {0} format",
|
||||||
|
"acceptUpload": "Only upload files in {0} format",
|
||||||
|
"maxSize": "A single file does not exceed {0}MB ",
|
||||||
|
"maxSizeMultiple": "Only upload files up to {0}MB!",
|
||||||
|
"maxNumber": "Only upload up to {0} files",
|
||||||
|
"legend": "Legend",
|
||||||
|
"fileName": "File name",
|
||||||
|
"fileSize": "File size",
|
||||||
|
"fileStatue": "File status",
|
||||||
|
"pending": "Pending",
|
||||||
|
"startUpload": "Start upload",
|
||||||
|
"uploadSuccess": "Upload successfully",
|
||||||
|
"uploadError": "Upload failed",
|
||||||
|
"uploading": "Uploading",
|
||||||
|
"uploadWait": "Please wait for the file upload to finish",
|
||||||
|
"reUploadFailed": "Re-upload failed files"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pages": {
|
"pages": {
|
||||||
|
@ -29,6 +29,35 @@
|
|||||||
"notice": {
|
"notice": {
|
||||||
"title": "消息",
|
"title": "消息",
|
||||||
"received": "收到新消息"
|
"received": "收到新消息"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"save": "保存",
|
||||||
|
"upload": "上传",
|
||||||
|
"imgUpload": "图片上传",
|
||||||
|
"uploaded": "已上传",
|
||||||
|
"operating": "操作",
|
||||||
|
"del": "删除",
|
||||||
|
"download": "下载",
|
||||||
|
"saveWarn": "请等待文件上传后,保存!",
|
||||||
|
"saveError": "没有上传成功的文件,无法保存!",
|
||||||
|
"preview": "预览",
|
||||||
|
"choose": "选择文件",
|
||||||
|
"accept": "支持{0}格式",
|
||||||
|
"acceptUpload": "只能上传{0}格式文件",
|
||||||
|
"maxSize": "单个文件不超过{0}MB",
|
||||||
|
"maxSizeMultiple": "只能上传不超过{0}MB的文件!",
|
||||||
|
"maxNumber": "最多只能上传{0}个文件",
|
||||||
|
"legend": "略缩图",
|
||||||
|
"fileName": "文件名",
|
||||||
|
"fileSize": "文件大小",
|
||||||
|
"fileStatue": "状态",
|
||||||
|
"pending": "待上传",
|
||||||
|
"startUpload": "开始上传",
|
||||||
|
"uploadSuccess": "上传成功",
|
||||||
|
"uploadError": "上传失败",
|
||||||
|
"uploading": "上传中",
|
||||||
|
"uploadWait": "请等待文件上传结束后操作",
|
||||||
|
"reUploadFailed": "重新上传失败文件"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pages": {
|
"pages": {
|
||||||
|
30
apps/web-antd/src/views/演示使用自行删除/upload/index.vue
Normal file
30
apps/web-antd/src/views/演示使用自行删除/upload/index.vue
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
import { JsonPreview, Page } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { RadioGroup } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { ImageUpload } from '#/components/upload';
|
||||||
|
|
||||||
|
const resultField = ref<'ossId' | 'url'>('ossId');
|
||||||
|
|
||||||
|
const fileList = ref([]);
|
||||||
|
const fieldOptions = [
|
||||||
|
{ label: 'ossId', value: 'ossId' },
|
||||||
|
{ label: '链接地址', value: 'url' },
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Page class="flex flex-col gap-[8px]">
|
||||||
|
<div class="bg-background flex flex-col gap-[12px] rounded-lg p-6">
|
||||||
|
<div class="flex gap-[8px]">
|
||||||
|
<span>返回字段: </span>
|
||||||
|
<RadioGroup v-model:value="resultField" :options="fieldOptions" />
|
||||||
|
</div>
|
||||||
|
<ImageUpload v-model:value="fileList" :result-field="resultField" />
|
||||||
|
<JsonPreview :data="fileList" />
|
||||||
|
</div>
|
||||||
|
</Page>
|
||||||
|
</template>
|
@ -621,6 +621,9 @@ importers:
|
|||||||
|
|
||||||
apps/web-antd:
|
apps/web-antd:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@ant-design/icons-vue':
|
||||||
|
specifier: ^7.0.1
|
||||||
|
version: 7.0.1(vue@3.5.11(typescript@5.6.2))
|
||||||
'@tinymce/tinymce-vue':
|
'@tinymce/tinymce-vue':
|
||||||
specifier: ^6.0.1
|
specifier: ^6.0.1
|
||||||
version: 6.0.1(vue@3.5.11(typescript@5.6.2))
|
version: 6.0.1(vue@3.5.11(typescript@5.6.2))
|
||||||
@ -5926,9 +5929,6 @@ packages:
|
|||||||
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
|
resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==}
|
||||||
engines: {node: '>=12.13'}
|
engines: {node: '>=12.13'}
|
||||||
|
|
||||||
core-js-compat@3.38.0:
|
|
||||||
resolution: {integrity: sha512-75LAicdLa4OJVwFxFbQR3NdnZjNgX6ILpVcVzcC4T2smerB5lELMrJQQQoWV6TiuC/vlaFqgU2tKQx9w5s0e0A==}
|
|
||||||
|
|
||||||
core-js-compat@3.38.1:
|
core-js-compat@3.38.1:
|
||||||
resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==}
|
resolution: {integrity: sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw==}
|
||||||
|
|
||||||
@ -12029,7 +12029,7 @@ snapshots:
|
|||||||
babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
|
babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.25.2)
|
||||||
babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2)
|
babel-plugin-polyfill-corejs3: 0.10.6(@babel/core@7.25.2)
|
||||||
babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
|
babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.25.2)
|
||||||
core-js-compat: 3.38.0
|
core-js-compat: 3.38.1
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
@ -15176,7 +15176,7 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.25.2
|
'@babel/core': 7.25.2
|
||||||
'@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
|
'@babel/helper-define-polyfill-provider': 0.6.2(@babel/core@7.25.2)
|
||||||
core-js-compat: 3.38.0
|
core-js-compat: 3.38.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
@ -15645,10 +15645,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-what: 4.1.16
|
is-what: 4.1.16
|
||||||
|
|
||||||
core-js-compat@3.38.0:
|
|
||||||
dependencies:
|
|
||||||
browserslist: 4.23.3
|
|
||||||
|
|
||||||
core-js-compat@3.38.1:
|
core-js-compat@3.38.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.23.3
|
browserslist: 4.23.3
|
||||||
|
Loading…
Reference in New Issue
Block a user