mirror of
https://github.com/vbenjs/vben-admin-thin-next.git
synced 2025-01-23 17:50:22 +08:00
perf(upload): improve upload component
This commit is contained in:
parent
a161bfa818
commit
661db0c767
@ -3,6 +3,11 @@
|
|||||||
### ✨ Features
|
### ✨ Features
|
||||||
|
|
||||||
- 新增 base64 文件流下载
|
- 新增 base64 文件流下载
|
||||||
|
- 优化上传组件及示例
|
||||||
|
|
||||||
|
### 🎫 Chores
|
||||||
|
|
||||||
|
- 更新 antdv 到`2.0.0-rc.1`
|
||||||
|
|
||||||
## 2.0.0-rc.10 (2020-11-13)
|
## 2.0.0-rc.10 (2020-11-13)
|
||||||
|
|
||||||
|
@ -226,10 +226,10 @@ yarn clean:lib # Delete node_modules, supported window
|
|||||||
- [x] Data import and export
|
- [x] Data import and export
|
||||||
- [x] Global error handling
|
- [x] Global error handling
|
||||||
- [x] Rich text component
|
- [x] Rich text component
|
||||||
|
- [x] Upload component
|
||||||
|
|
||||||
## Developing features
|
## Developing features
|
||||||
|
|
||||||
- [ ] Upload component
|
|
||||||
- [ ] Theme configuration
|
- [ ] Theme configuration
|
||||||
- [ ] Dark theme
|
- [ ] Dark theme
|
||||||
- [ ] Build CDN
|
- [ ] Build CDN
|
||||||
|
@ -228,10 +228,10 @@ yarn clean:lib # 删除node_modules,兼容window系统
|
|||||||
- [x] 系统性能优化
|
- [x] 系统性能优化
|
||||||
- [x] 全局错误处理
|
- [x] 全局错误处理
|
||||||
- [x] 富文本组件
|
- [x] 富文本组件
|
||||||
|
- [x] 上传组件
|
||||||
|
|
||||||
## 正在开发的功能
|
## 正在开发的功能
|
||||||
|
|
||||||
- [ ] 上传组件
|
|
||||||
- [ ] 主题配置
|
- [ ] 主题配置
|
||||||
- [ ] 黑暗主题
|
- [ ] 黑暗主题
|
||||||
- [ ] 打包 CDN
|
- [ ] 打包 CDN
|
||||||
|
12
package.json
12
package.json
@ -22,8 +22,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@iconify/iconify": "^2.0.0-rc.2",
|
"@iconify/iconify": "^2.0.0-rc.2",
|
||||||
"@vueuse/core": "^4.0.0-beta.40",
|
"@vueuse/core": "^4.0.0-beta.41",
|
||||||
"ant-design-vue": "^2.0.0-beta.15",
|
"ant-design-vue": "^2.0.0-rc.1",
|
||||||
"apexcharts": "3.22.0",
|
"apexcharts": "3.22.0",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
"echarts": "^4.9.0",
|
"echarts": "^4.9.0",
|
||||||
@ -33,10 +33,10 @@
|
|||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"qrcode": "^1.4.4",
|
"qrcode": "^1.4.4",
|
||||||
"vditor": "^3.6.0",
|
"vditor": "^3.6.2",
|
||||||
"vue": "^3.0.2",
|
"vue": "^3.0.2",
|
||||||
"vue-i18n": "^9.0.0-beta.6",
|
"vue-i18n": "^9.0.0-beta.6",
|
||||||
"vue-router": "^4.0.0-rc.2",
|
"vue-router": "^4.0.0-rc.3",
|
||||||
"vuex": "^4.0.0-rc.1",
|
"vuex": "^4.0.0-rc.1",
|
||||||
"vuex-module-decorators": "^1.0.1",
|
"vuex-module-decorators": "^1.0.1",
|
||||||
"xlsx": "^0.16.8",
|
"xlsx": "^0.16.8",
|
||||||
@ -45,11 +45,11 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^11.0.0",
|
"@commitlint/cli": "^11.0.0",
|
||||||
"@commitlint/config-conventional": "^11.0.0",
|
"@commitlint/config-conventional": "^11.0.0",
|
||||||
"@iconify/json": "^1.1.254",
|
"@iconify/json": "^1.1.258",
|
||||||
"@ls-lint/ls-lint": "^1.9.2",
|
"@ls-lint/ls-lint": "^1.9.2",
|
||||||
"@purge-icons/generated": "^0.4.1",
|
"@purge-icons/generated": "^0.4.1",
|
||||||
"@types/echarts": "^4.9.0",
|
"@types/echarts": "^4.9.0",
|
||||||
"@types/fs-extra": "^9.0.2",
|
"@types/fs-extra": "^9.0.4",
|
||||||
"@types/koa-static": "^4.0.1",
|
"@types/koa-static": "^4.0.1",
|
||||||
"@types/lodash-es": "^4.17.3",
|
"@types/lodash-es": "^4.17.3",
|
||||||
"@types/mockjs": "^1.0.3",
|
"@types/mockjs": "^1.0.3",
|
||||||
|
@ -24,7 +24,7 @@ export const footerProps = {
|
|||||||
okButtonProps: Object as PropType<any>,
|
okButtonProps: Object as PropType<any>,
|
||||||
okText: {
|
okText: {
|
||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
default: '保存',
|
default: '确认',
|
||||||
},
|
},
|
||||||
okType: {
|
okType: {
|
||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
|
@ -44,7 +44,6 @@
|
|||||||
import { useFormValues } from './hooks/useFormValues';
|
import { useFormValues } from './hooks/useFormValues';
|
||||||
import useAdvanced from './hooks/useAdvanced';
|
import useAdvanced from './hooks/useAdvanced';
|
||||||
import { useFormAction } from './hooks/useFormAction';
|
import { useFormAction } from './hooks/useFormAction';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicForm',
|
name: 'BasicForm',
|
||||||
components: { FormItem, Form, Row, FormAction },
|
components: { FormItem, Form, Row, FormAction },
|
||||||
|
@ -18,7 +18,7 @@ export default defineComponent({
|
|||||||
// icon size
|
// icon size
|
||||||
size: {
|
size: {
|
||||||
type: [String, Number] as PropType<string | number>,
|
type: [String, Number] as PropType<string | number>,
|
||||||
default: 14,
|
default: 16,
|
||||||
},
|
},
|
||||||
prefix: {
|
prefix: {
|
||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
import { ButtonProps } from 'ant-design-vue/es/button/buttonTypes';
|
||||||
export const modalProps = {
|
export const modalProps = {
|
||||||
visible: Boolean as PropType<boolean>,
|
visible: Boolean as PropType<boolean>,
|
||||||
// open drag
|
// open drag
|
||||||
@ -16,7 +17,7 @@ export const modalProps = {
|
|||||||
},
|
},
|
||||||
okText: {
|
okText: {
|
||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
default: '保存',
|
default: '确认',
|
||||||
},
|
},
|
||||||
closeFunc: Function as PropType<() => Promise<boolean>>,
|
closeFunc: Function as PropType<() => Promise<boolean>>,
|
||||||
};
|
};
|
||||||
@ -100,9 +101,9 @@ export const basicProps = Object.assign({}, modalProps, {
|
|||||||
default: 'primary',
|
default: 'primary',
|
||||||
},
|
},
|
||||||
|
|
||||||
okButtonProps: Object as PropType<any>,
|
okButtonProps: Object as PropType<ButtonProps>,
|
||||||
|
|
||||||
cancelButtonProps: Object as PropType<any>,
|
cancelButtonProps: Object as PropType<ButtonProps>,
|
||||||
|
|
||||||
title: {
|
title: {
|
||||||
type: String as PropType<string>,
|
type: String as PropType<string>,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
import { defineComponent, watchEffect, PropType, ref, unref } from 'vue';
|
import { defineComponent, watchEffect, PropType, ref, unref } from 'vue';
|
||||||
import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
|
import { toCanvas, QRCodeRenderersOptions, LogoType } from './qrcodePlus';
|
||||||
import { toDataURL } from 'qrcode';
|
import { toDataURL } from 'qrcode';
|
||||||
import { downloadByUrl } from '/@/utils/file/FileDownload';
|
import { downloadByUrl } from '/@/utils/file/download';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'QrCode',
|
name: 'QrCode',
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
class="basic-table"
|
class="basic-table"
|
||||||
:class="{
|
:class="{
|
||||||
'table-form-container': getBindValues.useSearchForm,
|
'table-form-container': getBindValues.useSearchForm,
|
||||||
|
inset: getBindValues.inset,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<BasicForm
|
<BasicForm
|
||||||
|
@ -84,7 +84,7 @@ export function useDataSource(
|
|||||||
const { api, searchInfo, fetchSetting, beforeFetch, afterFetch, useSearchForm } = unref(
|
const { api, searchInfo, fetchSetting, beforeFetch, afterFetch, useSearchForm } = unref(
|
||||||
propsRef
|
propsRef
|
||||||
);
|
);
|
||||||
if (!api && !isFunction(api)) return;
|
if (!api || !isFunction(api)) return;
|
||||||
try {
|
try {
|
||||||
loadingRef.value = true;
|
loadingRef.value = true;
|
||||||
const { pageField, sizeField, listField, totalField } = fetchSetting || FETCH_SETTING;
|
const { pageField, sizeField, listField, totalField } = fetchSetting || FETCH_SETTING;
|
||||||
|
@ -16,7 +16,10 @@ export const basicProps = {
|
|||||||
tableSetting: {
|
tableSetting: {
|
||||||
type: Object as PropType<TableSetting>,
|
type: Object as PropType<TableSetting>,
|
||||||
},
|
},
|
||||||
|
inset: {
|
||||||
|
type: Boolean as PropType<boolean>,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
sortFn: {
|
sortFn: {
|
||||||
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
type: Function as PropType<(sortInfo: SorterResult) => any>,
|
||||||
default: DEFAULT_SORT_FN,
|
default: DEFAULT_SORT_FN,
|
||||||
|
@ -49,6 +49,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.inset {
|
||||||
|
.ant-table-wrapper {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
.ant-table {
|
.ant-table {
|
||||||
border: none;
|
border: none;
|
||||||
|
@ -126,6 +126,8 @@ export interface TableSetting {
|
|||||||
export interface BasicTableProps<T = any> {
|
export interface BasicTableProps<T = any> {
|
||||||
// 自定义排序方法
|
// 自定义排序方法
|
||||||
sortFn?: (sortInfo: SorterResult) => any;
|
sortFn?: (sortInfo: SorterResult) => any;
|
||||||
|
// 取消表格的默认padding
|
||||||
|
inset?: boolean;
|
||||||
// 显示表格设置
|
// 显示表格设置
|
||||||
showTableSetting?: boolean;
|
showTableSetting?: boolean;
|
||||||
tableSetting?: TableSetting;
|
tableSetting?: TableSetting;
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
export { default as UploadContainer } from './src/UploadContainer.vue';
|
export { default as BasicUpload } from './src/BasicUpload.vue';
|
||||||
// export * from './src/types';
|
// export * from './src/types';
|
||||||
|
99
src/components/Upload/src/BasicUpload.vue
Normal file
99
src/components/Upload/src/BasicUpload.vue
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<a-button-group>
|
||||||
|
<a-button type="primary" @click="openUploadModal" preIcon="ant-design:cloud-upload-outlined">
|
||||||
|
上传
|
||||||
|
</a-button>
|
||||||
|
<Tooltip placement="bottom" v-if="showPreview">
|
||||||
|
<template #title>
|
||||||
|
已上传
|
||||||
|
<template v-if="fileListRef.length">{{ fileListRef.length }}</template>
|
||||||
|
</template>
|
||||||
|
<a-button @click="openPreviewModal">
|
||||||
|
<Icon icon="ant-design:eye-outlined" />
|
||||||
|
<template v-if="fileListRef.length && showPreviewNumber">
|
||||||
|
{{ fileListRef.length }}
|
||||||
|
</template>
|
||||||
|
</a-button>
|
||||||
|
</Tooltip>
|
||||||
|
</a-button-group>
|
||||||
|
|
||||||
|
<UploadModal v-bind="bindValue" @register="registerUploadModal" @change="handleChange" />
|
||||||
|
|
||||||
|
<UploadPreviewModal
|
||||||
|
:value="fileListRef"
|
||||||
|
@register="registerPreviewModal"
|
||||||
|
@list-change="handlePreviewChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, ref, watch, unref, computed } from 'vue';
|
||||||
|
|
||||||
|
import UploadModal from './UploadModal.vue';
|
||||||
|
import UploadPreviewModal from './UploadPreviewModal.vue';
|
||||||
|
import Icon from '/@/components/Icon';
|
||||||
|
import { Tooltip } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import { useModal } from '/@/components/Modal';
|
||||||
|
|
||||||
|
import { uploadContainerProps } from './props';
|
||||||
|
import { omit } from 'lodash-es';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: { UploadModal, UploadPreviewModal, Icon, Tooltip },
|
||||||
|
props: uploadContainerProps,
|
||||||
|
setup(props, { emit, attrs }) {
|
||||||
|
// 上传modal
|
||||||
|
const [registerUploadModal, { openModal: openUploadModal }] = useModal();
|
||||||
|
|
||||||
|
// 预览modal
|
||||||
|
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
|
||||||
|
|
||||||
|
const fileListRef = ref<string[]>([]);
|
||||||
|
|
||||||
|
const showPreview = computed(() => {
|
||||||
|
const { emptyHidePreview } = props;
|
||||||
|
if (!emptyHidePreview) return true;
|
||||||
|
return emptyHidePreview ? fileListRef.value.length > 0 : true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const bindValue = computed(() => {
|
||||||
|
const value = { ...attrs, ...props };
|
||||||
|
return omit(value, 'onChange');
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(value = []) => {
|
||||||
|
fileListRef.value = value;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 上传modal保存操作
|
||||||
|
function handleChange(urls: string[]) {
|
||||||
|
fileListRef.value = [...unref(fileListRef), ...(urls || [])];
|
||||||
|
emit('change', fileListRef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 预览modal保存操作
|
||||||
|
function handlePreviewChange(urls: string[]) {
|
||||||
|
fileListRef.value = [...(urls || [])];
|
||||||
|
emit('change', fileListRef.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
registerUploadModal,
|
||||||
|
openUploadModal,
|
||||||
|
handleChange,
|
||||||
|
handlePreviewChange,
|
||||||
|
registerPreviewModal,
|
||||||
|
openPreviewModal,
|
||||||
|
fileListRef,
|
||||||
|
showPreview,
|
||||||
|
bindValue,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -5,25 +5,22 @@
|
|||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, PropType } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
fileUrl: {
|
fileUrl: {
|
||||||
type: String,
|
type: String as PropType<string>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
fileType: {
|
fileType: {
|
||||||
type: String,
|
type: String as PropType<string>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
fileName: {
|
fileName: {
|
||||||
type: String,
|
type: String as PropType<string>,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
|
||||||
return {};
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<a-button-group>
|
|
||||||
<a-button type="primary" @click="openUploadModal">上传</a-button>
|
|
||||||
<a-button @click="openPreviewModal">
|
|
||||||
<Icon icon="ant-design:eye-outlined" />
|
|
||||||
</a-button>
|
|
||||||
</a-button-group>
|
|
||||||
<UploadModal v-bind="$props" @register="registerUploadModal" @change="handleChange" />
|
|
||||||
<UploadPreviewModal
|
|
||||||
:value="fileListRef"
|
|
||||||
@register="registerPreviewModal"
|
|
||||||
@change="handlePreviewChange"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent, ref, watch, unref } from 'vue';
|
|
||||||
import { useModal } from '/@/components/Modal';
|
|
||||||
import UploadModal from './UploadModal.vue';
|
|
||||||
import { uploadContainerProps } from './props';
|
|
||||||
import UploadPreviewModal from './UploadPreviewModal.vue';
|
|
||||||
import Icon from '/@/components/Icon/index';
|
|
||||||
export default defineComponent({
|
|
||||||
components: { UploadModal, UploadPreviewModal, Icon },
|
|
||||||
props: uploadContainerProps,
|
|
||||||
setup(props, { emit }) {
|
|
||||||
// 上传modal
|
|
||||||
const [registerUploadModal, { openModal: openUploadModal }] = useModal();
|
|
||||||
// 预览modal
|
|
||||||
const [registerPreviewModal, { openModal: openPreviewModal }] = useModal();
|
|
||||||
|
|
||||||
const fileListRef = ref<string[]>([]);
|
|
||||||
watch(
|
|
||||||
() => props.value,
|
|
||||||
(value) => {
|
|
||||||
fileListRef.value = [...(value || [])];
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
);
|
|
||||||
// 上传modal保存操作
|
|
||||||
function handleChange(urls: string[]) {
|
|
||||||
fileListRef.value = [...unref(fileListRef), ...(urls || [])];
|
|
||||||
emit('change', fileListRef.value);
|
|
||||||
}
|
|
||||||
// 预览modal保存操作
|
|
||||||
function handlePreviewChange(urls: string[]) {
|
|
||||||
fileListRef.value = [...(urls || [])];
|
|
||||||
emit('change', fileListRef.value);
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
registerUploadModal,
|
|
||||||
openUploadModal,
|
|
||||||
handleChange,
|
|
||||||
handlePreviewChange,
|
|
||||||
registerPreviewModal,
|
|
||||||
openPreviewModal,
|
|
||||||
fileListRef,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
</script>
|
|
@ -1,31 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasicModal
|
<BasicModal
|
||||||
|
width="800px"
|
||||||
|
title="上传"
|
||||||
|
okText="保存"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
@register="register"
|
@register="register"
|
||||||
@ok="handleOk"
|
@ok="handleOk"
|
||||||
:closeFunc="handleCloseFunc"
|
:closeFunc="handleCloseFunc"
|
||||||
:maskClosable="false"
|
:maskClosable="false"
|
||||||
width="800px"
|
:keyboard="false"
|
||||||
title="上传组件"
|
|
||||||
wrapClassName="upload-modal"
|
wrapClassName="upload-modal"
|
||||||
:okButtonProps="{ disabled: isUploadingRef }"
|
:okButtonProps="getOkButtonProps"
|
||||||
:cancelButtonProps="{ disabled: isUploadingRef }"
|
:cancelButtonProps="{ disabled: isUploadingRef }"
|
||||||
>
|
>
|
||||||
<template #centerdFooter>
|
<template #centerdFooter>
|
||||||
<a-button @click="handleStartUpload" color="success" :loading="isUploadingRef">
|
<a-button
|
||||||
{{ isUploadingRef ? '上传中' : '开始上传' }}
|
@click="handleStartUpload"
|
||||||
|
color="success"
|
||||||
|
:disabled="!getIsSelectFile"
|
||||||
|
:loading="isUploadingRef"
|
||||||
|
>
|
||||||
|
{{ getUploadBtnText }}
|
||||||
</a-button>
|
</a-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<BasicTable @register="registerTable" :dataSource="fileListRef">
|
||||||
|
<template #toolbar>
|
||||||
<Upload :accept="getStringAccept" :multiple="multiple" :before-upload="beforeUpload">
|
<Upload :accept="getStringAccept" :multiple="multiple" :before-upload="beforeUpload">
|
||||||
<a-button type="primary"> 选择文件 </a-button>
|
<a-button type="primary"> 选择文件 </a-button>
|
||||||
<span class="px-2">{{ getHelpText }}</span>
|
|
||||||
</Upload>
|
</Upload>
|
||||||
<BasicTable @register="registerTable" :dataSource="fileListRef" />
|
</template>
|
||||||
|
<template #tableTitle>
|
||||||
|
<Alert :message="getHelpText" type="info" banner></Alert>
|
||||||
|
</template>
|
||||||
|
</BasicTable>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, reactive, ref, toRef, unref } from 'vue';
|
import { defineComponent, reactive, ref, toRefs, unref, computed } from 'vue';
|
||||||
import { Upload } from 'ant-design-vue';
|
import { Upload, Alert } from 'ant-design-vue';
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { BasicTable, useTable } from '/@/components/Table';
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
// hooks
|
// hooks
|
||||||
@ -39,23 +52,56 @@
|
|||||||
import { checkFileType, checkImgType, getBase64WithFile } from './utils';
|
import { checkFileType, checkImgType, getBase64WithFile } from './utils';
|
||||||
import { buildUUID } from '/@/utils/uuid';
|
import { buildUUID } from '/@/utils/uuid';
|
||||||
import { createImgPreview } from '/@/components/Preview/index';
|
import { createImgPreview } from '/@/components/Preview/index';
|
||||||
import { uploadApi } from '/@/api/demo/upload';
|
import { uploadApi } from '/@/api/sys/upload';
|
||||||
|
import { isFunction } from '/@/utils/is';
|
||||||
|
import { warn } from '/@/utils/log';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicModal, Upload, BasicTable },
|
components: { BasicModal, Upload, BasicTable, Alert },
|
||||||
props: basicProps,
|
props: basicProps,
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const [register, { closeModal }] = useModalInner();
|
// 是否正在上传
|
||||||
const { getAccept, getStringAccept, getHelpText } = useUploadType({
|
const isUploadingRef = ref(false);
|
||||||
acceptRef: toRef(props, 'accept'),
|
const fileListRef = ref<FileItem[]>([]);
|
||||||
helpTextRef: toRef(props, 'helpText'),
|
const state = reactive<{ fileList: FileItem[] }>({
|
||||||
maxNumberRef: toRef(props, 'maxNumber'),
|
fileList: [],
|
||||||
maxSizeRef: toRef(props, 'maxSize'),
|
});
|
||||||
|
|
||||||
|
const [register, { closeModal }] = useModalInner();
|
||||||
|
|
||||||
|
const { accept, helpText, maxNumber, maxSize } = toRefs(props);
|
||||||
|
const { getAccept, getStringAccept, getHelpText } = useUploadType({
|
||||||
|
acceptRef: accept,
|
||||||
|
helpTextRef: helpText,
|
||||||
|
maxNumberRef: maxNumber,
|
||||||
|
maxSizeRef: maxSize,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fileListRef = ref<FileItem[]>([]);
|
|
||||||
const state = reactive<{ fileList: FileItem[] }>({ fileList: [] });
|
|
||||||
const { createMessage } = useMessage();
|
const { createMessage } = useMessage();
|
||||||
|
|
||||||
|
const getIsSelectFile = computed(() => {
|
||||||
|
return (
|
||||||
|
fileListRef.value.length > 0 &&
|
||||||
|
!fileListRef.value.every((item) => item.status === UploadResultStatus.SUCCESS)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getOkButtonProps = computed(() => {
|
||||||
|
const someSuccess = fileListRef.value.some(
|
||||||
|
(item) => item.status === UploadResultStatus.SUCCESS
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
disabled: isUploadingRef.value || fileListRef.value.length === 0 || !someSuccess,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const getUploadBtnText = computed(() => {
|
||||||
|
const someError = fileListRef.value.some(
|
||||||
|
(item) => item.status === UploadResultStatus.ERROR
|
||||||
|
);
|
||||||
|
return isUploadingRef.value ? '上传中' : someError ? '重新上传失败文件' : '开始上传';
|
||||||
|
});
|
||||||
|
|
||||||
// 上传前校验
|
// 上传前校验
|
||||||
function beforeUpload(file: File) {
|
function beforeUpload(file: File) {
|
||||||
const { size, name } = file;
|
const { size, name } = file;
|
||||||
@ -73,6 +119,14 @@
|
|||||||
createMessage.error!(`只能上传${accept.join(',')}格式文件`);
|
createMessage.error!(`只能上传${accept.join(',')}格式文件`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const commonItem = {
|
||||||
|
uuid: buildUUID(),
|
||||||
|
file,
|
||||||
|
size,
|
||||||
|
name,
|
||||||
|
percent: 0,
|
||||||
|
type: name.split('.').pop(),
|
||||||
|
};
|
||||||
// 生成图片缩略图
|
// 生成图片缩略图
|
||||||
if (checkImgType(file)) {
|
if (checkImgType(file)) {
|
||||||
// beforeUpload,如果异步会调用自带上传方法
|
// beforeUpload,如果异步会调用自带上传方法
|
||||||
@ -81,29 +135,13 @@
|
|||||||
fileListRef.value = [
|
fileListRef.value = [
|
||||||
...unref(fileListRef),
|
...unref(fileListRef),
|
||||||
{
|
{
|
||||||
uuid: buildUUID(),
|
|
||||||
file,
|
|
||||||
thumbUrl,
|
thumbUrl,
|
||||||
size,
|
...commonItem,
|
||||||
name,
|
|
||||||
percent: 0,
|
|
||||||
type: name.split('.').pop(),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
fileListRef.value = [
|
fileListRef.value = [...unref(fileListRef), commonItem];
|
||||||
...unref(fileListRef),
|
|
||||||
{
|
|
||||||
uuid: buildUUID(),
|
|
||||||
|
|
||||||
file,
|
|
||||||
size,
|
|
||||||
name,
|
|
||||||
percent: 0,
|
|
||||||
type: name.split('.').pop(),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -112,6 +150,7 @@
|
|||||||
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
|
const index = fileListRef.value.findIndex((item) => item.uuid === record.uuid);
|
||||||
index !== -1 && fileListRef.value.splice(index, 1);
|
index !== -1 && fileListRef.value.splice(index, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 预览
|
// 预览
|
||||||
function handlePreview(record: FileItem) {
|
function handlePreview(record: FileItem) {
|
||||||
const { thumbUrl = '' } = record;
|
const { thumbUrl = '' } = record;
|
||||||
@ -119,19 +158,18 @@
|
|||||||
imageList: [thumbUrl],
|
imageList: [thumbUrl],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const [registerTable] = useTable({
|
|
||||||
columns: createTableColumns(),
|
|
||||||
actionColumn: createActionColumn(handleRemove, handlePreview),
|
|
||||||
pagination: false,
|
|
||||||
});
|
|
||||||
// 是否正在上传
|
|
||||||
const isUploadingRef = ref(false);
|
|
||||||
async function uploadApiByItem(item: FileItem) {
|
async function uploadApiByItem(item: FileItem) {
|
||||||
|
const { api } = props;
|
||||||
|
if (!api || !isFunction(api)) {
|
||||||
|
return warn('upload api must exist and be a function');
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
item.status = UploadResultStatus.UPLOADING;
|
item.status = UploadResultStatus.UPLOADING;
|
||||||
|
|
||||||
const { data } = await uploadApi(
|
const { data } = await uploadApi(
|
||||||
{
|
{
|
||||||
|
...(props.uploadParams || {}),
|
||||||
file: item.file,
|
file: item.file,
|
||||||
},
|
},
|
||||||
function onUploadProgress(progressEvent: ProgressEvent) {
|
function onUploadProgress(progressEvent: ProgressEvent) {
|
||||||
@ -154,32 +192,42 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击开始上传
|
// 点击开始上传
|
||||||
async function handleStartUpload() {
|
async function handleStartUpload() {
|
||||||
|
const { maxNumber } = props;
|
||||||
|
if (fileListRef.value.length > maxNumber) {
|
||||||
|
return createMessage.warning(`最多只能上传${maxNumber}个文件`);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
isUploadingRef.value = true;
|
isUploadingRef.value = true;
|
||||||
|
// 只上传不是成功状态的
|
||||||
|
const uploadFileList =
|
||||||
|
fileListRef.value.filter((item) => item.status !== UploadResultStatus.SUCCESS) || [];
|
||||||
const data = await Promise.all(
|
const data = await Promise.all(
|
||||||
unref(fileListRef).map((item) => {
|
uploadFileList.map((item) => {
|
||||||
return uploadApiByItem(item);
|
return uploadApiByItem(item);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
isUploadingRef.value = false;
|
isUploadingRef.value = false;
|
||||||
// 生产环境:抛出错误
|
// 生产环境:抛出错误
|
||||||
const errorList = data.filter((item) => !item.success);
|
const errorList = data.filter((item: any) => !item.success);
|
||||||
if (errorList.length > 0) {
|
if (errorList.length > 0) throw errorList;
|
||||||
throw errorList;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isUploadingRef.value = false;
|
isUploadingRef.value = false;
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击保存
|
// 点击保存
|
||||||
function handleOk() {
|
function handleOk() {
|
||||||
// TODO: 没起作用:okButtonProps={{ disabled: state.isUploading }}
|
const { maxNumber } = props;
|
||||||
|
|
||||||
|
if (fileListRef.value.length > maxNumber) {
|
||||||
|
return createMessage.warning(`最多只能上传${maxNumber}个文件`);
|
||||||
|
}
|
||||||
if (isUploadingRef.value) {
|
if (isUploadingRef.value) {
|
||||||
createMessage.warning('请等待文件上传后,保存');
|
return createMessage.warning('请等待文件上传后,保存');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
const fileList: string[] = [];
|
const fileList: string[] = [];
|
||||||
|
|
||||||
@ -189,18 +237,15 @@
|
|||||||
fileList.push(responseData.url);
|
fileList.push(responseData.url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 存在一个上传成功的即可保存
|
// 存在一个上传成功的即可保存
|
||||||
|
|
||||||
if (fileList.length <= 0) {
|
if (fileList.length <= 0) {
|
||||||
createMessage.warning('没有上传成功的文件,无法保存');
|
return createMessage.warning('没有上传成功的文件,无法保存');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
console.log(fileList);
|
|
||||||
emit('change', fileList);
|
|
||||||
fileListRef.value = [];
|
fileListRef.value = [];
|
||||||
closeModal();
|
closeModal();
|
||||||
|
emit('change', fileList);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击关闭:则所有操作不保存,包括上传的
|
// 点击关闭:则所有操作不保存,包括上传的
|
||||||
function handleCloseFunc() {
|
function handleCloseFunc() {
|
||||||
if (!isUploadingRef.value) {
|
if (!isUploadingRef.value) {
|
||||||
@ -211,11 +256,22 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const [registerTable] = useTable({
|
||||||
|
columns: createTableColumns(),
|
||||||
|
actionColumn: createActionColumn(handleRemove, handlePreview),
|
||||||
|
pagination: false,
|
||||||
|
inset: true,
|
||||||
|
scroll: {
|
||||||
|
y: 3000,
|
||||||
|
},
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
register,
|
register,
|
||||||
closeModal,
|
closeModal,
|
||||||
getHelpText,
|
getHelpText,
|
||||||
getStringAccept,
|
getStringAccept,
|
||||||
|
getOkButtonProps,
|
||||||
beforeUpload,
|
beforeUpload,
|
||||||
registerTable,
|
registerTable,
|
||||||
fileListRef,
|
fileListRef,
|
||||||
@ -224,14 +280,13 @@
|
|||||||
handleStartUpload,
|
handleStartUpload,
|
||||||
handleOk,
|
handleOk,
|
||||||
handleCloseFunc,
|
handleCloseFunc,
|
||||||
|
getIsSelectFile,
|
||||||
|
getUploadBtnText,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="less">
|
<style lang="less">
|
||||||
// /deep/ .ant-upload-list {
|
|
||||||
// display: none;
|
|
||||||
// }
|
|
||||||
.upload-modal {
|
.upload-modal {
|
||||||
.ant-upload-list {
|
.ant-upload-list {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasicModal
|
<BasicModal
|
||||||
|
width="800px"
|
||||||
|
title="预览"
|
||||||
wrapClassName="upload-preview-modal"
|
wrapClassName="upload-preview-modal"
|
||||||
v-bind="$attrs"
|
v-bind="$attrs"
|
||||||
width="800px"
|
|
||||||
@register="register"
|
@register="register"
|
||||||
title="预览"
|
|
||||||
:showOkBtn="false"
|
:showOkBtn="false"
|
||||||
>
|
>
|
||||||
<BasicTable @register="registerTable" :dataSource="fileListRef" />
|
<BasicTable @register="registerTable" :dataSource="fileListRef" />
|
||||||
@ -12,17 +12,18 @@
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, watch, ref, unref } from 'vue';
|
import { defineComponent, watch, ref, unref } from 'vue';
|
||||||
|
|
||||||
import { BasicTable, useTable } from '/@/components/Table';
|
import { BasicTable, useTable } from '/@/components/Table';
|
||||||
import { createPreviewColumns, createPreviewActionColumn } from './data';
|
|
||||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
import { priviewProps } from './props';
|
import { previewProps } from './props';
|
||||||
import { PreviewFileItem } from './types';
|
import { PreviewFileItem } from './types';
|
||||||
import { createImgPreview } from '/@/components/Preview/index';
|
import { createImgPreview } from '/@/components/Preview/index';
|
||||||
import { downloadByUrl } from '/@/utils/file/FileDownload';
|
import { downloadByUrl } from '/@/utils/file/download';
|
||||||
|
|
||||||
|
import { createPreviewColumns, createPreviewActionColumn } from './data';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { BasicModal, BasicTable },
|
components: { BasicModal, BasicTable },
|
||||||
props: priviewProps,
|
props: previewProps,
|
||||||
setup(props, { emit }) {
|
setup(props, { emit }) {
|
||||||
const [register, { closeModal }] = useModalInner();
|
const [register, { closeModal }] = useModalInner();
|
||||||
const fileListRef = ref<PreviewFileItem[]>([]);
|
const fileListRef = ref<PreviewFileItem[]>([]);
|
||||||
@ -43,17 +44,19 @@
|
|||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
// 删除
|
// 删除
|
||||||
function handleRemove(record: PreviewFileItem) {
|
function handleRemove(record: PreviewFileItem) {
|
||||||
const index = fileListRef.value.findIndex((item) => item.url === record.url);
|
const index = fileListRef.value.findIndex((item) => item.url === record.url);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
fileListRef.value.splice(index, 1);
|
fileListRef.value.splice(index, 1);
|
||||||
emit(
|
emit(
|
||||||
'change',
|
'list-change',
|
||||||
fileListRef.value.map((item) => item.url)
|
fileListRef.value.map((item) => item.url)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 预览
|
// 预览
|
||||||
function handlePreview(record: PreviewFileItem) {
|
function handlePreview(record: PreviewFileItem) {
|
||||||
const { url = '' } = record;
|
const { url = '' } = record;
|
||||||
@ -61,16 +64,19 @@
|
|||||||
imageList: [url],
|
imageList: [url],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 下载
|
// 下载
|
||||||
function handleDownload(record: PreviewFileItem) {
|
function handleDownload(record: PreviewFileItem) {
|
||||||
const { url = '' } = record;
|
const { url = '' } = record;
|
||||||
downloadByUrl({ url });
|
downloadByUrl({ url });
|
||||||
}
|
}
|
||||||
|
|
||||||
const [registerTable] = useTable({
|
const [registerTable] = useTable({
|
||||||
columns: createPreviewColumns(),
|
columns: createPreviewColumns(),
|
||||||
pagination: false,
|
pagination: false,
|
||||||
actionColumn: createPreviewActionColumn({ handleRemove, handlePreview, handleDownload }),
|
actionColumn: createPreviewActionColumn({ handleRemove, handlePreview, handleDownload }),
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
register,
|
register,
|
||||||
closeModal,
|
closeModal,
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
// import { BasicColumn, TableAction, ActionItem } from '@/components/table';
|
|
||||||
import { checkImgType, isImgTypeByName } from './utils';
|
import { checkImgType, isImgTypeByName } from './utils';
|
||||||
// import ThumnUrl from './ThumbUrl.vue';
|
import { Progress, Tag } from 'ant-design-vue';
|
||||||
import { Progress } from 'ant-design-vue';
|
|
||||||
import { FileItem, PreviewFileItem, UploadResultStatus } from './types';
|
import { FileItem, PreviewFileItem, UploadResultStatus } from './types';
|
||||||
// import { ElecArchivesSaveResult } from '@/api/biz/file/model/fileModel';
|
|
||||||
// import { quryFile } from '@/api/biz/file/file';
|
|
||||||
import { BasicColumn, ActionItem, TableAction } from '/@/components/Table/index';
|
import { BasicColumn, ActionItem, TableAction } from '/@/components/Table/index';
|
||||||
|
|
||||||
// 文件上传列表
|
// 文件上传列表
|
||||||
@ -16,8 +12,7 @@ export function createTableColumns(): BasicColumn[] {
|
|||||||
width: 100,
|
width: 100,
|
||||||
customRender: ({ record }) => {
|
customRender: ({ record }) => {
|
||||||
const { thumbUrl, type } = (record as FileItem) || {};
|
const { thumbUrl, type } = (record as FileItem) || {};
|
||||||
return <span>{thumbUrl ? <img src={thumbUrl} style={{ width: '50px' }} /> : type}</span>;
|
return <span>{thumbUrl ? <img style={{ maxWidth: '60px' }} src={thumbUrl} /> : type}</span>;
|
||||||
// return <ThumnUrl fileUrl={thumbUrl} fileType={type} fileName={type} />;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -26,7 +21,7 @@ export function createTableColumns(): BasicColumn[] {
|
|||||||
align: 'left',
|
align: 'left',
|
||||||
customRender: ({ text, record }) => {
|
customRender: ({ text, record }) => {
|
||||||
const { percent, status: uploadStatus } = (record as FileItem) || {};
|
const { percent, status: uploadStatus } = (record as FileItem) || {};
|
||||||
let status = 'normal';
|
let status: 'normal' | 'exception' | 'active' | 'success' = 'normal';
|
||||||
if (uploadStatus === UploadResultStatus.ERROR) {
|
if (uploadStatus === UploadResultStatus.ERROR) {
|
||||||
status = 'exception';
|
status = 'exception';
|
||||||
} else if (uploadStatus === UploadResultStatus.UPLOADING) {
|
} else if (uploadStatus === UploadResultStatus.UPLOADING) {
|
||||||
@ -63,11 +58,11 @@ export function createTableColumns(): BasicColumn[] {
|
|||||||
width: 100,
|
width: 100,
|
||||||
customRender: ({ text }) => {
|
customRender: ({ text }) => {
|
||||||
if (text === UploadResultStatus.SUCCESS) {
|
if (text === UploadResultStatus.SUCCESS) {
|
||||||
return '上传成功';
|
return <Tag color="green">{() => '上传成功'}</Tag>;
|
||||||
} else if (text === UploadResultStatus.ERROR) {
|
} else if (text === UploadResultStatus.ERROR) {
|
||||||
return '上传失败';
|
return <Tag color="red">{() => '上传失败'}</Tag>;
|
||||||
} else if (text === UploadResultStatus.UPLOADING) {
|
} else if (text === UploadResultStatus.UPLOADING) {
|
||||||
return '上传中';
|
return <Tag color="blue">{() => '上传中'}</Tag>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return text;
|
return text;
|
||||||
@ -85,6 +80,7 @@ export function createActionColumn(handleRemove: Function, handlePreview: Functi
|
|||||||
const actions: ActionItem[] = [
|
const actions: ActionItem[] = [
|
||||||
{
|
{
|
||||||
label: '删除',
|
label: '删除',
|
||||||
|
color: 'error',
|
||||||
onClick: handleRemove.bind(null, record),
|
onClick: handleRemove.bind(null, record),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@ -125,9 +121,9 @@ export function createPreviewActionColumn({
|
|||||||
handlePreview,
|
handlePreview,
|
||||||
handleDownload,
|
handleDownload,
|
||||||
}: {
|
}: {
|
||||||
handleRemove: Function;
|
handleRemove: Fn;
|
||||||
handlePreview: Function;
|
handlePreview: Fn;
|
||||||
handleDownload: Function;
|
handleDownload: Fn;
|
||||||
}): BasicColumn {
|
}): BasicColumn {
|
||||||
return {
|
return {
|
||||||
width: 160,
|
width: 160,
|
||||||
@ -135,11 +131,12 @@ export function createPreviewActionColumn({
|
|||||||
dataIndex: 'action',
|
dataIndex: 'action',
|
||||||
fixed: false,
|
fixed: false,
|
||||||
customRender: ({ record }) => {
|
customRender: ({ record }) => {
|
||||||
const { url } = (record as PreviewFileItem) || {};
|
const { url } = (record || {}) as PreviewFileItem;
|
||||||
|
|
||||||
const actions: ActionItem[] = [
|
const actions: ActionItem[] = [
|
||||||
{
|
{
|
||||||
label: '删除',
|
label: '删除',
|
||||||
|
color: 'error',
|
||||||
onClick: handleRemove.bind(null, record),
|
onClick: handleRemove.bind(null, record),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -10,10 +10,10 @@ export const basicProps = {
|
|||||||
type: Number as PropType<number>,
|
type: Number as PropType<number>,
|
||||||
default: 2,
|
default: 2,
|
||||||
},
|
},
|
||||||
// 最大数量的文件,0不限制
|
// 最大数量的文件,Infinity不限制
|
||||||
maxNumber: {
|
maxNumber: {
|
||||||
type: Number as PropType<number>,
|
type: Number as PropType<number>,
|
||||||
default: 0,
|
default: Infinity,
|
||||||
},
|
},
|
||||||
// 根据后缀,或者其他
|
// 根据后缀,或者其他
|
||||||
accept: {
|
accept: {
|
||||||
@ -21,9 +21,18 @@ export const basicProps = {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
multiple: {
|
multiple: {
|
||||||
type: Boolean,
|
type: Boolean as PropType<boolean>,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
uploadParams: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: {},
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
type: Function as PropType<PromiseFn>,
|
||||||
|
default: null,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const uploadContainerProps = {
|
export const uploadContainerProps = {
|
||||||
@ -32,9 +41,17 @@ export const uploadContainerProps = {
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
...basicProps,
|
...basicProps,
|
||||||
|
showPreviewNumber: {
|
||||||
|
type: Boolean as PropType<boolean>,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
emptyHidePreview: {
|
||||||
|
type: Boolean as PropType<boolean>,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const priviewProps = {
|
export const previewProps = {
|
||||||
value: {
|
value: {
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { UploadApiResult } from '/@/api/demo/model/uploadModel';
|
import { UploadApiResult } from '/@/api/sys/model/uploadModel';
|
||||||
|
|
||||||
export enum UploadResultStatus {
|
export enum UploadResultStatus {
|
||||||
SUCCESS = 'success',
|
SUCCESS = 'success',
|
||||||
|
@ -42,12 +42,12 @@ export function useUploadType({
|
|||||||
|
|
||||||
const maxSize = unref(maxSizeRef);
|
const maxSize = unref(maxSizeRef);
|
||||||
if (maxSize) {
|
if (maxSize) {
|
||||||
helpTexts.push(`不超过${maxSize}MB`);
|
helpTexts.push(`单个文件不超过${maxSize}MB`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxNumber = unref(maxNumberRef);
|
const maxNumber = unref(maxNumberRef);
|
||||||
if (maxNumber) {
|
if (maxNumber && maxNumber !== Infinity) {
|
||||||
helpTexts.push(`最多可选择${maxNumber}个文件`);
|
helpTexts.push(`最多只能上传${maxNumber}个文件`);
|
||||||
}
|
}
|
||||||
return helpTexts.join(',');
|
return helpTexts.join(',');
|
||||||
});
|
});
|
||||||
|
@ -3,18 +3,17 @@ export function checkFileType(file: File, accepts: string[]) {
|
|||||||
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
|
// const reg = /\.(jpg|jpeg|png|gif|txt|doc|docx|xls|xlsx|xml)$/i;
|
||||||
const reg = new RegExp('\\.(' + newTypes + ')$', 'i');
|
const reg = new RegExp('\\.(' + newTypes + ')$', 'i');
|
||||||
|
|
||||||
if (!reg.test(file.name)) {
|
return reg.test(file.name);
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkImgType(file: File) {
|
export function checkImgType(file: File) {
|
||||||
return /\.(jpg|jpeg|png|gif)$/i.test(file.name);
|
return isImgTypeByName(file.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isImgTypeByName(name: string) {
|
export function isImgTypeByName(name: string) {
|
||||||
return /\.(jpg|jpeg|png|gif)$/i.test(name);
|
return /\.(jpg|jpeg|png|gif)$/i.test(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBase64WithFile(file: File) {
|
export function getBase64WithFile(file: File) {
|
||||||
return new Promise<{
|
return new Promise<{
|
||||||
result: string;
|
result: string;
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
// &.ant-btn-primary:not(.ant-btn-link) {
|
// &.ant-btn-primary:not(.ant-btn-link) {
|
||||||
// box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.08) !important;
|
// box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.12), 0 2px 4px 0 rgba(0, 0, 0, 0.08) !important;
|
||||||
// }
|
// }
|
||||||
|
// &-group {
|
||||||
|
// .ant-btn:not(:first-child) {
|
||||||
|
// bottom: 1px;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
&-primary {
|
&-primary {
|
||||||
color: @white;
|
color: @white;
|
||||||
|
@ -16,4 +16,4 @@
|
|||||||
@page-loading-z-index: 10000;
|
@page-loading-z-index: 10000;
|
||||||
|
|
||||||
// left-menu
|
// left-menu
|
||||||
@app-menu-item-height: 46px;
|
@app-menu-item-height: 44px;
|
||||||
|
@ -4,6 +4,9 @@ const menu: MenuModule = {
|
|||||||
menu: {
|
menu: {
|
||||||
name: '组件',
|
name: '组件',
|
||||||
path: '/comp',
|
path: '/comp',
|
||||||
|
tag: {
|
||||||
|
dot: true,
|
||||||
|
},
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: 'basic',
|
path: 'basic',
|
||||||
@ -38,10 +41,13 @@ const menu: MenuModule = {
|
|||||||
path: 'strength-meter',
|
path: 'strength-meter',
|
||||||
name: '密码强度组件',
|
name: '密码强度组件',
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// path: 'upload',
|
path: 'upload',
|
||||||
// name: '上传组件',
|
name: '上传组件',
|
||||||
// },
|
tag: {
|
||||||
|
content: 'new',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'scroll',
|
path: 'scroll',
|
||||||
name: '滚动组件',
|
name: '滚动组件',
|
||||||
|
8
src/types/global.d.ts
vendored
8
src/types/global.d.ts
vendored
@ -1,5 +1,9 @@
|
|||||||
declare interface Fn<T = any> {
|
declare interface Fn<T = any, R = T> {
|
||||||
(...arg: T[]): T;
|
(...arg: T[]): R;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare interface PromiseFn<T = any, R = T> {
|
||||||
|
(...arg: T[]): Promise<R>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 任意对象
|
// 任意对象
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
import { dataURLtoBlob } from './stream';
|
import { dataURLtoBlob, urlToBase64 } from './stream';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download online pictures
|
||||||
|
* @param url
|
||||||
|
* @param filename
|
||||||
|
* @param mime
|
||||||
|
* @param bom
|
||||||
|
*/
|
||||||
|
export function downloadByOnlineUrl(url: string, filename: string, mime?: string, bom?: BlobPart) {
|
||||||
|
urlToBase64(url).then((base64) => {
|
||||||
|
downloadByBase64(base64, filename, mime, bom);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download pictures based on base64
|
||||||
|
* @param buf
|
||||||
|
* @param filename
|
||||||
|
* @param mime
|
||||||
|
* @param bom
|
||||||
|
*/
|
||||||
export function downloadByBase64(buf: string, filename: string, mime?: string, bom?: BlobPart) {
|
export function downloadByBase64(buf: string, filename: string, mime?: string, bom?: BlobPart) {
|
||||||
const base64Buf = dataURLtoBlob(buf);
|
const base64Buf = dataURLtoBlob(buf);
|
||||||
downloadByData(base64Buf, filename, mime, bom);
|
downloadByData(base64Buf, filename, mime, bom);
|
@ -13,3 +13,29 @@ export function dataURLtoBlob(base64Buf: string): Blob {
|
|||||||
}
|
}
|
||||||
return new Blob([u8arr], { type: mime });
|
return new Blob([u8arr], { type: mime });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* img url to base64
|
||||||
|
* @param url
|
||||||
|
*/
|
||||||
|
export function urlToBase64(url: string, mineType?: string): Promise<string> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let canvas = document.createElement('CANVAS') as Nullable<HTMLCanvasElement>;
|
||||||
|
const ctx = canvas!.getContext('2d');
|
||||||
|
|
||||||
|
const img = new Image();
|
||||||
|
img.crossOrigin = '';
|
||||||
|
img.onload = function () {
|
||||||
|
if (!canvas || !ctx) {
|
||||||
|
return reject();
|
||||||
|
}
|
||||||
|
canvas.height = img.height;
|
||||||
|
canvas.width = img.width;
|
||||||
|
ctx.drawImage(img, 0, 0);
|
||||||
|
const dataURL = canvas.toDataURL(mineType || 'image/png');
|
||||||
|
canvas = null;
|
||||||
|
resolve(dataURL);
|
||||||
|
};
|
||||||
|
img.src = url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -118,11 +118,8 @@ export class VAxios {
|
|||||||
Object.keys(params.data).forEach((key) => {
|
Object.keys(params.data).forEach((key) => {
|
||||||
if (!params.data) return;
|
if (!params.data) return;
|
||||||
const value = params.data[key];
|
const value = params.data[key];
|
||||||
// support key-value array data
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
value.forEach((item) => {
|
value.forEach((item) => {
|
||||||
// { list: [ 11, 22 ] }
|
|
||||||
// formData.append('list[]', 11);
|
|
||||||
formData.append(`${key}[]`, item);
|
formData.append(`${key}[]`, item);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -160,20 +160,18 @@ const transform: AxiosTransform = {
|
|||||||
try {
|
try {
|
||||||
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
if (code === 'ECONNABORTED' && message.indexOf('timeout') !== -1) {
|
||||||
createMessage.error('接口请求超时,请刷新页面重试!');
|
createMessage.error('接口请求超时,请刷新页面重试!');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (err && err.includes('Network Error')) {
|
if (err && err.includes('Network Error')) {
|
||||||
createErrorModal({
|
createErrorModal({
|
||||||
title: '网络异常',
|
title: '网络异常',
|
||||||
content: '请检查您的网络连接是否正常!',
|
content: '请检查您的网络连接是否正常!',
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
checkStatus(error.response && error.response.status, msg);
|
checkStatus(error.response && error.response.status, msg);
|
||||||
return error;
|
return Promise.reject(error);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,4 +38,5 @@ export interface UploadFileParams {
|
|||||||
file: File | Blob;
|
file: File | Blob;
|
||||||
// 文件名
|
// 文件名
|
||||||
filename?: string;
|
filename?: string;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,60 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<UploadContainer :maxSize="5" />
|
<a-alert message="基础示例" class="my-5"></a-alert>
|
||||||
|
<BasicUpload :maxSize="20" :maxNumber="10" @change="handleChange" :api="uploadApi" />
|
||||||
|
|
||||||
|
<a-alert message="嵌入表单,加入表单校验" class="my-5"></a-alert>
|
||||||
|
|
||||||
|
<BasicForm @register="register" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, h } from 'vue';
|
||||||
import { UploadContainer } from '/@/components/Upload/index';
|
import { BasicUpload } from '/@/components/Upload';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
||||||
|
|
||||||
|
import { uploadApi } from '/@/api/sys/upload';
|
||||||
// import { Alert } from 'ant-design-vue';
|
// import { Alert } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const schemas: FormSchema[] = [
|
||||||
|
{
|
||||||
|
field: 'field1',
|
||||||
|
component: 'Input',
|
||||||
|
label: '字段1',
|
||||||
|
colProps: {
|
||||||
|
span: 8,
|
||||||
|
},
|
||||||
|
rules: [{ required: true, type: 'array', message: '请选择上传文件' }],
|
||||||
|
render: ({ model, field }) => {
|
||||||
|
return h(BasicUpload, {
|
||||||
|
value: model[field],
|
||||||
|
api: uploadApi,
|
||||||
|
onChange: (val: string[]) => {
|
||||||
|
model[field] = val;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: { UploadContainer },
|
components: { BasicUpload, BasicForm },
|
||||||
setup() {
|
setup() {
|
||||||
return {};
|
const { createMessage } = useMessage();
|
||||||
|
const [register] = useForm({
|
||||||
|
labelWidth: 120,
|
||||||
|
schemas,
|
||||||
|
actionColOptions: {
|
||||||
|
span: 16,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
handleChange: (list: string[]) => {
|
||||||
|
createMessage.info(`已上传文件${JSON.stringify(list)}`);
|
||||||
|
},
|
||||||
|
uploadApi,
|
||||||
|
register,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -8,11 +8,21 @@
|
|||||||
|
|
||||||
<a-alert message="base64流下载" />
|
<a-alert message="base64流下载" />
|
||||||
<a-button type="primary" class="my-4" @click="handleDownloadByBase64"> base64流下载 </a-button>
|
<a-button type="primary" class="my-4" @click="handleDownloadByBase64"> base64流下载 </a-button>
|
||||||
|
|
||||||
|
<a-alert message="图片Url下载,如果有跨域问题,需要处理图片跨域" />
|
||||||
|
<a-button type="primary" class="my-4" @click="handleDownloadByOnlineUrl">
|
||||||
|
图片Url下载
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { downloadByUrl, downloadByData, downloadByBase64 } from '/@/utils/file/FileDownload';
|
import {
|
||||||
|
downloadByUrl,
|
||||||
|
downloadByData,
|
||||||
|
downloadByBase64,
|
||||||
|
downloadByOnlineUrl,
|
||||||
|
} from '/@/utils/file/download';
|
||||||
import imgBase64 from './imgBase64';
|
import imgBase64 from './imgBase64';
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
setup() {
|
setup() {
|
||||||
@ -24,15 +34,28 @@
|
|||||||
url: 'https://codeload.github.com/anncwb/vue-vben-admin-doc/zip/master',
|
url: 'https://codeload.github.com/anncwb/vue-vben-admin-doc/zip/master',
|
||||||
target: '_self',
|
target: '_self',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
downloadByUrl({
|
||||||
|
url: 'https://vebn.oss-cn-beijing.aliyuncs.com/vben/logo.png',
|
||||||
|
target: '_self',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleDownloadByBase64() {
|
function handleDownloadByBase64() {
|
||||||
downloadByBase64(imgBase64, 'logo.png');
|
downloadByBase64(imgBase64, 'logo.png');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDownloadByOnlineUrl() {
|
||||||
|
downloadByOnlineUrl(
|
||||||
|
'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5944817f47b8408e9f1442ece49d68ca~tplv-k3u1fbpfcp-watermark.image',
|
||||||
|
'logo.png'
|
||||||
|
);
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
handleDownloadByUrl,
|
handleDownloadByUrl,
|
||||||
handleDownByData,
|
handleDownByData,
|
||||||
handleDownloadByBase64,
|
handleDownloadByBase64,
|
||||||
|
handleDownloadByOnlineUrl,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
58
yarn.lock
58
yarn.lock
@ -1050,10 +1050,10 @@
|
|||||||
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
resolved "https://registry.npmjs.org/@iconify/iconify/-/iconify-2.0.0-rc.2.tgz#c4a95ddc06ca9b9496df03604e66fdefb39f4c4b"
|
||||||
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
integrity sha512-BybEHU5/I9EQ0CcwKAqmreZ2bMnAXrqLCTptAc6vPetHMbrXdZfejP5mt57e/8PNSt/qE7BHniU5PCYA+PGIHw==
|
||||||
|
|
||||||
"@iconify/json@^1.1.254":
|
"@iconify/json@^1.1.258":
|
||||||
version "1.1.256"
|
version "1.1.258"
|
||||||
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.256.tgz#0f138d421ab12faca2fdd49aaf4fbc0122db08e3"
|
resolved "https://registry.npmjs.org/@iconify/json/-/json-1.1.258.tgz#392064ae8fd4c6d542c21bb4d0d57d5860f38abb"
|
||||||
integrity sha512-CeLKbKL3lvq8afhR3LEyaBqXZDC52fgU0Ij3LbTRCwPUsumLNzhXA7MzN/f0JDYfXm9LShkfpgMcm00wQaANgg==
|
integrity sha512-x5DKhRrg8v1NWmClWa8zA80gWQ9xevivsUAF4s8CyAl/ZplBsEE1funKuuVcIKjexyE1UXb7uFWrUKt1fB5n1A==
|
||||||
|
|
||||||
"@koa/cors@^3.1.0":
|
"@koa/cors@^3.1.0":
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
@ -1316,10 +1316,10 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
"@types/fs-extra@^9.0.2":
|
"@types/fs-extra@^9.0.4":
|
||||||
version "9.0.3"
|
version "9.0.4"
|
||||||
resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.3.tgz#9996e5cce993508c32325380b429f04a1327523e"
|
resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.4.tgz#12553138cf0438db9a31cdc8b0a3aa9332eb67aa"
|
||||||
integrity sha512-NKdGoXLTFTRED3ENcfCsH8+ekV4gbsysanx2OPbstXVV6fZMgUCqTxubs6I9r7pbOJbFgVq1rpFtLURjKCZWUw==
|
integrity sha512-50GO5ez44lxK5MDH90DYHFFfqxH7+fTqEEnvguQRzJ/tY9qFrMSHLiYHite+F3SNmf7+LHC1eMXojuD+E3Qcyg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
@ -1725,18 +1725,18 @@
|
|||||||
vscode-languageserver-textdocument "^1.0.1"
|
vscode-languageserver-textdocument "^1.0.1"
|
||||||
vscode-uri "^2.1.2"
|
vscode-uri "^2.1.2"
|
||||||
|
|
||||||
"@vueuse/core@^4.0.0-beta.40":
|
"@vueuse/core@^4.0.0-beta.41":
|
||||||
version "4.0.0-beta.40"
|
version "4.0.0-beta.41"
|
||||||
resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.0.0-beta.40.tgz#7efdc15c1b994647dff7ae65c0ca573d96ce9b28"
|
resolved "https://registry.npmjs.org/@vueuse/core/-/core-4.0.0-beta.41.tgz#0058aed5ade75ae2866283498009ad5172cbae84"
|
||||||
integrity sha512-FOTOUrXAAp0NOmy8hMlP1HpUhnB8LeRJZDOEUl/A9gKMDwWvPTEvxKsDAIzSa4s7I0MapVzfeP3soNCNfl9+vQ==
|
integrity sha512-CgUih65PzYScorm1S4F93e6XXm+qxA8GrRLOSB1kXaqtP6vXedwkBxKkNEYNACx4reL4VEHqM/BrM6FajXkQUg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@vueuse/shared" "4.0.0-beta.40"
|
"@vueuse/shared" "4.0.0-beta.41"
|
||||||
vue-demi latest
|
vue-demi latest
|
||||||
|
|
||||||
"@vueuse/shared@4.0.0-beta.40":
|
"@vueuse/shared@4.0.0-beta.41":
|
||||||
version "4.0.0-beta.40"
|
version "4.0.0-beta.41"
|
||||||
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.0.0-beta.40.tgz#76e9b52228159e7ec88df2c8f4eea8fce1a42ec3"
|
resolved "https://registry.npmjs.org/@vueuse/shared/-/shared-4.0.0-beta.41.tgz#395782ea2e580f1fc9488d25c89bd09f70170b25"
|
||||||
integrity sha512-Ay71viUTXs0XX2hQ04kEExhpsCrw3KankBMP7euorsPjuQmIZjUA4NNOb45UAudg+uF5HXLpgWLvwb4cMOLHnQ==
|
integrity sha512-dqnuEPPC3OUJ6L6rhMiOCuPWIR698DtdwOydwCZBISsG2V6gZ2QFND6xtRwLib6/lhUMYVYPwIz3hPjlx7BIzw==
|
||||||
dependencies:
|
dependencies:
|
||||||
vue-demi latest
|
vue-demi latest
|
||||||
|
|
||||||
@ -1850,10 +1850,10 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
color-convert "^2.0.1"
|
color-convert "^2.0.1"
|
||||||
|
|
||||||
ant-design-vue@^2.0.0-beta.15:
|
ant-design-vue@^2.0.0-rc.1:
|
||||||
version "2.0.0-beta.15"
|
version "2.0.0-rc.1"
|
||||||
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.0-beta.15.tgz#3c787dabb70a33885d0e751e58f9a5610ed06134"
|
resolved "https://registry.npmjs.org/ant-design-vue/-/ant-design-vue-2.0.0-rc.1.tgz#2ef02475f3aa4c1474f2fe3cf44a52c34787be02"
|
||||||
integrity sha512-OxZy+ZYU3LauIL4Rhqwy441K/iD++Cit6upnQy5+LVUrX0PSObPqPqMWVpncbAmJJYTEz88gkvgGeYqBdzouWA==
|
integrity sha512-iKXkFtTHarvLHV7LWmYh6g/Cmkv+xK+vS621A1Qvg37Z6lCGg3K9BGAizmklAYzOTiPz0Ltt63eSiNqYMGh52g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@ant-design-vue/use" "^0.0.1-0"
|
"@ant-design-vue/use" "^0.0.1-0"
|
||||||
"@ant-design/icons-vue" "^5.1.5"
|
"@ant-design/icons-vue" "^5.1.5"
|
||||||
@ -8109,10 +8109,10 @@ vary@^1.1.2:
|
|||||||
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
|
||||||
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
|
||||||
|
|
||||||
vditor@^3.6.0:
|
vditor@^3.6.2:
|
||||||
version "3.6.1"
|
version "3.6.2"
|
||||||
resolved "https://registry.npmjs.org/vditor/-/vditor-3.6.1.tgz#b0b510f23d0cf0e5d8b3d36924e40400de96f692"
|
resolved "https://registry.npmjs.org/vditor/-/vditor-3.6.2.tgz#ee6011efa3ec563c6356ed82efbf2e00ba2e35c6"
|
||||||
integrity sha512-83GdGLIWrV1x04aK8DO9aZidqQfmuGXXUbxSCuQxRla+T9KfnFRmJwfqIxXQm8h+4jUBCFL38e8PqLa3fBOf9w==
|
integrity sha512-HPHHun5+IXmYGMKDWcUD83VfP1Qfncz7DmaIKoWpluJgE8ve7s+4RbFBcaEpYPXYzIuL2UTHoMnIjmTPbenOCA==
|
||||||
dependencies:
|
dependencies:
|
||||||
diff-match-patch "^1.0.5"
|
diff-match-patch "^1.0.5"
|
||||||
|
|
||||||
@ -8272,10 +8272,10 @@ vue-i18n@^9.0.0-beta.6:
|
|||||||
dependencies:
|
dependencies:
|
||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
|
|
||||||
vue-router@^4.0.0-rc.2:
|
vue-router@^4.0.0-rc.3:
|
||||||
version "4.0.0-rc.2"
|
version "4.0.0-rc.3"
|
||||||
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.2.tgz#8545cab76a05ca4f6dffbe6c6a671a4dbf585ab2"
|
resolved "https://registry.npmjs.org/vue-router/-/vue-router-4.0.0-rc.3.tgz#70d18e90030bc6a25e81a30401d673223998ec6b"
|
||||||
integrity sha512-51mBp39rzBFpk1nyU9SkhPcwR67gBzWIH8p3pyeDmtNYgWzGF3q8MneD/xbMwsfTQkw2H1qBk6uwRaVy3M8Nxw==
|
integrity sha512-NnPqWIfanEhJC4wu8BEFBmnEDIrx9ST0/HtmBiE+oV2MQlhyRk1TmdttWwVqx6Sh7kONsrI10GQV9l3YEkcWXg==
|
||||||
|
|
||||||
vue-types@^3.0.0:
|
vue-types@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user