mirror of
https://github.com/cool-team-official/cool-admin-vue.git
synced 2025-12-12 05:32:48 +00:00
优化 upload 模块,添加响应式处理
This commit is contained in:
parent
a1790e65f5
commit
1c9f7caeaf
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cool-admin-vue",
|
"name": "cool-admin-vue",
|
||||||
"version": "3.1.7",
|
"version": "3.2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export default {
|
|||||||
list: [fMenu]
|
list: [fMenu]
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
// 窗口列表
|
// 页面进程列表
|
||||||
processList: state => state.list
|
processList: state => state.list
|
||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
|
|||||||
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<cl-crud ref="crud" @load="onLoad" :on-refresh="onRefresh">
|
<cl-crud ref="crud" :on-refresh="onRefresh" @load="onLoad">
|
||||||
<el-row type="flex">
|
<el-row type="flex">
|
||||||
<cl-refresh-btn></cl-refresh-btn>
|
<cl-refresh-btn></cl-refresh-btn>
|
||||||
<cl-add-btn></cl-add-btn>
|
<cl-add-btn></cl-add-btn>
|
||||||
@ -123,36 +123,30 @@ export default {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
type: "selection",
|
type: "selection",
|
||||||
align: "center",
|
width: 60
|
||||||
width: "60"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "headImg",
|
prop: "headImg",
|
||||||
label: "头像",
|
label: "头像"
|
||||||
align: "center"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "name",
|
prop: "name",
|
||||||
label: "姓名",
|
label: "姓名",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "username",
|
prop: "username",
|
||||||
label: "用户名",
|
label: "用户名",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "nickName",
|
prop: "nickName",
|
||||||
label: "昵称",
|
label: "昵称",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "departmentName",
|
prop: "departmentName",
|
||||||
label: "部门名称",
|
label: "部门名称",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -164,19 +158,16 @@ export default {
|
|||||||
{
|
{
|
||||||
prop: "phone",
|
prop: "phone",
|
||||||
label: "手机号码",
|
label: "手机号码",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "remark",
|
prop: "remark",
|
||||||
label: "备注",
|
label: "备注",
|
||||||
align: "center",
|
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "status",
|
prop: "status",
|
||||||
label: "状态",
|
label: "状态",
|
||||||
align: "center",
|
|
||||||
"min-width": 120,
|
"min-width": 120,
|
||||||
dict: [
|
dict: [
|
||||||
{
|
{
|
||||||
@ -194,15 +185,13 @@ export default {
|
|||||||
{
|
{
|
||||||
prop: "createTime",
|
prop: "createTime",
|
||||||
label: "创建时间",
|
label: "创建时间",
|
||||||
align: "center",
|
|
||||||
sortable: "custom",
|
sortable: "custom",
|
||||||
"min-width": 150
|
"min-width": 150
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
align: "center",
|
|
||||||
type: "op",
|
type: "op",
|
||||||
buttons: ["slot-move-btn", "edit", "delete"],
|
buttons: ["slot-move-btn", "edit", "delete"],
|
||||||
width: "160px"
|
width: 160
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -271,7 +260,7 @@ export default {
|
|||||||
prop: "password",
|
prop: "password",
|
||||||
label: "密码",
|
label: "密码",
|
||||||
span: 12,
|
span: 12,
|
||||||
hidden: ":isEdit",
|
hidden: ":isAdd",
|
||||||
component: {
|
component: {
|
||||||
name: "el-input",
|
name: "el-input",
|
||||||
attrs: {
|
attrs: {
|
||||||
@ -362,7 +351,7 @@ export default {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: "tips",
|
prop: "tips",
|
||||||
hidden: ":isAdd",
|
hidden: ":isEdit",
|
||||||
component: (
|
component: (
|
||||||
<div>
|
<div>
|
||||||
<i class="el-icon-warning"></i>
|
<i class="el-icon-warning"></i>
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
'append-to-body': true,
|
'append-to-body': true,
|
||||||
'close-on-click-modal': false
|
'close-on-click-modal': false
|
||||||
}"
|
}"
|
||||||
:controls="['slot-session', 'cl-flex1', 'fullscreen', 'close']"
|
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
|
||||||
>
|
>
|
||||||
<div class="cl-chat">
|
<div class="cl-chat">
|
||||||
<!-- 会话列表 -->
|
<!-- 会话列表 -->
|
||||||
@ -29,7 +29,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #slot-session>
|
<!-- 展开按钮 -->
|
||||||
|
<template #slot-expand>
|
||||||
<button v-if="session">
|
<button v-if="session">
|
||||||
<i
|
<i
|
||||||
class="el-icon-notebook-2"
|
class="el-icon-notebook-2"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import Upload from "./index.vue";
|
import Upload from "./index.vue";
|
||||||
import UploadSpace from "./space.vue";
|
import UploadSpace from "./space/index.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Upload,
|
Upload,
|
||||||
|
|||||||
@ -1,721 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="cl-upload-space__wrap">
|
|
||||||
<slot>
|
|
||||||
<el-button v-if="showButton" size="mini" @click="open">点击上传</el-button>
|
|
||||||
</slot>
|
|
||||||
|
|
||||||
<!-- 弹框 -->
|
|
||||||
<cl-dialog :visible.sync="visible" v-bind="props" :op-list="['close']">
|
|
||||||
<div class="cl-upload-space">
|
|
||||||
<!-- 类目 -->
|
|
||||||
<div class="cl-upload-space__category">
|
|
||||||
<div class="cl-upload-space__category-search">
|
|
||||||
<el-button type="primary" size="mini" @click="editCategory()"
|
|
||||||
>添加分类</el-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<el-input
|
|
||||||
v-model="category.keyword"
|
|
||||||
placeholder="输入关键字过滤"
|
|
||||||
size="mini"
|
|
||||||
></el-input>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cl-upload-space__category-list">
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
v-for="(item, index) in categoryList"
|
|
||||||
:key="index"
|
|
||||||
:class="{
|
|
||||||
'is-active': item.id == category.current.id
|
|
||||||
}"
|
|
||||||
@click="selectCategory(item)"
|
|
||||||
@contextmenu.stop.prevent="openCategoryContextMenu($event, item)"
|
|
||||||
>
|
|
||||||
{{ item.name }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容 -->
|
|
||||||
<div class="cl-upload-space__content">
|
|
||||||
<!-- 操作栏 -->
|
|
||||||
<div class="cl-upload-space__opbar">
|
|
||||||
<el-button
|
|
||||||
type="success"
|
|
||||||
size="mini"
|
|
||||||
:disabled="selection.length === 0"
|
|
||||||
@click="confirmFile()"
|
|
||||||
>使用选中文件</el-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
size="mini"
|
|
||||||
:disabled="selection.length === 0"
|
|
||||||
@click="deleteFile()"
|
|
||||||
>删除选中文件</el-button
|
|
||||||
>
|
|
||||||
|
|
||||||
<cl-upload
|
|
||||||
style="margin-left: 10px"
|
|
||||||
list-type="slot"
|
|
||||||
:action="action"
|
|
||||||
:accept="accept"
|
|
||||||
:limit-size="limitSize"
|
|
||||||
:show-file-list="false"
|
|
||||||
:headers="headers"
|
|
||||||
:data="data"
|
|
||||||
:disabled="disabled"
|
|
||||||
:rename="rename"
|
|
||||||
:on-success="onSuccess"
|
|
||||||
:on-progress="onProgress"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
>
|
|
||||||
<el-button size="mini" type="primary">点击上传</el-button>
|
|
||||||
</cl-upload>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 文件区域 -->
|
|
||||||
<div
|
|
||||||
class="cl-upload-space__file"
|
|
||||||
v-loading="file.loading"
|
|
||||||
element-loading-text="拼命加载中"
|
|
||||||
>
|
|
||||||
<!-- 文件列表 -->
|
|
||||||
<el-row v-if="file.list.length > 0">
|
|
||||||
<el-col :span="6" v-for="item in file.list" :key="item.id">
|
|
||||||
<file-item
|
|
||||||
:value="item"
|
|
||||||
:element-loading-text="item.progress"
|
|
||||||
v-loading="item.loading"
|
|
||||||
></file-item>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
|
|
||||||
<!-- 空态 -->
|
|
||||||
<div class="cl-upload-space__file-empty" v-else>
|
|
||||||
<cl-upload
|
|
||||||
drag
|
|
||||||
:action="action"
|
|
||||||
:accept="accept"
|
|
||||||
:limit-size="limitSize"
|
|
||||||
:headers="headers"
|
|
||||||
:data="data"
|
|
||||||
:disabled="disabled"
|
|
||||||
:rename="rename"
|
|
||||||
:on-success="onSuccess"
|
|
||||||
:on-progress="onProgress"
|
|
||||||
:before-upload="beforeUpload"
|
|
||||||
>
|
|
||||||
<i class="el-icon-upload"></i>
|
|
||||||
<div class="el-upload__text">
|
|
||||||
将文件拖到此处,或<em>点击上传</em>
|
|
||||||
</div>
|
|
||||||
</cl-upload>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 分页 -->
|
|
||||||
<el-pagination
|
|
||||||
background
|
|
||||||
:page-size="file.pagination.size"
|
|
||||||
:current-page="file.pagination.page"
|
|
||||||
:total="file.pagination.total"
|
|
||||||
@current-change="onCurrentChange"
|
|
||||||
></el-pagination>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</cl-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { mapGetters } from "vuex";
|
|
||||||
import { last, isEmpty } from "cl-admin/utils";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: "cl-upload-space",
|
|
||||||
|
|
||||||
componentName: "UploadSpace",
|
|
||||||
|
|
||||||
props: {
|
|
||||||
// 上传的地址
|
|
||||||
action: String,
|
|
||||||
// 选择图片的长度
|
|
||||||
limit: {
|
|
||||||
type: Number,
|
|
||||||
default: 8
|
|
||||||
},
|
|
||||||
// 最大允许上传文件大小(MB)
|
|
||||||
limitSize: {
|
|
||||||
type: Number,
|
|
||||||
default: 10
|
|
||||||
},
|
|
||||||
// 是否禁用
|
|
||||||
disabled: Boolean,
|
|
||||||
// 是否以 uuid 重命名
|
|
||||||
rename: Boolean,
|
|
||||||
// 设置上传的请求头部
|
|
||||||
headers: Object,
|
|
||||||
// 上传时附带的额外参数
|
|
||||||
data: Object,
|
|
||||||
// 上传的文件类型
|
|
||||||
accept: String,
|
|
||||||
// 是否返回详细数据
|
|
||||||
detailData: Boolean,
|
|
||||||
// 是否显示按钮
|
|
||||||
showButton: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
components: {
|
|
||||||
fileItem: {
|
|
||||||
props: {
|
|
||||||
value: Object
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
parent() {
|
|
||||||
let parent = this;
|
|
||||||
|
|
||||||
while (parent.$options.componentName != "UploadSpace") {
|
|
||||||
parent = parent.$parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
onSelect() {
|
|
||||||
this.parent.selectFile(this.value);
|
|
||||||
},
|
|
||||||
|
|
||||||
onContextMenu(e) {
|
|
||||||
this.parent.openFileContextMenu(e, this.value);
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (!this.value) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
let itemEl = null;
|
|
||||||
|
|
||||||
const { url, type, selected, id } = this.value;
|
|
||||||
const fileType = (type || "").split("/")[0];
|
|
||||||
|
|
||||||
switch (fileType) {
|
|
||||||
case "image":
|
|
||||||
itemEl = <el-image fit="cover" src={url} lazy></el-image>;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "video":
|
|
||||||
itemEl = (
|
|
||||||
<video
|
|
||||||
controls
|
|
||||||
src={url}
|
|
||||||
style={{
|
|
||||||
"max-height": "100%",
|
|
||||||
"max-width": "100%"
|
|
||||||
}}></video>
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
itemEl = <span>{url}</span>;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
class={["cl-upload-space__file-item", `is-${fileType}`]}
|
|
||||||
on-click={this.onSelect}
|
|
||||||
on-contextmenu={this.onContextMenu}>
|
|
||||||
{itemEl}
|
|
||||||
|
|
||||||
<div class="cl-upload-space__file-size"></div>
|
|
||||||
|
|
||||||
{selected && (
|
|
||||||
<div class="cl-upload-space__file-mask">
|
|
||||||
<i class="el-icon-success"></i>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
visible: false,
|
|
||||||
props: {
|
|
||||||
title: "文件空间",
|
|
||||||
props: {
|
|
||||||
"close-on-click-modal": false,
|
|
||||||
"append-to-body": true,
|
|
||||||
width: "1000px"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
category: {
|
|
||||||
list: [],
|
|
||||||
current: {},
|
|
||||||
keyword: ""
|
|
||||||
},
|
|
||||||
file: {
|
|
||||||
list: [],
|
|
||||||
pagination: {
|
|
||||||
page: 1,
|
|
||||||
size: 12,
|
|
||||||
total: 0
|
|
||||||
},
|
|
||||||
loading: false
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
...mapGetters(["token"]),
|
|
||||||
|
|
||||||
categoryList() {
|
|
||||||
return this.category.list.filter(e => e.name.includes(this.category.keyword));
|
|
||||||
},
|
|
||||||
|
|
||||||
selection() {
|
|
||||||
return this.file.list.filter(e => e.selected);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
filters: {
|
|
||||||
file_name(url) {
|
|
||||||
return last(url.split("."));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
|
||||||
this.refreshCategory().then(() => {
|
|
||||||
this.category.current = this.category.list[0];
|
|
||||||
this.refreshFile();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
open(key) {
|
|
||||||
this.visible = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
close() {
|
|
||||||
this.visible = false;
|
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.file.list.map(e => {
|
|
||||||
this.$set(e, "selected", false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 上传成功
|
|
||||||
onSuccess(res, file) {
|
|
||||||
let item = this.file.list.find(e => file.uid == e.uid);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
item.url = res.data;
|
|
||||||
|
|
||||||
this.$service.space.info
|
|
||||||
.add({
|
|
||||||
url: res.data,
|
|
||||||
type: item.type,
|
|
||||||
classifyId: item.classifyId
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
item.loading = false;
|
|
||||||
item.id = res.id;
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
this.$message.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 上传前,添加文件
|
|
||||||
beforeUpload({ tempFilePath, type, uid }) {
|
|
||||||
this.file.list.unshift({
|
|
||||||
url: tempFilePath,
|
|
||||||
type,
|
|
||||||
uid,
|
|
||||||
classifyId: this.category.current.id,
|
|
||||||
loading: true,
|
|
||||||
progress: "0%"
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 上传进度
|
|
||||||
onProgress({ percent }, file) {
|
|
||||||
let item = this.file.list.find(({ uid }) => uid == file.uid);
|
|
||||||
|
|
||||||
if (item) {
|
|
||||||
item.progress = percent + "%";
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// 刷新资源文件
|
|
||||||
refreshFile(params) {
|
|
||||||
this.file.loading = true;
|
|
||||||
|
|
||||||
this.$service.space.info
|
|
||||||
.page({
|
|
||||||
...this.file.pagination,
|
|
||||||
...params,
|
|
||||||
classifyId: this.category.current.id,
|
|
||||||
type: this.accept
|
|
||||||
})
|
|
||||||
.then(res => {
|
|
||||||
this.file.pagination = res.pagination;
|
|
||||||
this.file.list = res.list;
|
|
||||||
})
|
|
||||||
.done(() => {
|
|
||||||
this.file.loading = false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 刷新分类
|
|
||||||
refreshCategory() {
|
|
||||||
return this.$service.space.type.list().then(res => {
|
|
||||||
res.unshift({
|
|
||||||
name: "全部文件",
|
|
||||||
id: null
|
|
||||||
});
|
|
||||||
this.category.list = res;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 编辑分类
|
|
||||||
editCategory(item = {}) {
|
|
||||||
this.$crud.openForm({
|
|
||||||
title: "添加分类",
|
|
||||||
width: "400px",
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
label: "分类名称",
|
|
||||||
prop: "name",
|
|
||||||
value: item.name,
|
|
||||||
component: {
|
|
||||||
name: "el-input",
|
|
||||||
attrs: {
|
|
||||||
placeholder: "请填写分类名称"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
required: true,
|
|
||||||
message: "分类名称不能为空"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
on: {
|
|
||||||
submit: (data, { done, close }) => {
|
|
||||||
let next = null;
|
|
||||||
|
|
||||||
if (!item.id) {
|
|
||||||
next = this.$service.space.type.add(data);
|
|
||||||
} else {
|
|
||||||
next = this.$service.space.type.update({
|
|
||||||
...data,
|
|
||||||
id: item.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
next.then(() => {
|
|
||||||
this.refreshCategory();
|
|
||||||
close();
|
|
||||||
}).catch(err => {
|
|
||||||
this.$message.error(err);
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 选择类目
|
|
||||||
selectCategory(item) {
|
|
||||||
this.category.current = item;
|
|
||||||
this.file.pagination = {
|
|
||||||
page: 1,
|
|
||||||
size: 12,
|
|
||||||
total: 0
|
|
||||||
};
|
|
||||||
this.refreshFile({
|
|
||||||
classifyId: item.id
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 打开类目列表右键菜单
|
|
||||||
openCategoryContextMenu(e, { id, name }) {
|
|
||||||
if (!id) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.$crud.openContextMenu(e, {
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
label: "编辑",
|
|
||||||
"suffix-icon": "el-icon-edit",
|
|
||||||
callback: (_, done) => {
|
|
||||||
done();
|
|
||||||
this.editCategory({ id, name });
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
"suffix-icon": "el-icon-delete",
|
|
||||||
callback: (_, done) => {
|
|
||||||
done();
|
|
||||||
|
|
||||||
this.$confirm(`此操作将删除【${name}】下的文件, 是否继续?`, "提示", {
|
|
||||||
type: "warning"
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.$service.space.type
|
|
||||||
.delete({
|
|
||||||
ids: id
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.$message.success("删除成功");
|
|
||||||
this.refreshCategory();
|
|
||||||
|
|
||||||
// 删除当前类目时,重置选择
|
|
||||||
if (id == this.category.current.id) {
|
|
||||||
this.category.current = this.category.list[0];
|
|
||||||
this.refreshFile();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
this.$message.error(err);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 打开文件列表右键菜单
|
|
||||||
openFileContextMenu(e, data) {
|
|
||||||
this.$crud.openContextMenu(e, {
|
|
||||||
list: [
|
|
||||||
{
|
|
||||||
label: data.selected ? "取消选中" : "选中",
|
|
||||||
"suffix-icon": data.selected ? "el-icon-close" : "el-icon-check",
|
|
||||||
callback: (_, done) => {
|
|
||||||
this.selectFile(data);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: "删除",
|
|
||||||
"suffix-icon": "el-icon-delete",
|
|
||||||
callback: (_, done) => {
|
|
||||||
this.deleteFile(data);
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 确认选中文件
|
|
||||||
confirmFile() {
|
|
||||||
const selection = this.selection.filter((e, i) => i < this.limit);
|
|
||||||
const urls = selection.map(e => e.url).join(",");
|
|
||||||
|
|
||||||
this.$emit("input", urls);
|
|
||||||
this.$emit("confirm", this.detailData ? selection : urls);
|
|
||||||
|
|
||||||
this.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
// 选择文件
|
|
||||||
selectFile(item) {
|
|
||||||
this.$set(item, "selected", !item.selected);
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除选中文件
|
|
||||||
deleteFile(...selection) {
|
|
||||||
if (isEmpty(selection)) {
|
|
||||||
selection = this.selection;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$confirm("此操作将删除文件, 是否继续?", "提示", {
|
|
||||||
type: "warning"
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.$message.success("删除成功");
|
|
||||||
|
|
||||||
this.file.list = this.file.list.filter(
|
|
||||||
e => !selection.map(e => e.id).includes(e.id)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.$service.space.info
|
|
||||||
.delete({
|
|
||||||
ids: selection.map(e => e.id).join(",")
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
this.$message.error(err);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
},
|
|
||||||
|
|
||||||
// 选择页
|
|
||||||
onCurrentChange(i) {
|
|
||||||
this.refreshFile({
|
|
||||||
page: i
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.cl-upload-space {
|
|
||||||
display: flex;
|
|
||||||
min-height: 520px;
|
|
||||||
|
|
||||||
&__category {
|
|
||||||
width: 250px;
|
|
||||||
margin-right: 20px;
|
|
||||||
|
|
||||||
&-search {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
|
|
||||||
.el-button {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-list {
|
|
||||||
overflow: hidden auto;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
li {
|
|
||||||
list-style: none;
|
|
||||||
font-size: 14px;
|
|
||||||
height: 40px;
|
|
||||||
line-height: 40px;
|
|
||||||
border-bottom: 1px dashed #eee;
|
|
||||||
padding: 0 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&.is-active {
|
|
||||||
color: #409eff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__opbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__file {
|
|
||||||
height: calc(100% - 80px);
|
|
||||||
overflow: hidden auto;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
|
|
||||||
/deep/.cl-upload-space__file-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 160px;
|
|
||||||
width: 160px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
margin: 5px 0;
|
|
||||||
|
|
||||||
&.is-image {
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
img {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-video {
|
|
||||||
video {
|
|
||||||
max-height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cl-upload-space__file-size {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cl-upload-space__file-mask {
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 30px;
|
|
||||||
color: #67c23a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-empty {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 100px;
|
|
||||||
|
|
||||||
& > div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
border-radius: 6px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 180px;
|
|
||||||
width: 360px;
|
|
||||||
|
|
||||||
i {
|
|
||||||
font-size: 67px;
|
|
||||||
color: #c0c4cc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
275
src/cool/modules/upload/components/space/category.vue
Normal file
275
src/cool/modules/upload/components/space/category.vue
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="cl-upload-space-category"
|
||||||
|
:class="{
|
||||||
|
'is-position': browser.isMini,
|
||||||
|
'is-show': space.category.visible
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="cl-upload-space-category__search">
|
||||||
|
<el-button type="primary" size="mini" @click="edit()">添加分类</el-button>
|
||||||
|
|
||||||
|
<el-input v-model="keyword" placeholder="输入关键字过滤" size="mini"></el-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cl-upload-space-category__list">
|
||||||
|
<ul class="scroller1">
|
||||||
|
<li
|
||||||
|
v-for="(item, index) in flist"
|
||||||
|
:key="index"
|
||||||
|
:class="{
|
||||||
|
'is-active': item.id == current
|
||||||
|
}"
|
||||||
|
@click="select(item.id)"
|
||||||
|
@contextmenu.stop.prevent="openContextMenu($event, item)"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
import { isEmpty } from "cl-admin/utils";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "cl-upload-space-category",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: [Number]
|
||||||
|
},
|
||||||
|
|
||||||
|
inject: ["space"],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
list: [],
|
||||||
|
current: undefined,
|
||||||
|
keyword: ""
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["browser"]),
|
||||||
|
|
||||||
|
flist() {
|
||||||
|
return this.list.filter(e => e.name.includes(this.keyword));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
current: {
|
||||||
|
handler(id) {
|
||||||
|
this.$emit("input", id);
|
||||||
|
this.$emit("change", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
this.refresh();
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
// 刷新分类
|
||||||
|
refresh() {
|
||||||
|
return this.$service.space.type.list().then(res => {
|
||||||
|
res.unshift({
|
||||||
|
name: "全部文件",
|
||||||
|
id: null
|
||||||
|
});
|
||||||
|
|
||||||
|
this.list = res;
|
||||||
|
|
||||||
|
if (!isEmpty(res)) {
|
||||||
|
if (!this.current) {
|
||||||
|
this.current = res[0].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 编辑分类
|
||||||
|
edit(item = {}) {
|
||||||
|
this.$crud.openForm({
|
||||||
|
title: "添加分类",
|
||||||
|
width: "400px",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
label: "分类名称",
|
||||||
|
prop: "name",
|
||||||
|
value: item.name,
|
||||||
|
component: {
|
||||||
|
name: "el-input",
|
||||||
|
attrs: {
|
||||||
|
placeholder: "请填写分类名称"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
required: true,
|
||||||
|
message: "分类名称不能为空"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
on: {
|
||||||
|
submit: (data, { done, close }) => {
|
||||||
|
let next = null;
|
||||||
|
|
||||||
|
if (!item.id) {
|
||||||
|
next = this.$service.space.type.add(data);
|
||||||
|
} else {
|
||||||
|
next = this.$service.space.type.update({
|
||||||
|
...data,
|
||||||
|
id: item.id
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
next.then(() => {
|
||||||
|
this.refresh();
|
||||||
|
close();
|
||||||
|
}).catch(err => {
|
||||||
|
this.$message.error(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择类目
|
||||||
|
select(id) {
|
||||||
|
this.current = id;
|
||||||
|
|
||||||
|
// 小屏幕下收起左侧类目
|
||||||
|
if (this.browser.isMini) {
|
||||||
|
this.space.category.visible = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 打开类目列表右键菜单
|
||||||
|
openContextMenu(e, { id, name }) {
|
||||||
|
if (!id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$crud.openContextMenu(e, {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
label: "刷新",
|
||||||
|
"suffix-icon": "el-icon-edit",
|
||||||
|
callback: (_, done) => {
|
||||||
|
this.refresh();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "编辑",
|
||||||
|
"suffix-icon": "el-icon-edit",
|
||||||
|
callback: (_, done) => {
|
||||||
|
this.edit({ id, name });
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "删除",
|
||||||
|
"suffix-icon": "el-icon-delete",
|
||||||
|
callback: (_, done) => {
|
||||||
|
this.$confirm(`此操作将删除【${name}】下的文件, 是否继续?`, "提示", {
|
||||||
|
type: "warning"
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$service.space.type
|
||||||
|
.delete({
|
||||||
|
ids: [id]
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success("删除成功");
|
||||||
|
|
||||||
|
if (id == this.current) {
|
||||||
|
this.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.$message.error(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cl-upload-space-category {
|
||||||
|
height: 100%;
|
||||||
|
width: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: width 0.2s ease-in-out;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
&.is-show {
|
||||||
|
width: 250px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-position {
|
||||||
|
position: absolute;
|
||||||
|
left: 5px;
|
||||||
|
top: 51px;
|
||||||
|
height: calc(100% - 56px);
|
||||||
|
z-index: 3000;
|
||||||
|
|
||||||
|
&.is-show {
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
|
||||||
|
.el-button {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__list {
|
||||||
|
height: calc(100% - 48px);
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
font-size: 14px;
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
border-bottom: 1px dashed #eee;
|
||||||
|
padding: 0 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&.is-active {
|
||||||
|
color: $color-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
167
src/cool/modules/upload/components/space/file-item.vue
Normal file
167
src/cool/modules/upload/components/space/file-item.vue
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="cl-upload-space-item"
|
||||||
|
:class="[`is-${type}`]"
|
||||||
|
@click.stop.prevent="select"
|
||||||
|
@contextmenu.stop.prevent="openContextMenu"
|
||||||
|
>
|
||||||
|
<!-- 错误 -->
|
||||||
|
<template v-if="value.error">
|
||||||
|
<div class="cl-upload-space-item__error">上传失败:{{ value.error }}</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 成功 -->
|
||||||
|
<template v-else>
|
||||||
|
<!-- 图片 -->
|
||||||
|
<template v-if="type === 'image'">
|
||||||
|
<el-image fit="cover" :src="value.url" lazy></el-image>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 视频 -->
|
||||||
|
<template v-else-if="type === 'video'">
|
||||||
|
<video
|
||||||
|
controls
|
||||||
|
:src="value.url"
|
||||||
|
:style="{
|
||||||
|
'max-height': '100%',
|
||||||
|
'max-width': '100%'
|
||||||
|
}"
|
||||||
|
></video>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 其他 -->
|
||||||
|
<template v-else>
|
||||||
|
<span>{{ value.url }}</span>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 大小 -->
|
||||||
|
<div class="cl-upload-space-item__size"></div>
|
||||||
|
|
||||||
|
<!-- 遮罩层 -->
|
||||||
|
<div class="cl-upload-space-item__mask" v-if="isSelected">
|
||||||
|
<span>{{ index + 1 }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "cl-upload-space-item",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
value: Object
|
||||||
|
},
|
||||||
|
|
||||||
|
inject: ["space"],
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
index() {
|
||||||
|
return this.space.selection.findIndex(e => e.id === this.value.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
isSelected() {
|
||||||
|
return this.index >= 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
type() {
|
||||||
|
return (this.value.type || "").split("/")[0];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
select() {
|
||||||
|
this.$emit("select", this.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this.$emit("remove", this.value);
|
||||||
|
},
|
||||||
|
|
||||||
|
openContextMenu(e) {
|
||||||
|
this.$crud.openContextMenu(e, {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
label: this.isSelected ? "取消选中" : "选中",
|
||||||
|
"suffix-icon": this.isSelected ? "el-icon-close" : "el-icon-check",
|
||||||
|
callback: (_, done) => {
|
||||||
|
this.select();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "删除",
|
||||||
|
"suffix-icon": "el-icon-delete",
|
||||||
|
callback: (_, done) => {
|
||||||
|
this.remove();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cl-upload-space-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 160px;
|
||||||
|
width: 160px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
margin: 5px 10px 5px 0;
|
||||||
|
|
||||||
|
&.is-image {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.is-video {
|
||||||
|
video {
|
||||||
|
max-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__size {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__error {
|
||||||
|
padding: 10px;
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__mask {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
background-color: #67c23a;
|
||||||
|
color: #fff;
|
||||||
|
display: inline-block;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 20px;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
462
src/cool/modules/upload/components/space/index.vue
Normal file
462
src/cool/modules/upload/components/space/index.vue
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
<template>
|
||||||
|
<div class="cl-upload-space__wrap">
|
||||||
|
<slot>
|
||||||
|
<el-button v-if="showButton" size="mini" @click="open">点击上传</el-button>
|
||||||
|
</slot>
|
||||||
|
|
||||||
|
<!-- 弹框 -->
|
||||||
|
<cl-dialog
|
||||||
|
title="文件空间"
|
||||||
|
height="630px"
|
||||||
|
width="1000px"
|
||||||
|
:visible.sync="visible"
|
||||||
|
:props="{
|
||||||
|
'close-on-click-modal': false,
|
||||||
|
'append-to-body': true,
|
||||||
|
customClass: 'dialog-upload-space'
|
||||||
|
}"
|
||||||
|
:controls="['slot-expand', 'cl-flex1', 'fullscreen', 'close']"
|
||||||
|
>
|
||||||
|
<div class="cl-upload-space">
|
||||||
|
<!-- 类目 -->
|
||||||
|
<category v-model="category.id" @change="refresh()" />
|
||||||
|
|
||||||
|
<!-- 内容 -->
|
||||||
|
<div class="cl-upload-space__content">
|
||||||
|
<!-- 操作栏 -->
|
||||||
|
<div class="cl-upload-space__header scroller1">
|
||||||
|
<el-button size="mini" @click="refresh()">刷新</el-button>
|
||||||
|
|
||||||
|
<cl-upload
|
||||||
|
style="margin: 0 10px"
|
||||||
|
list-type="slot"
|
||||||
|
:action="action"
|
||||||
|
:accept="accept"
|
||||||
|
:limit-size="limitSize"
|
||||||
|
:show-file-list="false"
|
||||||
|
:headers="headers"
|
||||||
|
:data="data"
|
||||||
|
:disabled="disabled"
|
||||||
|
:rename="rename"
|
||||||
|
:on-success="onSuccess"
|
||||||
|
:on-error="onError"
|
||||||
|
:on-progress="onProgress"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
>
|
||||||
|
<el-button size="mini" type="primary">点击上传</el-button>
|
||||||
|
</cl-upload>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="success"
|
||||||
|
size="mini"
|
||||||
|
:disabled="!isSelected"
|
||||||
|
@click="confirm()"
|
||||||
|
>使用选中文件 {{ this.limitTip }}</el-button
|
||||||
|
>
|
||||||
|
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="mini"
|
||||||
|
:disabled="!isSelected"
|
||||||
|
@click="remove()"
|
||||||
|
>删除选中文件</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 文件区域 -->
|
||||||
|
<div
|
||||||
|
class="cl-upload-space__file scroller1"
|
||||||
|
v-loading="loading"
|
||||||
|
element-loading-text="拼命加载中"
|
||||||
|
>
|
||||||
|
<!-- 文件列表 -->
|
||||||
|
<template v-if="list.length > 0">
|
||||||
|
<div class="cl-upload-space__file-list">
|
||||||
|
<file-item
|
||||||
|
v-for="item in list"
|
||||||
|
:key="item.id"
|
||||||
|
:value="item"
|
||||||
|
:element-loading-text="item.progress"
|
||||||
|
v-loading="item.loading"
|
||||||
|
@select="select"
|
||||||
|
@remove="remove"
|
||||||
|
></file-item>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- 空态 -->
|
||||||
|
<div class="cl-upload-space__file-empty" v-else>
|
||||||
|
<cl-upload
|
||||||
|
drag
|
||||||
|
:action="action"
|
||||||
|
:accept="accept"
|
||||||
|
:limit-size="limitSize"
|
||||||
|
:headers="headers"
|
||||||
|
:data="data"
|
||||||
|
:disabled="disabled"
|
||||||
|
:rename="rename"
|
||||||
|
:on-success="onSuccess"
|
||||||
|
:on-error="onError"
|
||||||
|
:on-progress="onProgress"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
>
|
||||||
|
<i class="el-icon-upload"></i>
|
||||||
|
<div class="el-upload__text">
|
||||||
|
将文件拖到此处,或<em>点击上传</em>
|
||||||
|
</div>
|
||||||
|
</cl-upload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分页 -->
|
||||||
|
<div class="cl-upload-space__footer">
|
||||||
|
<el-pagination
|
||||||
|
background
|
||||||
|
:page-size="pagination.size"
|
||||||
|
:current-page="pagination.page"
|
||||||
|
:total="pagination.total"
|
||||||
|
@current-change="
|
||||||
|
page => {
|
||||||
|
refresh({ page });
|
||||||
|
}
|
||||||
|
"
|
||||||
|
></el-pagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 展开按钮 -->
|
||||||
|
<template #slot-expand>
|
||||||
|
<button>
|
||||||
|
<i
|
||||||
|
class="el-icon-notebook-2"
|
||||||
|
v-if="category.visible"
|
||||||
|
@click="category.visible = false"
|
||||||
|
></i>
|
||||||
|
<i class="el-icon-arrow-left" v-else @click="category.visible = true"></i>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</cl-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { isEmpty } from "cl-admin/utils";
|
||||||
|
import Category from "./category";
|
||||||
|
import FileItem from "./file-item";
|
||||||
|
import { mapGetters } from "vuex";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "cl-upload-space",
|
||||||
|
|
||||||
|
props: {
|
||||||
|
// 上传的地址
|
||||||
|
action: String,
|
||||||
|
// 选择图片的长度
|
||||||
|
limit: {
|
||||||
|
type: Number,
|
||||||
|
default: 9
|
||||||
|
},
|
||||||
|
// 最大允许上传文件大小(MB)
|
||||||
|
limitSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: Boolean,
|
||||||
|
// 是否以 uuid 重命名
|
||||||
|
rename: Boolean,
|
||||||
|
// 设置上传的请求头部
|
||||||
|
headers: Object,
|
||||||
|
// 上传时附带的额外参数
|
||||||
|
data: Object,
|
||||||
|
// 上传的文件类型
|
||||||
|
accept: String,
|
||||||
|
// 是否返回详细数据
|
||||||
|
detailData: Boolean,
|
||||||
|
// 是否显示按钮
|
||||||
|
showButton: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
components: {
|
||||||
|
Category,
|
||||||
|
FileItem
|
||||||
|
},
|
||||||
|
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
space: this
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: true,
|
||||||
|
loading: false,
|
||||||
|
category: {
|
||||||
|
id: null,
|
||||||
|
visible: true
|
||||||
|
},
|
||||||
|
selection: [],
|
||||||
|
list: [],
|
||||||
|
pagination: {
|
||||||
|
page: 1,
|
||||||
|
size: 12,
|
||||||
|
total: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters(["browser"]),
|
||||||
|
|
||||||
|
limitTip() {
|
||||||
|
return this.selection.length + "/" + this.limit;
|
||||||
|
},
|
||||||
|
|
||||||
|
isSelected() {
|
||||||
|
return !isEmpty(this.selection);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
"browser.isMini": {
|
||||||
|
immediate: true,
|
||||||
|
handler(val) {
|
||||||
|
this.category.visible = val ? false : true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
open() {
|
||||||
|
this.visible = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
close() {
|
||||||
|
this.visible = false;
|
||||||
|
this.clear();
|
||||||
|
},
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.selection = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传成功
|
||||||
|
onSuccess(res, file) {
|
||||||
|
const item = this.list.find(e => file.uid == e.uid);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
item.url = res.data;
|
||||||
|
|
||||||
|
this.$service.space.info
|
||||||
|
.add({
|
||||||
|
url: res.data,
|
||||||
|
type: item.type,
|
||||||
|
classifyId: item.classifyId
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
item.loading = false;
|
||||||
|
item.id = res.id;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.$message.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传失败
|
||||||
|
onError(err, file) {
|
||||||
|
const item = this.list.find(e => file.uid == e.uid);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
item.loading = false;
|
||||||
|
this.$set(item, "error", err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传前,添加文件
|
||||||
|
beforeUpload({ tempFilePath, type, uid }) {
|
||||||
|
this.list.unshift({
|
||||||
|
url: tempFilePath,
|
||||||
|
type,
|
||||||
|
uid,
|
||||||
|
classifyId: this.category.id,
|
||||||
|
loading: true,
|
||||||
|
progress: "0%"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 上传进度
|
||||||
|
onProgress({ percent }, file) {
|
||||||
|
const item = this.list.find(({ uid }) => uid == file.uid);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
item.progress = percent + "%";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 刷新资源文件
|
||||||
|
refresh(params) {
|
||||||
|
// 清空选择
|
||||||
|
this.clear();
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
this.$service.space.info
|
||||||
|
.page({
|
||||||
|
...this.pagination,
|
||||||
|
...params,
|
||||||
|
classifyId: this.category.id,
|
||||||
|
type: this.accept
|
||||||
|
})
|
||||||
|
.then(res => {
|
||||||
|
this.pagination = res.pagination;
|
||||||
|
this.list = res.list;
|
||||||
|
})
|
||||||
|
.done(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 确认选中
|
||||||
|
confirm() {
|
||||||
|
const urls = this.selection.map(e => e.url).join(",");
|
||||||
|
|
||||||
|
this.$emit("input", urls);
|
||||||
|
this.$emit("confirm", this.detailData ? this.selection : urls);
|
||||||
|
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
// 选择
|
||||||
|
select(item) {
|
||||||
|
const index = this.selection.findIndex(e => e.id === item.id);
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
this.selection.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
if (this.selection.length < this.limit) {
|
||||||
|
this.selection.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除选中
|
||||||
|
remove(...selection) {
|
||||||
|
if (isEmpty(selection)) {
|
||||||
|
selection = this.selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 已选文件 id
|
||||||
|
const ids = selection.map(e => e.id);
|
||||||
|
|
||||||
|
this.$confirm("此操作将删除文件, 是否继续?", "提示", {
|
||||||
|
type: "warning"
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.$message.success("删除成功");
|
||||||
|
|
||||||
|
// 删除文件及选择
|
||||||
|
ids.forEach(id => {
|
||||||
|
[this.list, this.selection].forEach(list => {
|
||||||
|
const index = list.findIndex(e => e.id === id);
|
||||||
|
list.splice(index, 1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 删除请求
|
||||||
|
this.$service.space.info
|
||||||
|
.delete({
|
||||||
|
ids
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.$message.error(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.dialog-upload-space {
|
||||||
|
.el-dialog {
|
||||||
|
&__body {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cl-upload-space {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #f7f7f7;
|
||||||
|
padding: 5px;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 50px;
|
||||||
|
overflow: auto hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__file {
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-list {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-empty {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 90px);
|
||||||
|
left: calc(50% - 160px);
|
||||||
|
|
||||||
|
/deep/.cl-upload {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.el-upload-dragger {
|
||||||
|
height: 180px;
|
||||||
|
width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
font-size: 67px;
|
||||||
|
color: #c0c4cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
padding: 9px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user