更新 upload 插件

This commit is contained in:
神仙都没用 2024-02-05 18:18:56 +08:00
parent 52e345712e
commit d9b2405184
7 changed files with 226 additions and 215 deletions

View File

@ -111,7 +111,7 @@ import { ZoomIn, Delete, VideoPause, VideoPlay } from "@element-plus/icons-vue";
import { ContextMenu } from "@cool-vue/crud";
import { useCool } from "/@/cool";
import { extname } from "/@/cool/utils";
import { download, fileName, getRule } from "../../utils";
import { fileName, getRule } from "../../utils";
import { ElMessage } from "element-plus";
import { useClipboard } from "@vueuse/core";
import Viewer from "./viewer.vue";
@ -172,16 +172,6 @@ function onContextMenu(e: any) {
done();
}
},
{
label: "下载",
callback(done) {
if (props.item.url) {
download(props.item.url);
}
done();
}
},
{
label: "复制链接",
callback(done) {

View File

@ -11,34 +11,18 @@
</div>
<!-- 文档 -->
<cl-dialog
v-model="doc.visible"
title="文档预览"
height="70vh"
width="80%"
:scrollbar="false"
:controls="['slot-download', 'fullscreen', 'close']"
>
<template #slot-download>
<button type="button" class="cl-dialog__controls-icon" @click="download(doc.url)">
<el-icon>
<icon-download />
</el-icon>
</button>
</template>
<cl-dialog v-model="doc.visible" title="文档预览" height="70vh" width="80%" :scrollbar="false">
<div class="viewer-doc" v-loading="doc.loading">
<iframe :src="doc.previewUrl" :ref="setRefs('docIframe')" />
<iframe :src="doc.url" :ref="setRefs('docIframe')" />
</div>
</cl-dialog>
</template>
<script lang="ts" setup name="file-viewer">
import { reactive, nextTick } from "vue";
import { getType, download } from "../../utils";
import { getType } from "../../utils";
import type { Upload } from "../../types";
import { useCool } from "/@/cool";
import { Download as IconDownload } from "@element-plus/icons-vue";
const { refs, setRefs } = useCool();
@ -52,8 +36,7 @@ const img = reactive({
const doc = reactive({
visible: false,
loading: false,
url: "",
previewUrl: ""
url: ""
});
//
@ -77,8 +60,7 @@ function open(item: Upload.Item) {
if (["word", "excel", "ppt", "pdf"].includes(type)) {
doc.visible = true;
doc.loading = true;
doc.previewUrl = `https://view.officeapps.live.com/op/view.aspx?src=${decodeURIComponent(url)}`;
doc.url = url;
doc.url = `https://view.officeapps.live.com/op/view.aspx?src=${decodeURIComponent(url)}`;
nextTick(() => {
refs.docIframe.onload = () => {

View File

@ -22,7 +22,7 @@
:http-request="httpRequest"
:headers="headers"
:multiple="multiple"
:disabled="uploadDisabled"
:disabled="disabled"
>
<slot>
<el-button type="success">{{ text }}</el-button>
@ -61,7 +61,7 @@
:http-request="httpRequest"
:headers="headers"
:multiple="multiple"
:disabled="uploadDisabled"
:disabled="disabled"
>
<slot>
<div class="cl-upload__demo is-dragger" v-if="drag">
@ -103,7 +103,7 @@
}
"
:headers="headers"
:disabled="uploadDisabled"
:disabled="disabled"
v-if="showFileList"
>
<slot name="item" :item="item" :index="index">
@ -127,15 +127,15 @@
<script lang="ts" setup name="cl-upload">
import { computed, ref, watch, type PropType, nextTick } from "vue";
import { isArray, isNumber } from "lodash-es";
import { type AxiosProgressEvent } from "axios";
import Draggable from "vuedraggable";
import { ElMessage } from "element-plus";
import { PictureFilled, UploadFilled } from "@element-plus/icons-vue";
import { useForm } from "@cool-vue/crud";
import { useCool, module } from "/@/cool";
import { useCool } from "/@/cool";
import { useBase } from "/$/base";
import { uuid, isPromise } from "/@/cool/utils";
import { getUrls, getType, pathJoin } from "../utils";
import { getUrls, getType } from "../utils";
import { useUpload } from "../hooks";
import UploadItem from "./upload-item/index.vue";
import type { Upload } from "../types";
@ -187,15 +187,7 @@ const props = defineProps({
//
beforeUpload: Function,
//
prefixPath: {
type: String,
default: "app"
},
//
menu: {
type: String,
default: "base"
},
prefixPath: String,
// CRUD穿
isEdit: Boolean,
@ -206,12 +198,10 @@ const props = defineProps({
const emit = defineEmits(["update:modelValue", "upload", "success", "error", "progress"]);
const { service, refs, setRefs } = useCool();
const { refs, setRefs } = useCool();
const { user } = useBase();
const Form = useForm();
//
const { options } = module.get("upload");
const { options, toUpload } = useUpload();
//
const size = computed(() => {
@ -224,11 +214,6 @@ const disabled = computed(() => {
return props.isDisabled || props.disabled;
});
//
const uploadDisabled = computed(() => {
return disabled.value;
});
//
const limit = props.limit || options.limit.upload;
@ -357,7 +342,7 @@ function clear() {
}
//
async function httpRequest(req: any, item?: any) {
async function httpRequest(req: any, item?: Upload.Item) {
if (!item) {
item = list.value.find((e) => e.uid == req.file.uid);
}
@ -366,149 +351,23 @@ async function httpRequest(req: any, item?: any) {
return false;
}
// id
const fileId = uuid("");
try {
//
const { mode, type } = await service.base.comm.uploadMode();
//
const isLocal = mode == "local";
//
const fileName = fileId + "_" + req.file.name;
// Key
const key = isLocal ? fileName : pathJoin(props.prefixPath, props.menu, fileName);
//
return new Promise((resolve, reject) => {
//
async function next({
host,
preview,
data
}: {
host: string;
preview?: string;
data?: any;
}) {
const fd = new FormData();
// key
fd.append("key", key);
//
for (const i in data) {
if (!fd.has(i)) {
fd.append(i, data[i]);
}
}
//
fd.append("file", req.file);
//
await service
.request({
url: host,
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
Authorization: isLocal ? user.token : null
},
timeout: 600000,
data: fd,
onUploadProgress(e: AxiosProgressEvent) {
item.progress = e.total ? Math.floor((e.loaded / e.total) * 100) : 0;
emit("progress", item);
},
proxy: isLocal,
NProgress: false
})
.then((res) => {
item.key = encodeURIComponent(key);
if (isLocal) {
item.url = res;
} else {
item.url = pathJoin(preview || host, item.key);
}
item.fileId = fileId;
emit("success", item);
resolve(item.url);
update();
})
.catch((err) => {
ElMessage.error(err.message);
item.error = err.message;
emit("error", item);
reject(err);
});
}
if (isLocal) {
next({
host: "/admin/base/comm/upload"
});
} else {
service.base.comm
.upload(
type == "aws"
? {
key
}
: {}
)
.then((res) => {
switch (type) {
//
case "cos":
next({
host: res.url,
data: res.credentials
});
break;
//
case "oss":
next({
host: res.host,
preview: res.publicDomain,
data: {
OSSAccessKeyId: res.OSSAccessKeyId,
policy: res.policy,
signature: res.signature
}
});
break;
//
case "qiniu":
next({
host: res.uploadUrl,
preview: res.publicDomain,
data: {
token: res.token
}
});
break;
// aws
case "aws":
next({
host: res.url,
data: res.fields
});
break;
}
})
.catch(reject);
}
//
toUpload(req.file, {
prefixPath: props.prefixPath,
onProgress(progress) {
item.progress = progress;
emit("progress", item);
}
})
.then((res) => {
Object.assign(item, res);
emit("success", item);
update();
})
.catch((err) => {
item.error = err.message;
emit("error", item);
});
} catch (err) {
ElMessage.error("上传配置错误");
}
}
//

View File

@ -3,8 +3,8 @@ export default () => {
label: "文件上传",
description: "基于 el-upload 封装的文件上传组件",
author: "COOL",
version: "1.0.0",
updateTime: "2024-02-01",
version: "1.1.0",
updateTime: "2024-02-05",
demo: [
{
name: "基础用法",
@ -47,6 +47,11 @@ export default () => {
// 上传大小限制
size: 100
},
// 云端上传路径前缀
prefixPath: {
type: String,
default: "app/base"
},
// 规则
rules: [
{

View File

@ -0,0 +1,180 @@
import { ElMessage } from "element-plus";
import { module, service } from "/@/cool";
import { uuid } from "/@/cool/utils";
import { pathJoin } from "../utils";
import { useBase } from "/$/base";
import { type AxiosProgressEvent } from "axios";
import type { Upload } from "../types";
import { merge } from "lodash-es";
export function useUpload() {
const { options } = module.get("upload");
const { user } = useBase();
// 上传
async function toUpload(
file: File,
opts: Upload.Options = {}
): Promise<{
key: string;
url: string;
fileId: string;
}> {
return new Promise(async (resolve, reject) => {
// 合并配置
const { prefixPath, onProgress } = merge(opts, options);
// 文件id
const fileId = uuid("");
try {
// 上传模式、类型
const { mode, type } = await service.base.comm.uploadMode();
// 本地上传
const isLocal = mode == "local";
// 文件名
const fileName = fileId + "_" + file.name;
// Key
let key = isLocal ? fileName : pathJoin(prefixPath!, fileName);
// 多种上传请求
// 上传到云端
async function next({
host,
preview,
data
}: {
host: string;
preview?: string;
data?: any;
}) {
const fd = new FormData();
// key
fd.append("key", key);
// 签名数据
for (const i in data) {
if (!fd.has(i)) {
fd.append(i, data[i]);
}
}
// 文件
fd.append("file", file);
// 上传
await service
.request({
url: host,
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
Authorization: isLocal ? user.token : null
},
timeout: 600000,
data: fd,
onUploadProgress(e: AxiosProgressEvent) {
const progress = e.total
? Math.floor((e.loaded / e.total) * 100)
: 0;
onProgress?.(progress);
},
proxy: isLocal,
NProgress: false
})
.then((res) => {
key = encodeURIComponent(key);
let url = "";
if (isLocal) {
url = res;
} else {
url = pathJoin(preview || host, key);
}
resolve({
key,
url,
fileId
});
})
.catch((err) => {
ElMessage.error(err.message);
reject(err);
});
}
if (isLocal) {
next({
host: "/admin/base/comm/upload"
});
} else {
service.base.comm
.upload(
type == "aws"
? {
key
}
: {}
)
.then((res) => {
switch (type) {
// 腾讯
case "cos":
next({
host: res.url,
data: res.credentials
});
break;
// 阿里
case "oss":
next({
host: res.host,
preview: res.publicDomain,
data: {
OSSAccessKeyId: res.OSSAccessKeyId,
policy: res.policy,
signature: res.signature
}
});
break;
// 七牛
case "qiniu":
next({
host: res.uploadUrl,
preview: res.publicDomain,
data: {
token: res.token
}
});
break;
// aws
case "aws":
next({
host: res.url,
data: res.fields
});
break;
}
})
.catch(reject);
}
} catch (err) {
ElMessage.error("文件上传失败");
console.error("[upload]", err);
reject(err);
}
});
}
return {
options,
toUpload
};
}

View File

@ -15,4 +15,10 @@ export declare namespace Upload {
isPlay?: boolean;
[key: string]: any;
}
interface Options {
prefixPath?: string;
onProgress?(progress: number): void;
[key: string]: any;
}
}

View File

@ -1,7 +1,7 @@
import { last } from "lodash-es";
import { filename, extname } from "/@/cool/utils";
import { module } from "/@/cool";
import type { Upload } from "../types";
import { Upload } from "../types";
// 模块参数
const { options } = module.get("upload");
@ -74,14 +74,3 @@ export function pathJoin(...parts: string[]): string {
return normalizedParts.join("/");
}
}
// 下载
export function download(url: string) {
const a = document.createElement("a");
a.href = url;
a.download = url;
a.target = "_blank";
a.style.display = "none";
document.body.appendChild(a);
a.click();
}