Skip to content

Commit 4baec83

Browse files
authored
feat: add examples: form-upload (#5955)
* feat: add examples: form-upload * fix: upload: accept and label * fix: upload: 设置表单值、图片预览
1 parent f7a4d13 commit 4baec83

File tree

6 files changed

+106
-3
lines changed

6 files changed

+106
-3
lines changed

apps/backend-mock/api/upload.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { verifyAccessToken } from '~/utils/jwt-utils';
2+
import { unAuthorizedResponse } from '~/utils/response';
3+
4+
export default eventHandler((event) => {
5+
const userinfo = verifyAccessToken(event);
6+
if (!userinfo) {
7+
return unAuthorizedResponse(event);
8+
}
9+
return useResponseSuccess({
10+
url: 'https://unpkg.com/@vbenjs/[email protected]/source/logo-v1.webp',
11+
});
12+
// return useResponseError("test")
13+
});

apps/backend-mock/routes/[...].ts

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export default defineEventHandler(() => {
77
<li><a href="/api/menu">/api/menu/all</a></li>
88
<li><a href="/api/auth/codes">/api/auth/codes</a></li>
99
<li><a href="/api/auth/login">/api/auth/login</a></li>
10+
<li><a href="/api/upload">/api/upload</a></li>
1011
</ul>
1112
`;
1213
});

playground/src/api/examples/upload.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { requestClient } from '#/api/request';
2+
3+
interface UploadFileParams {
4+
file: File;
5+
onError?: (error: Error) => void;
6+
onProgress?: (progress: { percent: number }) => void;
7+
onSuccess?: (data: any, file: File) => void;
8+
}
9+
export async function upload_file({
10+
file,
11+
onError,
12+
onProgress,
13+
onSuccess,
14+
}: UploadFileParams) {
15+
try {
16+
onProgress?.({ percent: 0 });
17+
18+
const data = await requestClient.upload('/upload', { file });
19+
20+
onProgress?.({ percent: 100 });
21+
onSuccess?.(data, file);
22+
} catch (error) {
23+
onError?.(error instanceof Error ? error : new Error(String(error)));
24+
}
25+
}

playground/src/locales/langs/en-US/examples.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818
"dynamic": "Dynamic Form",
1919
"custom": "Custom Component",
2020
"api": "Api",
21-
"merge": "Merge Form"
21+
"merge": "Merge Form",
22+
"upload-error": "Partial file upload failed",
23+
"upload-urls": "Urls after file upload",
24+
"file": "file",
25+
"upload-image": "Click to upload image"
2226
},
2327
"vxeTable": {
2428
"title": "Vxe Table",

playground/src/locales/langs/zh-CN/examples.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@
2121
"dynamic": "动态表单",
2222
"custom": "自定义组件",
2323
"api": "Api",
24-
"merge": "合并表单"
24+
"merge": "合并表单",
25+
"upload-error": "部分文件上传失败",
26+
"upload-urls": "文件上传后的网址",
27+
"file": "文件",
28+
"upload-image": "点击上传图片"
2529
},
2630
"vxeTable": {
2731
"title": "Vxe 表格",

playground/src/views/examples/form/basic.vue

+57-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<script lang="ts" setup>
2-
import { h, ref } from 'vue';
2+
import type { UploadFile } from 'ant-design-vue';
3+
4+
import { h, ref, toRaw } from 'vue';
35
46
import { Page } from '@vben/common-ui';
57
@@ -9,6 +11,8 @@ import dayjs from 'dayjs';
911
1012
import { useVbenForm, z } from '#/adapter/form';
1113
import { getAllMenusApi } from '#/api';
14+
import { upload_file } from '#/api/examples/upload';
15+
import { $t } from '#/locales';
1216
1317
import DocButton from '../doc-button.vue';
1418
@@ -329,12 +333,56 @@ const [BaseForm, baseFormApi] = useVbenForm({
329333
fieldName: 'treeSelect',
330334
label: '树选择',
331335
},
336+
{
337+
component: 'Upload',
338+
componentProps: {
339+
// 更多属性见:https://ant.design/components/upload-cn
340+
accept: '.png,.jpg,.jpeg',
341+
// 自动携带认证信息
342+
customRequest: upload_file,
343+
disabled: false,
344+
maxCount: 1,
345+
multiple: false,
346+
showUploadList: true,
347+
// 上传列表的内建样式,支持四种基本样式 text, picture, picture-card 和 picture-circle
348+
listType: 'picture-card',
349+
},
350+
fieldName: 'files',
351+
label: $t('examples.form.file'),
352+
renderComponentContent: () => {
353+
return {
354+
default: () => $t('examples.form.upload-image'),
355+
};
356+
},
357+
rules: 'required',
358+
},
332359
],
333360
// 大屏一行显示3个,中屏一行显示2个,小屏一行显示1个
334361
wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3',
335362
});
336363
337364
function onSubmit(values: Record<string, any>) {
365+
const files = toRaw(values.files) as UploadFile[];
366+
const doneFiles = files.filter((file) => file.status === 'done');
367+
const failedFiles = files.filter((file) => file.status !== 'done');
368+
369+
const msg = [
370+
...doneFiles.map((file) => file.response?.url || file.url),
371+
...failedFiles.map((file) => file.name),
372+
].join(', ');
373+
374+
if (failedFiles.length === 0) {
375+
message.success({
376+
content: `${$t('examples.form.upload-urls')}: ${msg}`,
377+
});
378+
} else {
379+
message.error({
380+
content: `${$t('examples.form.upload-error')}: ${msg}`,
381+
});
382+
return;
383+
}
384+
// 如果需要可提交前替换为需要的urls
385+
values.files = doneFiles.map((file) => file.response?.url || file.url);
338386
message.success({
339387
content: `form values: ${JSON.stringify(values)}`,
340388
});
@@ -347,6 +395,14 @@ function handleSetFormValue() {
347395
baseFormApi.setValues({
348396
checkboxGroup: ['1'],
349397
datePicker: dayjs('2022-01-01'),
398+
files: [
399+
{
400+
name: 'example.png',
401+
status: 'done',
402+
uid: '-1',
403+
url: 'https://unpkg.com/@vbenjs/[email protected]/source/logo-v1.webp',
404+
},
405+
],
350406
mentions: '@afc163',
351407
number: 3,
352408
options: '1',

0 commit comments

Comments
 (0)