赞
踩
2024年3月20日 更新特性:支持任务管理设置同时上传的最大任务数,满足个性化同时上传数量需求。
特性:
- 可以全屏
- 可以还原尺寸、拖拽调整托盘尺寸
- 可以最小化
- 可以回到右下角默认位置
- 支持删除队列数据(支持一键清除所有上传记录)
- 支持清空已经上传成功的记录
- 上传过程在百分号右侧会有旋转加载动画
- 支持提示上传超大文件的title
- 实时加载上传进度条(逼真的已加载数据大小)
- 支持清除队列中失败的记录
- 支持显示实时上传速度、已耗时间、剩余上传时间
- 支持项卡切换上传中、成功、失败的队列
- 支持列表翻页
- 支持动态设置【同时上传的最大任务数】
- <template>
- <!--
- 新特性:
- 1、支持用户自定义同时上传任务数量2024.03.19
- -->
- <div :class="$options.name" :show="show" :size="size" :style="style">
- <div class="upload-list-tray">
- <!-- 托盘头部 -->
- <div class="header" ref="header" @dblclick.stop.prevent="dblclickHeader">
- <div class="left">
- <div class="title">
- <span class="upload-count" slot="reference">上传队列</span>
- <div class="upload-info" v-if="liveSpeed && liveSpeed > 0">
- <el-divider :direction="`vertical`" />
- <div class="info-item live-speed">
- <label>速度</label>
- <span>{{ $g.getSize(liveSpeed) }}/s</span>
- </div>
- <div class="info-item taken-time" v-if="takenTime && takenTime > 0">
- <label>已耗时</label>
- <span>{{
- $g.date.toHourMinuteSecondByMillisecond(takenTime * 1000, {
- zh: true, //中文单位
- hideMilliSecond: true, //隐藏毫秒
- hideZero: true, //隐藏为0的时间单位
- })
- }}</span>
- </div>
- <div class="info-item remain-time" v-if="remainTime && remainTime > 0">
- <label>剩余</label
- ><span>{{
- $g.date.toHourMinuteSecondByMillisecond(remainTime * 1000, {
- zh: true, //中文单位
- hideMilliSecond: true, //隐藏毫秒
- hideZero: true, //隐藏为0的时间单位
- })
- }}</span>
- </div>
- </div>
- </div>
- </div>
- <div class="right" @mousedown.stop>
- <!-- 控制文件的图标按钮 -->
- <div class="file-btns" v-if="showDelSuccessIconBtn || showErrorIconBtn">
- <div
- class="icon-btn"
- v-if="showDelSuccessIconBtn"
- @dblclick.stop
- @click.stop="clearAllSuccessFile"
- title="清除所有已经成功的上传记录"
- >
- <i class="el-icon-delete" style="color: #67c23a"></i>
- </div>
- <div
- class="icon-btn"
- v-if="showErrorIconBtn"
- @dblclick.stop
- @click.stop="clearAllErrorFile"
- title="清除所有失败的上传记录"
- >
- <i class="el-icon-delete-solid" style="color: #f56c6c"></i>
- </div>
- <div
- class="icon-btn"
- v-if="showErrorIconBtn"
- @dblclick.stop
- @click.stop="uploadAllErrorFile"
- title="重新上传所有失败的文件"
- >
- <i class="el-icon-upload2" style="color: #409eff"></i>
- </div>
- </div>
- <!-- 控制托盘的图标按钮 -->
- <div class="tray-btns">
- <div
- class="icon-btn"
- v-if="size !== 'lg' && showRightBottomBtn"
- @dblclick.stop
- @click.stop="toRightBottomPosition"
- title="回到原来的位置"
- >
- <i class="el-icon-bottom-right"></i>
- </div>
- <div
- class="icon-btn"
- v-if="size !== 'mn'"
- @dblclick.stop
- @click.stop="size = 'mn'"
- title="最小化"
- >
- <i class="el-icon-minus"></i>
- </div>
- <div
- class="icon-btn"
- v-if="size !== 'md'"
- @dblclick.stop
- @click.stop="size = 'md'"
- title="还原"
- >
- <i :class="size === 'lg' ? 'el-icon-copy-document' : 'el-icon-d-caret'"></i>
- </div>
- <div
- class="icon-btn"
- v-if="size !== 'lg'"
- @dblclick.stop
- @click.stop="size = 'lg'"
- title="全屏"
- >
- <i class="el-icon-full-screen"></i>
- </div>
- <div class="icon-btn" @dblclick.stop @click.stop="close">
- <i class="el-icon-close"></i>
- </div>
- </div>
- </div>
- </div>
- <div class="body">
- <div class="left" :collapse="collapseMenu">
- <el-menu
- :show-timeout="0"
- :default-active="defaultMenuActive"
- :background-color="'white'"
- :text-color="'#333'"
- :active-text-color="'#409EFF'"
- :collapse="collapseMenu"
- :unique-opened="false"
- @select="menuSelect"
- >
- <template v-for="(a, i) in menuList">
- <!-- 有子栏目--->
- <el-submenu
- :key="i"
- :index="a.path"
- v-if="a.children && a.children.length"
- :disabled="a.disabled"
- >
- <template slot="title">
- <i :class="a.icon" v-if="a.icon" />
- <span>{{ a.label }}</span>
- </template>
- <el-menu-item-group>
- <el-menu-item
- v-for="(a, i) in a.children"
- :key="i"
- :index="a.path"
- :disabled="a.disabled"
- >
- <i :class="a.icon" v-if="a.icon" />
- <span>{{ a.label }}</span>
- </el-menu-item>
- </el-menu-item-group>
- </el-submenu>
- <!-- 没有子栏目-->
- <el-tooltip
- :content="a.label"
- :placement="`left`"
- :disabled="!collapseMenu"
- v-else
- >
- <el-menu-item :key="i" :index="a.path" :disabled="a.disabled">
- <i :class="a.icon" v-if="a.icon" />
- <span>{{ a.label }}</span>
- </el-menu-item>
- </el-tooltip>
- </template>
- </el-menu>
- <!-- 折叠按钮 -->
- <div class="collapseBtn" @click="collapseMenu = !collapseMenu">
- <i class="el-icon-caret-right" v-if="collapseMenu" />
- <i class="el-icon-caret-left" v-else />
- </div>
- </div>
-
- <!-- 设置 ------------------------------------------>
- <div class="right" v-if="defaultMenuActive === `set`">
- <div class="set-list">
- <el-collapse v-model="collapseActiveName_set" accordion>
- <el-collapse-item
- :name="parseInt(index)"
- v-for="(item, index) in collapseItems_set"
- :key="index"
- >
- <template slot="title">
- <h1>{{ item.title }}</h1>
- </template>
- <div class="form-body">
- <el-form @submit.native.prevent label-position="right" size="mini">
- <el-form-item :label="`同时上传的最大任务数`" label-width="">
- <el-input-number
- style="width: 100px"
- v-model.trim="setData.uploadMaxCount"
- :precision="0"
- :step="1"
- :min="0"
- :max="10"
- :controls-position="`left`"
- />
- </el-form-item>
- </el-form>
- </div>
- </el-collapse-item>
- </el-collapse>
- </div>
- </div>
-
- <!-- 上传中的文件列表 ------------------------------------------>
- <div class="right" v-else>
- <div class="upload-file-list">
- <ul v-if="tableData.length">
- <li
- v-for="(a, i) in tableData"
- :key="i"
- :title="
- a.size > 1024 * 1024 * 500
- ? `超大文件上传中,请耐心等待,切勿关闭或刷新浏览器!`
- : ''
- "
- >
- <div class="left">
- <div class="icon-btns">
- <el-button
- title="移出上传队列"
- :show="a.status === 'error'"
- class="remove-icon-btn icon-btn"
- type="danger"
- icon="el-icon-delete-solid"
- size="mini"
- plain
- circle
- @click.stop="removeUploadFile(a)"
- ></el-button>
- </div>
- <!-- 动画加载旋转 -->
- <div
- class="fileLoading"
- v-loading="a.percent <= 100"
- v-if="a.status !== 'error' && a.status !== 'success'"
- ></div>
- <!-- 上传成功icon -->
- <div class="loadingSuccessIcon" v-if="a.status === `success`">
- <i class="el-icon-success" style="color: #67c23a"></i>
- </div>
- <!-- 上传失败icon -->
- <div class="loadingEorrorIcon" v-if="a.status === 'error'">
- <i class="el-icon-error" style="color: #f56c6c"></i>
- </div>
- <span class="name" :title="a.filePath || a.name">
- {{ a.filePath || a.name }}
- <!-- {{ a.filePath && a.filePath.includes(`/`) ? `[路径:${a.filePath}]` : "" }} -->
- </span>
- <el-tag class="size" size="mini"
- >{{ $g.getSize(a.size * (a.percent / 100)) }}/{{
- $g.getSize(a.size)
- }}</el-tag
- >
- <!-- <el-progress class="progress" :percentage="a.percent"></el-progress> -->
- <el-progress
- class="progress"
- style="width: 100%"
- type="line"
- :percentage="parseInt(a.percent)"
- :show-text="true"
- :stroke-width="10"
- :text-inside="false"
- :color="'#409EFF'"
- :define-back-color="'#eee'"
- />
- </div>
- <div class="right">
- <span class="tip" :color="a.color">{{ a.tip }}</span>
- <div class="icon-btns">
- <el-button
- v-if="a.status !== 'uploading'"
- title="重新上传"
- class="upload-icon-btn icon-btn"
- type="primary"
- icon="el-icon-upload2"
- size="mini"
- plain
- circle
- @click.stop="startUploadFile(a)"
- ></el-button>
- </div>
- </div>
- </li>
- </ul>
- <!-- 自定义空状态 -->
- <el-empty v-else>
- <div slot="image"><img :src="require('@/assets/404.png')" /></div>
- <div slot="description">{{ getEmptyText() }}</div>
- </el-empty>
- </div>
- <el-pagination
- style="width: 100%; text-align: center; margin-top: 10px"
- background
- :hidden="total <= 10"
- :layout="`total, sizes, prev, pager, next, jumper`"
- :page-sizes="[10, 20, 50, 100]"
- :pager-count="7"
- :current-page.sync="currentPage"
- :page-size.sync="pageSize"
- :total="total"
- @size-change="initList"
- @current-change="initList"
- />
- </div>
- </div>
- <div class="footer">
- <div class="text" v-html="popoverContent"></div>
- <div class="progress" v-if="uploadList.length > 1 && totalPercentage < 100">
- <label>。总进度</label>
- <el-progress
- style="width: 100%"
- type="line"
- :percentage="parseInt(totalPercentage)"
- :show-text="true"
- :stroke-width="10"
- :text-inside="false"
- :color="'#409EFF'"
- :define-back-color="'#eee'"
- />
- </div>
- </div>
- </div>
-
- <!-- 拖拽移动窗体 -->
- <sgDragMove
- :data="dragMoveDoms"
- :cursor="{
- grab: 'default',
- grabbing: 'default',
- }"
- nearPadding="10"
- :disabled="size === 'lg' && disabledDragMove"
- @dragStart="$emit(`dragStart`, dragMoveDoms)"
- @dragging="
- showRightBottomBtn = true;
- $emit(`dragging`, dragMoveDoms);
- "
- @dragEnd="$emit(`dragEnd`, dragMoveDoms)"
- mousemoveNearSide
- />
-
- <!-- 拖拽改变窗体尺寸 -->
- <sgDragSize
- v-if="resizeable_"
- :disabled="size === 'lg'"
- @dragStart="disabledDragMove = true"
- @dragging="draggingSize"
- @dragEnd="disabledDragMove = false"
- :minWidth="minWidth"
- :minHeight="minHeight"
- />
- </div>
- </template>
- <script>
- import sgDragMove from "@/vue/components/admin/sgDragMove";
- import sgDragSize from "@/vue/components/admin/sgDragSize";
- export default {
- name: "sgUploadTray_v2",
- components: {
- sgDragMove,
- sgDragSize,
- },
- data() {
- return {
- currentPage: 1,
- pageSize: 10,
- total: 0,
- tableData: [], //当前显示队列(不代表所有的上传队列,只为不要太卡)
-
- // maxShowUploadFileCount: 10, //默认展示上传数量
- // expandAllUploadList: false, //默认折叠
-
- minWidth: 950,
- minHeight: 40,
- style_bk: null,
- style: {},
- resizeable_: true,
- disabledDragMove: false, //屏蔽移动
- show: false,
- showRightBottomBtn: false,
- size: "md", //lg全屏、md普通、mn最小
- uploadList: [],
- uploadingFiles: [], //真正上传中的文件对象数组
- dragMoveDoms: [
- /* {
- canDragDom: elementDOM,//可以拖拽的位置元素
- moveDom: elementDOM,//拖拽同步移动的元素
- } */
- ], //可以拖拽移动的物体
-
- lastUploadedTotalSize: 0, //记录上次已经下载完成的总大小
- liveSpeed: 0, //瞬时下载速度(单位B)
- takenTime: 0, //已耗时
- remainTime: 0, //剩余下载时长
- interval: null,
- second: 1, //轮训间隔秒钟
-
- successFileList: [], //成功文件列表
- errorFileList: [], //失败文件列表
- remainFileList: [], //剩余文件列表
-
- collapseActiveName_set: 0,
- collapseItems_set: [
- // { value: 1, title: "基本设置", content: "开发中" },
- { value: 2, title: "任务管理", content: "开发中" },
- // { value: 3, title: "上传设置", content: "开发中" },
- // { value: 4, title: "提醒", content: "开发中" },
- // { value: 5, title: "高级设置", content: "开发中" },
- ],
-
- // defaultMenuActive: `uploading`, //当前激活菜单的 index
- defaultMenuActive: `set`, //测试
- collapseMenu: false, //是否水平折叠收起菜单(仅在 mode 为 vertical 时可用)
- menuList: [
- {
- label: "上传中",
- path: "uploading",
- icon: "el-icon-upload2",
- },
- {
- label: "已完成",
- path: "success",
- icon: "el-icon-success",
- },
- {
- label: "失败",
- path: "error",
- icon: "el-icon-error",
- },
- {
- label: "设置",
- path: "set",
- icon: "el-icon-s-tools",
- },
- ],
-
- setData: {
- uploadMaxCount: 5, //同时上传的最大任务数
- }, //上传设置配置参数
- };
- },
- props: ["data", "value", "resizeable", "position"],
- watch: {
- setData: {
- handler(d) {
- this.$store.getters._global.uploadSet = d;
- },
- deep: true,
- immediate: true,
- },
- value: {
- handler(d) {
- this.show = d;
- },
- deep: true,
- immediate: true,
- },
- show: {
- handler(d) {
- d && (this.defaultMenuActive = `uploading`);
- this.$emit(`input`, d);
- },
- deep: true,
- immediate: true,
- },
- data: {
- handler(d) {
- this.uploadList = d || [];
- },
- deep: true,
- immediate: true,
- },
- uploadList: {
- handler(newValue, oldValue) {
- if (newValue && Object.keys(newValue).length) {
- this.interval || this.startUploadCalcLiveSpeed();
- this.successFileList = newValue.filter((v) => v.status === `success`); //成功队列
- this.errorFileList = newValue.filter((v) => v.status === "error"); //失败队列
- this.remainFileList = newValue.filter(
- (v) => v.status !== "error" && v.status !== "success"
- ); //还需要上传的队列
- } else {
- this.successFileList = [];
- this.errorFileList = [];
- this.remainFileList = [];
- }
- // 计算正上传中的文件对象数组----------------------------------------
- this.uploadingFiles = (newValue || []).filter((v) => v.status === "uploading");
- this.$emit(`changeUploadingListClose`, {
- path: this.position,
- close: this.close,
- });
- // ----------------------------------------
- this.initList();
- },
- deep: true, //深度监听
- immediate: true, //立即执行
- },
- resizeable: {
- handler(newValue, oldValue) {
- this.resizeable_ = newValue === "" || newValue;
- },
- deep: true, //深度监听
- immediate: true, //立即执行
- },
- size: {
- handler(newValue, oldValue) {
- switch (newValue) {
- case "lg":
- case "mn":
- this.style_bk = JSON.parse(JSON.stringify(this.style));
- delete this.style.width, delete this.style.height;
- break;
- case "md":
- this.style_bk && (this.style = JSON.parse(JSON.stringify(this.style_bk)));
- break;
- }
- },
- deep: true, //深度监听
- immediate: true, //立即执行
- },
- },
- computed: {
- showDelSuccessIconBtn(d) {
- return this.uploadList.some((v) => v.status === `success`);
- },
- showErrorIconBtn(d) {
- return this.uploadList.some((v) => v.status === "error");
- },
- popoverContent(d) {
- let r = [];
- this.successFileList.length &&
- r.push(
- `已上传成功<span style="color: #67C23A;">${this.successFileList.length}</span>个`
- );
- this.errorFileList.length &&
- r.push(`失败<span style="color: #F56C6C;">${this.errorFileList.length}</span>个`);
- this.remainFileList.length &&
- r.push(
- `剩余<span style="color: #409EFF;">${this.remainFileList.length}</span>个`
- );
- if (this.uploadList.length) {
- return `共计${this.uploadList.length}个文件,${
- r.length ? `${r.join(",")}文件` : ``
- }`;
- } else {
- return `暂无待上传文件`;
- }
- },
- // 总体进度
- totalPercentage() {
- if (this.uploadList.length) {
- return parseFloat(
- ((this.successFileList.length / this.uploadList.length) * 100).toFixed(2)
- );
- } else {
- return 0;
- }
- },
- },
- mounted() {
- this.$el.style.setProperty("--minWidth", `${this.minWidth}px`); //js往css传递局部参数
- this.$el.style.setProperty("--minHeight", `${this.minHeight}px`); //js往css传递局部参数
- this.dragMoveDoms = [
- {
- canDragDom: this.$refs.header, //托盘的头部可以拖拽
- moveDom: this.$el, //拖拽的时候,整个上传列表一起跟随移动
- },
- ];
- },
- destroyed() {
- clearInterval(this.interval);
- },
- methods: {
- saveSet(d) {},
- getEmptyText() {
- let label = (this.menuList.find((v) => v.path === this.defaultMenuActive) || {})
- .label;
- return `暂无${label ? `${label}的` : ``}文件`;
- },
- //菜单激活回调
- menuSelect(index, path) {
- this.defaultMenuActive = index;
- //做其他操作
- this.initList();
- },
-
- //静态数据翻页(支持筛选搜索)
- initList({ keyword = this.keyword } = {}) {
- let results = this.uploadList.filter((v) =>
- keyword ? v.name.includes(keyword) : true
- );
- switch (this.defaultMenuActive) {
- case "uploading":
- results = results.filter(
- (v, i, ar) => v.status === `uploading` || v.status === ``
- );
- break;
- case "success":
- case "error":
- results = results.filter((v, i, ar) => v.status === this.defaultMenuActive);
- break;
- default:
- }
- this.total = results.length;
- this.tableData = results.slice(
- (this.currentPage - 1) * this.pageSize,
- this.currentPage * this.pageSize
- );
- },
-
- // 开始计算瞬时下载速度
- startUploadCalcLiveSpeed() {
- clearInterval(this.interval);
- this.interval = setInterval(() => {
- this.calcLiveSpeed();
- }, 1000 * this.second);
- },
- // 结束计算瞬时下载速度
- endUploadCalcLiveSpeed(d) {
- clearInterval(this.interval);
- this.interval = null;
- this.liveSpeed = 0;
- this.takenTime = 0;
- this.remainTime = 0;
- },
- // 没有上传进程文件才结束计算速度
- ifNoUploadingFile_EndCalcLiveSpeed(d) {
- this.uploadingFiles.length || this.endUploadCalcLiveSpeed();
- },
- // 计算瞬时下载速度
- calcLiveSpeed(d) {
- this.takenTime++;
- let uploadList = this.uploadList;
- if (uploadList.length) {
- let totalSize = uploadList.reduce(
- (prevResult, current) => prevResult + current.size,
- 0
- ); //求和需要上传的文件总大小
- let uploadedTotalSize = uploadList.reduce(
- (prevResult, current) => prevResult + current.size * (0.01 * current.percent),
- 0
- ); //求和已经上传的文件总大小
- let remainTotalSize = totalSize - uploadedTotalSize; //剩余需要上传的文件
- if (this.lastUploadedTotalSize) {
- this.liveSpeed = (uploadedTotalSize - this.lastUploadedTotalSize) / this.second; //瞬时速度
- this.remainTime = remainTotalSize / this.liveSpeed; //瞬时剩余时长
- } else {
- this.liveSpeed = 0;
- }
- this.lastUploadedTotalSize = uploadedTotalSize; //记录本次已经上传的总大小
- } else {
- this.endUploadCalcLiveSpeed();
- }
- },
- clearAllSuccessFile() {
- let successFileList = this.uploadList.filter((v) => v.status === `success`);
- if (successFileList.length === 0)
- return this.$message(`暂无可以移除的成功记录,请稍后再试!`);
- this.$emit(`clearAllSuccessFile`, successFileList);
- // this.$nextTick(() => {
- successFileList.forEach((file) => file.removeFile()); //移除原始队列&托盘队列
- this.uploadList = this.uploadList.filter((v) => v.percent <= 100);
- // });
- },
- clearAllErrorFile() {
- let errorFileList = this.uploadList.filter((v) => v.status === "error");
- if (errorFileList.length === 0)
- return this.$message(`暂无可以移除的失败记录,请稍后再试!`);
- this.$emit(`clearAllErrorFile`, errorFileList);
- this.$nextTick(() => {
- errorFileList.forEach((file) => file.removeFile()); //移除原始队列&托盘队列
- this.uploadList = this.uploadList.filter((v) => v.status !== "error");
- });
- },
- uploadAllErrorFile(d) {
- let errorFileList = this.uploadList.filter((v) => v.status === "error");
- errorFileList.forEach((fileData) => this.startUploadFile(fileData));
- if (errorFileList.length === 0) return this.$message(`暂无失败记录,请稍后再试!`);
- this.$emit(`uploadAllErrorFile`, errorFileList);
- },
- draggingSize({ style }) {
- this.disabledDragMove = true;
- this.style = style;
- },
- toRightBottomPosition(d) {
- this.showRightBottomBtn = false;
- let rect = this.$el.getBoundingClientRect();
- this.$el.style.left = `${innerWidth - rect.width}px`;
- this.$el.style.top = `${innerHeight - rect.height}px`;
- // 用下面的写法会清除掉setProperty属性
- /* this.$el.style = {
- left: innerWidth - rect.width + "px",
- top: innerHeight - rect.height + "px",
- }; */
- },
- dblclickHeader(d) {
- switch (this.size) {
- case "lg":
- this.size = "md";
- break;
- case "md":
- this.size = "mn";
- break;
- case "mn":
- this.size = "md";
- break;
- default:
- F;
- }
- },
- removeAllFilesFromList() {
- this.uploadList &&
- this.uploadList.length &&
- this.uploadList.slice(-1)[0].removeAllFile(); //移除原始队列&托盘队列
- },
- removeFileFromList(d) {
- d.removeFile(); //移除原始队列&托盘队列
- },
- // 重新上传失败的记录
- startUploadFile(fileData) {
- fileData.startUpload({ handleTrigger: true });
- },
- // 移出某一个队列文件
- removeUploadFile(d) {
- if (d.status === "uploading") {
- this.$confirm(`${d.name}正在上传中,确定要取消吗?`, `提示`, {
- dangerouslyUseHTMLString: true,
- confirmButtonText: `确定`,
- cancelButtonText: `取消`,
- type: "warning",
- })
- .then(() => {
- this.$emit(`stopUpload`, [d]);
- this.$nextTick(() => {
- this.removeFileFromList(d);
- this.ifNoUploadingFile_EndCalcLiveSpeed();
- });
- })
- .catch(() => {});
- } else {
- this.removeFileFromList(d);
- }
- },
- // 关闭托盘
- close({ cb } = {}) {
- let stopUploadList = this.uploadingFiles;
- if (stopUploadList.length) {
- this.$confirm(`您还有正在上传中的文件,确定要取消吗?`, `提示`, {
- dangerouslyUseHTMLString: true,
- confirmButtonText: `确定`,
- cancelButtonText: `取消`,
- type: "warning",
- })
- .then(() => {
- this.doRemove({ stopUploadList, cb });
- })
- .catch(() => {});
- } else {
- this.doRemove({ stopUploadList, cb });
- }
- },
- doRemove({ stopUploadList, cb } = {}) {
- this.show = false;
- this.$emit(`stopUpload`, stopUploadList);
- this.$nextTick(() => {
- this.endUploadCalcLiveSpeed();
- this.removeAllFilesFromList(); //清空上传列表
- cb && cb(stopUploadList); //完成后回调
- });
- },
- },
- };
- </script>
- <style lang="scss" scoped>
- .sgUploadTray_v2 {
- $bodyLeftWidth: 150px; //左侧分类菜单宽度
- $headerHeight: 40px; //头部高度
- $footerHeight: 40px; //底部统计上传进度高度
- $minWidth: var(--minWidth); //托盘最小宽度
- $minHeight: var(--minHeight); //托盘最小高度
- $leftIconBtnWidth: 50px; //左侧删除按钮宽度
- $rightIconBtnWidth: 50px; //右侧重新上传按钮宽度
- $loadingWidth: 30px; //加载动画宽度(旋转全全)
- $rightWidth: 150px; //右侧宽度
- $sizeWidth: 200px; //文件大小宽度宽度
- $progressWidth: 100px; //进度条宽度
- $tipWidth: 100px; //提示文本宽度
- // ----------------------------------------
- z-index: 2001; //根据情况自己拿捏(太大了会遮住element的其他弹窗组件),v-loading默认是2000的z-index
- user-select: none;
- position: fixed;
- right: 10px;
- bottom: 10px;
- width: $minWidth;
- background-color: white;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- border-radius: 8px;
- overflow: hidden;
- border: 1px solid #eee;
- font-size: 14px;
- display: none;
-
- &[show] {
- display: block;
- }
-
- &[size="lg"] {
- left: 0 !important;
- top: 0 !important;
- width: 100vw;
- height: 100vh;
- transition: none;
- .upload-file-list {
- max-height: calc(100vh - 60px) !important;
- }
- }
-
- &[size="md"] {
- width: $minWidth;
- height: revert;
- }
-
- &[size="mn"] {
- width: $minWidth;
- height: $minHeight;
- }
-
- .upload-list-tray {
- display: flex;
- flex-direction: column;
- box-sizing: border-box;
- padding-bottom: 20px;
- width: 100%;
- height: 100%;
- position: relative;
-
- .header {
- flex-shrink: 0;
- font-size: 16px;
- font-weight: bold;
- width: 100%;
- height: $headerHeight;
- box-sizing: border-box;
- padding: 10px 20px;
- /*从上往下线性渐变背景*/
- background: linear-gradient(#409eff11, white);
- color: #409eff;
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- .left {
- display: flex;
- align-items: center;
- flex-grow: 1;
-
- .title {
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- .upload-info {
- display: flex;
- align-items: center;
- color: black;
- flex-shrink: 0;
- align-items: center;
- font-weight: normal;
- .info-item {
- margin-right: 5px;
- &:last-of-type {
- margin-right: 0;
- }
- span {
- font-family: DIN-Light;
- color: #409eff;
- }
- &.live-speed {
- span {
- font-family: DIN-Black;
- }
- }
- }
- }
- }
- .icon-btns {
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- .icon-btn {
- cursor: pointer;
- margin-right: 5px;
- &:last-of-type {
- margin-right: 0;
- }
- i {
- pointer-events: none;
- }
-
- &:hover {
- opacity: 0.618;
- }
- }
- }
- }
-
- .right {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- flex-shrink: 0;
- pointer-events: auto;
-
- .icon-btn {
- margin-left: 10px;
- cursor: pointer;
-
- i {
- pointer-events: none;
- }
-
- &:hover {
- opacity: 0.618;
- }
- &:first-of-type {
- margin-left: 0;
- }
- }
-
- .file-btns {
- margin-left: 10px;
- display: flex;
- flex-wrap: nowrap;
- justify-content: flex-end;
- box-sizing: border-box;
- padding: 0 10px;
- border-right: 1px solid #eee;
- }
- .tray-btns {
- margin-left: 10px;
- display: flex;
- flex-wrap: nowrap;
- justify-content: flex-end;
- }
- }
- }
-
- .body {
- display: flex;
- flex-wrap: nowrap;
- width: 100%;
- height: calc(100% - #{$headerHeight} - #{$footerHeight} + 20px);
- max-height: calc(100vh - #{$headerHeight} - #{$footerHeight} - 40px);
-
- & > .left {
- // transition: 0.382s;
- position: relative;
- flex-shrink: 0;
- width: $bodyLeftWidth;
- box-sizing: border-box;
- padding: 0 10px 0 20px;
- border-right: solid 1px #eff0f1;
- >>> .el-menu {
- transition: none;
- .el-menu-item {
- transition: none;
-
- margin-bottom: 5px;
- border-radius: 8px;
- &:last-of-type {
- margin-bottom: 0;
- }
- &:focus,
- &:hover {
- background-color: #f5f6f7 !important;
- }
- &.is-active {
- background-color: #e9effb !important;
- }
- }
- }
- .collapseBtn {
- transform: translateY(50%); //防止托盘最小高度的时候还冒出一小截
- width: 10px;
- height: 20px;
- display: flex;
- justify-content: center;
- align-items: center;
- color: white;
- background-color: #409eff;
- font-size: 12px;
- position: absolute;
- margin: auto;
- top: 0;
- right: -10px;
- bottom: 0;
- z-index: 1;
- border-radius: 0 4px 4px 0;
- box-sizing: border-box;
- padding: 20px 0;
- cursor: pointer;
- &:hover {
- filter: brightness(1.1);
- }
- }
- &[collapse] {
- width: 70px;
- >>> .el-menu {
- .el-menu-item {
- width: 40px;
- height: 40px;
- display: flex;
- justify-content: center;
- align-items: center;
- span {
- display: none;
- }
- }
- }
- }
- }
- & > .right {
- width: calc(100% - #{$bodyLeftWidth});
- flex-grow: 1;
- box-sizing: border-box;
- padding: 0 20px 0 10px;
- .upload-file-list {
- width: 100%;
- flex-grow: 1;
- overflow-y: auto;
- position: relative;
- max-height: calc(100% - 42px);
- min-height: 200px;
- height: 100%;
-
- ul {
- width: 100%;
-
- & > li {
- line-height: 1.6;
- box-sizing: border-box;
- padding: 10px;
- border-radius: 8px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- height: 50px;
-
- & > .left {
- width: calc(100% - #{$rightWidth});
- display: flex;
- align-items: center;
- flex-grow: 1;
- flex-shrink: 0;
- // 上传队列记录左侧侧操作按钮
- .icon-btns {
- display: flex;
- flex-wrap: nowrap;
- .icon-btn {
- display: none;
- &[show] {
- margin-right: 15px;
- display: block;
- }
- }
- }
- .fileLoading {
- flex-shrink: 0;
- width: 30px;
- margin-right: 5px;
- height: 0;
- transform: scale(0.5);
- }
- .loadingSuccessIcon,
- .loadingEorrorIcon {
- margin-right: 5px;
- width: 30px;
- height: 30px;
- display: flex;
- justify-content: center;
- align-items: center;
- flex-shrink: 0;
- }
- .name {
- text-align: left;
- margin-right: 10px;
- width: calc(
- 100% - #{$loadingWidth} - #{$sizeWidth} - #{$progressWidth} - #{$rightWidth} -
- 20px
- );
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- flex-shrink: 0;
- flex-grow: 1;
- }
-
- .size {
- margin-right: 10px;
- max-width: $sizeWidth;
- /*单行省略号*/
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- flex-shrink: 0;
- }
-
- .progress {
- max-width: $progressWidth;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- flex-shrink: 0;
- }
- }
-
- & > .right {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- width: $rightWidth;
-
- .tip {
- width: $tipWidth;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- flex-shrink: 0;
- text-align: right;
-
- &[color="red"] {
- color: #f56c6c;
- }
-
- &[color="green"] {
- color: #67c23a;
- }
-
- &[color="blue"] {
- color: #409eff;
- }
- }
- // 上传队列记录右侧操作按钮
- .icon-btns {
- display: flex;
- flex-wrap: nowrap;
- .icon-btn {
- display: none;
- &[show] {
- margin-left: 15px;
- display: block;
- }
- }
- }
- }
-
- &:hover {
- background-color: #409eff11;
- color: #409eff;
- .left {
- // 移入上传队列记录左侧操作按钮
- .icon-btns {
- .icon-btn {
- display: block;
- &:last-of-type {
- margin-right: 10px;
- }
- }
- }
- /* .name {
- width: calc(
- 100% - #{$leftIconBtnWidth} - #{$loadingWidth} - #{$sizeWidth} - #{$progressWidth} -
- #{$rightWidth} - #{$rightIconBtnWidth} - 20px
- );
- } */
- }
- .right {
- .tip {
- margin-right: 15px;
- }
- // 移入上传队列记录右侧操作按钮
- .icon-btns {
- .icon-btn {
- display: block;
- &:first-of-type {
- margin-left: 0;
- }
- }
- }
- }
- }
- }
- }
- .el-empty {
- width: max-content;
- height: max-content;
- position: absolute;
- margin: auto;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- }
- }
- }
- }
- .footer {
- z-index: 1;
- font-weight: normal;
- flex-shrink: 0;
- font-size: 14px;
- font-weight: bold;
- width: 100%;
- height: $footerHeight;
- box-sizing: border-box;
- padding: 10px 20px;
- margin-bottom: -20px;
- background: linear-gradient(white, #eff2f7);
- color: #909399;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- white-space: nowrap;
- * {
- font-weight: normal;
- }
- .text {
- white-space: nowrap;
- }
- .progress {
- max-width: 200px;
- flex-grow: 1;
- white-space: nowrap;
- display: flex;
- align-items: center;
- flex-wrap: nowrap;
- label {
- white-space: nowrap;
- flex-shrink: 0;
- margin-right: 5px;
- }
- >>> .el-progress {
- white-space: nowrap;
- .el-progress__text {
- font-weight: normal;
- font-size: 14px !important;
- }
- }
- }
- }
- }
- }
- </style>
- <template>
- <div :class="$options.name">
- <el-button type="primary" @click="$refs.sgUpload_v2.triggerUploadFolder()"
- >点击上传文件夹</el-button
- >
-
- <!-- 上传组件 -->
- <sgUpload_v2
- :noCheckFile="true"
- ref="sgUpload_v2"
- :data="uploadData"
- :sgUploadTray="sgUploadTray"
- hideMessageSuccessTip
- />
-
- <!-- 上传托盘(右下角) -->
- <sgUploadTray ref="sgUploadTray" resizeable />
- </div>
- </template>
-
- <script>
- import sgUpload_v2 from "@/vue/components/admin/sgUpload_v2";
- import sgUploadTray from "@/vue/components/admin/sgUploadTray_v2";
-
- export default {
- name: `demoUploadTray`,
- components: {
- sgUpload_v2,
- sgUploadTray,
- },
- data() {
- return {
- //上传相关变量----------------------------------------
- sgUploadTray: null,
- uploadData: {
- limit: 10000, //限制上传文件个数
- name: `FILE`,
- accept: `*`,
- actionURL: `${this.$d.API_ROOT_URL}/xxx/xxx`,
- actionData: {
- ZYGS: this.$g.getZYGS({
- BMID: this.$global.getBMID(),
- type: this.type,
- }),
- sgLog: `前端请求来源:${this.$options.name}资源上传`,
- },
- },
- // ----------------------------------------
- };
- },
- mounted(d) {
- this.sgUploadTray = this.$refs.sgUploadTray;
- },
- };
- </script>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。