@@ -83,7 +83,7 @@ const router = new Router({ | |||
{ | |||
path: '/recycle', | |||
name: 'recycle', | |||
component: () => import('@/views/main_web/workspace/recyclebin'), | |||
component: () => import('@/views/main_web/recycle'), | |||
}, | |||
{ | |||
path: '/history', | |||
@@ -0,0 +1,136 @@ | |||
<template> | |||
<div class="collapse-unit" :class="{ 'collapse-unit-active': active }"> | |||
<div class="collapse-unit-title" @click.stop="active = !active"> | |||
<span>{{title}}</span> | |||
<div class="action-button">{{active ? '收起': '展开'}}</div> | |||
</div> | |||
<div class="collapse-unit-body"> | |||
<div | |||
class="collapse-unit-item" | |||
v-for="item in list" | |||
:key="item[itemKey]" | |||
:class="{ 'collapse-unit-item-active': item[itemKey] === selectedKey }" | |||
@click.stop="clickItem(item)" | |||
> | |||
{{item[itemLabel]}} | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
model: { | |||
prop: 'selectedKey', | |||
event: 'select', | |||
}, | |||
props: { | |||
itemKey: { | |||
type: String, | |||
default: 'key', | |||
}, | |||
itemLabel: { | |||
type: String, | |||
default: 'label', | |||
}, | |||
title: String, | |||
defaultExpand: Boolean, | |||
selectedKey: String, | |||
list: Array, // [{ key, label }] | |||
}, | |||
data() { | |||
return { | |||
active: this.defaultExpand || false, | |||
} | |||
}, | |||
methods: { | |||
clickItem(item) { | |||
this.$emit('select', item[this.itemKey]); | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.collapse-unit { | |||
margin-bottom: 10px; | |||
&-active { | |||
margin-bottom: 24px; | |||
.action-button:after { | |||
transform: rotate(-90deg); | |||
} | |||
.collapse-unit-body { | |||
height: 0; | |||
} | |||
.collapse-unit-title { | |||
background-color: #fff; | |||
} | |||
} | |||
&-body { | |||
border-radius: 8px; | |||
font-size: 14px; | |||
color: rgba(50, 50, 60, 100); | |||
overflow: auto; | |||
height: calc(100% - 44px); | |||
transition: height 0.1s linear; | |||
} | |||
&-title { | |||
position: relative; | |||
padding-left: 24px; | |||
color: rgba(0, 0, 0, 0.56); | |||
font-size: 14px; | |||
height: 44px; | |||
line-height: 44px; | |||
cursor: pointer; | |||
border-radius: 8px; | |||
background-color: transparent; | |||
transition: background-color 0.1s linear; | |||
.action-button { | |||
position: absolute; | |||
top: 0; | |||
bottom: 0; | |||
right: 40px; | |||
&:after { | |||
content: ''; | |||
position: absolute; | |||
width: 0; | |||
height: 0; | |||
top: 0; | |||
bottom: 0; | |||
right: -12 - 10px; | |||
margin: auto 0; | |||
border: 6px solid transparent; | |||
border-bottom-width: 0; | |||
border-top-color: #999B9D; | |||
transform-origin: center; | |||
transition: transform 0.1s linear; | |||
} | |||
} | |||
} | |||
&-item { | |||
height: 44px; | |||
line-height: 44px; | |||
padding-left: 24px; | |||
cursor: pointer; | |||
background-color: #fff; | |||
&:first-child { | |||
border-radius: 8px 8px 0 0; | |||
} | |||
&:last-child { | |||
border-radius: 0 0 8px 8px; | |||
} | |||
~ .collapse-unit-item { | |||
border-top: 1px solid rgba(0, 0, 0, 0.2);; | |||
} | |||
&:hover, | |||
&-active { | |||
background-color: rgba(50, 50, 60, 0.1); | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,46 @@ | |||
<template> | |||
<div :style="{ paddingLeft: `${indent > 1 ? 10 : 0}px` }"> | |||
<template v-for="node in list"> | |||
<list-file-item | |||
v-if="node.nodeType === 'file'" | |||
:key="node.id" | |||
:file="node" | |||
:readOnly="readOnly" | |||
:checked="selectedKeyMap[node.id]" | |||
@check="check" | |||
:indent="indent" | |||
/> | |||
<list-folder-item | |||
v-else | |||
:key="node.id" | |||
:folder="node" | |||
:readOnly="readOnly" | |||
@check="check" | |||
:selectedKeyMap="selectedKeyMap" | |||
:indent="indent" | |||
/> | |||
</template> | |||
</div> | |||
</template> | |||
<script> | |||
import ListFileItem from './list-file-item'; | |||
import ListFolderItem from './list-folder-item'; | |||
export default { | |||
components: { ListFileItem, ListFolderItem }, | |||
props: { | |||
list: Array, | |||
readOnly: Boolean, | |||
selectedKeyMap: Object, | |||
indent: { | |||
type: Number, | |||
default: 0, | |||
} | |||
}, | |||
methods: { | |||
check(node) { | |||
this.$emit('check', node); | |||
} | |||
} | |||
} | |||
</script> |
@@ -0,0 +1,122 @@ | |||
<template> | |||
<div class="list-file-item"> | |||
<div class="list-file-item-cell"> | |||
<el-checkbox v-show="!readOnly" :value="!!checked" @change="onCheckChange" class="list-file-item-checkbox" /> | |||
<span :title="fileName">{{fileName}}</span> | |||
</div> | |||
<div class="list-file-item-cell"> | |||
<span>V{{file.version}}</span> | |||
</div> | |||
<!-- <div class="list-file-item-cell" > | |||
<span>V{{file.version}}</span> | |||
</div> --> | |||
<div class="list-file-item-cell" > | |||
<span>{{file.modifyName}}</span> | |||
</div> | |||
<div class="list-file-item-cell"> | |||
<span>{{file.modifyTime | formatTime}}</span> | |||
</div> | |||
<div class="list-file-item-cell"> | |||
<span></span> | |||
</div> | |||
<!-- <div class="list-file-item-cell" :style="{ flex: '90' }"></div> --> | |||
</div> | |||
</template> | |||
<script> | |||
import dayjs from 'dayjs'; | |||
const getMap = (...args) => args.reduce((h, v) => (h[v] = true, h), {}); | |||
const imgType = getMap('jpg', 'png', 'bmp', 'gif', 'jpeg'); | |||
const docType = getMap('doc','docx','ppt','pptx','xls','xlsx', 'pdf', 'txt'); | |||
const videoType = getMap('avi', 'mov', 'wav','mp4'); | |||
const exeType = getMap('exe'); | |||
const zipType = getMap('zip'); | |||
export default { | |||
props: { | |||
file: Object, | |||
readOnly: Boolean, | |||
checked: Boolean, | |||
}, | |||
filters: { | |||
formatTime(v) { | |||
return dayjs(v).format('YYYY年MM月DD日 A HH:mm'); | |||
} | |||
}, | |||
computed: { | |||
fileName(){ | |||
const file = this.file; | |||
return `${file.archName}${file.extension ? `.${file.extension}`:''}`; | |||
}, | |||
fileType() { | |||
const ext = this.file.extension; | |||
if(imgType[ext]) return '图片'; | |||
if(docType[ext]) return '文档'; | |||
if(videoType[ext]) return '视频'; | |||
if(exeType[ext]) return '可执行程序'; | |||
if(zipType[ext]) return '压缩文件'; | |||
return '未识别'; | |||
} | |||
}, | |||
methods: { | |||
onCheckChange(){ | |||
this.$emit('check', this.file); | |||
} | |||
} | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
.list-file-item { | |||
display: flex; | |||
flex-direction: row; | |||
font-size: 12px; | |||
padding-left: 24px; | |||
&:hover { | |||
// border-radius: 4px; | |||
background-color: rgba(50, 50, 60, 0.1); | |||
} | |||
&-cell { | |||
height: 32px; | |||
line-height: 32px; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
overflow: hidden; | |||
&:not(:first-child) { | |||
&:before { | |||
content: ''; | |||
display: inline-block; | |||
width: 1px; | |||
height: 1px; | |||
margin-right: 10px; | |||
} | |||
} | |||
&:nth-child(1) { | |||
flex: 1; | |||
} | |||
&:nth-child(2), | |||
&:nth-child(3) { | |||
flex: 0 0 121px; | |||
} | |||
&:nth-child(4) { | |||
flex: 0 0 181px; | |||
} | |||
&:nth-child(5) { | |||
flex: 0 0 121px; | |||
} | |||
} | |||
&-checkbox { | |||
margin-right: 5px; | |||
::v-deep .el-checkbox__input { | |||
line-height: 1em; | |||
} | |||
::v-deep .el-checkbox__inner { | |||
width: 20px; | |||
height: 20px; | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,187 @@ | |||
<template> | |||
<div | |||
class="list-folder-item" | |||
:class="{ large: indent === 0 }" | |||
> | |||
<div class="list-folder-item-header"> | |||
<div | |||
@click.stop="expanded = !expanded" | |||
class="list-folder-item-lever" | |||
:class="{ 'list-folder-item-expanded': expanded }" | |||
/> | |||
<div | |||
class="list-folder-item-cell" | |||
:style="{ flex: 1 }" | |||
> | |||
<img | |||
class="list-folder-item-icon" | |||
src="static/img/file.png" | |||
/> | |||
<span>{{folder.folderName}}</span> | |||
<div | |||
v-if="!readOnly" | |||
class="list-folder-item-checkall" | |||
> | |||
<el-checkbox | |||
label="全选" | |||
:value="isChildrenAllChecked" | |||
@change="check(folder)" | |||
/> | |||
</div> | |||
</div> | |||
<!-- <div | |||
class="list-folder-item-cell " | |||
:class="{ 'list-folder-item-expanded': expanded }" | |||
:style="{ flex: '90' }" | |||
@click.stop="expanded = !expanded" | |||
> | |||
<span :style="{ marginLeft: '10px' }">{{ expanded ? '折叠' : '展开' }}</span> | |||
</div> --> | |||
</div> | |||
<item-list | |||
class="list-folder-item-body" | |||
:class="{ 'list-folder-item-body-hide': !expanded }" | |||
:list="folder.children" | |||
@check="check" | |||
:readOnly="readOnly" | |||
:selectedKeyMap="selectedKeyMap" | |||
:indent="indent + 1" | |||
/> | |||
</div> | |||
</template> | |||
<script> | |||
export default { | |||
components: { ItemList: () => import("./item-list") }, | |||
props: { | |||
folder: Object, | |||
readOnly: Boolean, | |||
selectedKeyMap: Object, | |||
indent: { | |||
type: Number, | |||
default: 0, | |||
}, | |||
}, | |||
data() { | |||
return { | |||
expanded: this.indent === 0, | |||
}; | |||
}, | |||
computed: { | |||
isChildrenAllChecked() { | |||
return recursionEvery(this.folder.children, this.selectedKeyMap); | |||
}, | |||
}, | |||
methods: { | |||
check(node) { | |||
this.$emit("check", node); | |||
}, | |||
}, | |||
}; | |||
function recursionEvery(list, checkedMap) { | |||
return list.every((node) => { | |||
if (node.nodeType === "file") return checkedMap[node.id]; | |||
return recursionEvery(node.children, checkedMap); | |||
}); | |||
} | |||
</script> | |||
<style lang="less" scoped> | |||
.list-folder-item { | |||
&.large { | |||
border-bottom: 1px solid rgba(0, 0, 0, 0.2); | |||
> .list-folder-item-header { | |||
> .list-folder-item-cell { | |||
height: 44px; | |||
line-height: 44px; | |||
font-size: 16px; | |||
} | |||
.list-folder-item-icon { | |||
display: none; | |||
} | |||
.list-folder-item-checkall { | |||
margin-left: 10px; | |||
right: 24px; | |||
::v-deep .el-checkbox__inner { | |||
width: 20px; | |||
height: 20px; | |||
} | |||
::v-deep .el-checkbox__label { | |||
font-size: 16px; | |||
} | |||
} | |||
} | |||
} | |||
&-header { | |||
position: relative; | |||
display: flex; | |||
flex-direction: row; | |||
// border-bottom: 1px solid rgba(0, 0, 0, 0.2); | |||
// &:hover { | |||
// // border-radius: 4px; | |||
// background-color: rgba(50, 50, 60, 0.1); | |||
// } | |||
} | |||
&-body { | |||
overflow: hidden; | |||
&-hide { | |||
height: 0; | |||
} | |||
} | |||
&-cell { | |||
position: relative; | |||
height: 32px; | |||
line-height: 32px; | |||
font-size: 12px; | |||
} | |||
&-icon { | |||
@iconWidth: 22px; | |||
position: relative; | |||
top: (32px - @iconWidth) / 2; | |||
left: -1px; | |||
width: @iconWidth; | |||
margin-right: 5px; | |||
} | |||
&-checkall { | |||
position: absolute; | |||
right: 17px; | |||
top: 0; | |||
} | |||
&-lever { | |||
cursor: pointer; | |||
position: relative; | |||
flex: 0 0 24px; | |||
// &:before { | |||
// content: ''; | |||
// position: absolute; | |||
// left: 0; | |||
// top: 0; | |||
// bottom: 0; | |||
// margin: auto 0; | |||
// width: 1px; | |||
// height: 25px; | |||
// background-color: rgba(17, 17, 17, 0.1); | |||
// } | |||
&:after { | |||
content: ""; | |||
position: absolute; | |||
top: 0; | |||
bottom: 0; | |||
margin: auto 0; | |||
right: 6px; | |||
width: 0; | |||
height: 0; | |||
border: 6px solid transparent; | |||
border-top-color: #999b9d; | |||
border-bottom-width: 0; | |||
transition: transform 0.1s linear; | |||
transform: rotate(-90deg); | |||
} | |||
} | |||
&-expanded:after { | |||
transform: rotate(0deg); | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,442 @@ | |||
<template> | |||
<div> | |||
<app-header | |||
theme="basis" | |||
showBackBtn | |||
:backBtnTitle="title" | |||
showUserCenter | |||
isInRecycle | |||
showRecycleBin | |||
> | |||
<template #center> | |||
<div class="main-title">回收站</div> | |||
</template> | |||
<template #right> | |||
<!-- <search-bar | |||
class="proj-search-bar" | |||
placeholder="请输入要搜索的文件" | |||
@search="searchForFile" | |||
:maxLength="35" | |||
/> --> | |||
</template> | |||
</app-header> | |||
<div class="recycle_content"> | |||
<div class="view-left"> | |||
<!-- <div class="view-left-title">从成果中选择交付物</div> --> | |||
<collapse-unit | |||
title="正在进行的项目" | |||
:list="aliveProjectList" | |||
v-model="selectedProjectId" | |||
itemKey="id" | |||
itemLabel="projName" | |||
style="max-height: 45%" | |||
/> | |||
<collapse-unit | |||
title="被删除的项目" | |||
:list="removedProjectList" | |||
v-model="selectedProjectId" | |||
itemKey="id" | |||
itemLabel="projName" | |||
style="max-height: 45%" | |||
/> | |||
</div> | |||
<div class="view-right"> | |||
<div class="view-right-title"> | |||
<span>文件</span> | |||
<el-button | |||
class="view-right-title-extra" | |||
@click.stop="selectable = !selectable" | |||
:type="selectable ? 'primary': undefined" | |||
>{{selectable ? '取消多选' : '多选'}}</el-button> | |||
</div> | |||
<div class="table-like"> | |||
<div class="table-header"> | |||
<div class="table-th">文件名</div> | |||
<div class="table-th">版本号</div> | |||
<!-- <div class="table-th">移除人</div> --> | |||
<div class="table-th">最后修改人</div> | |||
<div class="table-th">移除时间</div> | |||
<div class="table-th"> | |||
<!-- 操作 --> | |||
</div> | |||
</div> | |||
<item-list | |||
:list="rightPanelItemList" | |||
:readOnly="!selectable" | |||
:selectedKeyMap="selectedKeyMap" | |||
@check="toggleCheck" | |||
/> | |||
</div> | |||
<div class="view-right-bottom" v-if="selectable" > | |||
<el-button | |||
class="bottom-button" | |||
type="primary" | |||
:disabled="!canShowButton" | |||
>放回原处</el-button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</template> | |||
<script> | |||
import AppHeader from "@/components/app-header/app-header.vue"; | |||
// import SearchBar from "@/components/search-bar/search-bar"; | |||
import CollapseUnit from "./components/collapse-unit.vue"; | |||
import ItemList from "./components/item-list"; | |||
import { VirtualFolder } from "../workspace/helper"; | |||
import { firstCharToLowerCase } from "@/utils/tool"; | |||
export default { | |||
components: { AppHeader, /* SearchBar, */ CollapseUnit, ItemList }, | |||
mounted() { | |||
this.fetchProjectList(); | |||
}, | |||
data() { | |||
return { | |||
userId: sessionStorage.userId, | |||
title: "返回" + sessionStorage.pageTitle, | |||
// -------------------------------------- | |||
aliveProjectList: [], | |||
removedProjectList: [], | |||
selectedProjectId: undefined, | |||
rightPanelItemList: [], | |||
selectable: false, | |||
selectedKeyMap: {}, // 选中的文件的hash | |||
}; | |||
}, | |||
watch: { | |||
selectedProjectId(projectId) { | |||
this.fetchProjectRemovedFiles(projectId); | |||
this.selectable = false; | |||
}, | |||
selectable() { | |||
this.selectedKeyMap = {}; | |||
} | |||
}, | |||
computed: { | |||
canShowButton() { | |||
return Object.values(this.selectedKeyMap).filter(a => a).length; | |||
} | |||
}, | |||
methods: { | |||
searchForFile() { | |||
debugger; | |||
}, | |||
async fetchProjectList() { | |||
const res = await this.$fetchApi("project/queryAllProjectListByUserId", { | |||
userId: this.userId, | |||
}); | |||
const [aliveProjectList, removedProjectList] = (res.Data || []).reduce( | |||
(arr, upperProject) => { | |||
const project = firstCharToLowerCase(upperProject); | |||
if (project.nodeFolder) { | |||
project.nodeFolder = project.nodeFolder.map(firstCharToLowerCase); | |||
} | |||
arr[project.deleted ? 1 : 0].push(project); | |||
return arr; | |||
}, | |||
[[], []] | |||
); | |||
this.aliveProjectList = aliveProjectList; | |||
this.removedProjectList = removedProjectList; | |||
this.selectedProjectId = aliveProjectList.length | |||
? aliveProjectList[0].id | |||
: removedProjectList.length | |||
? removedProjectList[0].id | |||
: undefined; | |||
}, | |||
async fetchProjectRemovedFiles(projectId) { | |||
if (!projectId) { | |||
return; | |||
} | |||
const res = await this.$fetchApi( | |||
"file/queryFilesFromRecycleBinByProjectId", | |||
{ projectId } | |||
); | |||
const fileTreeList = (res.Data || []).reduce((oList, topNode) => { | |||
if (topNode.ProjArchives) { | |||
oList = oList.concat( | |||
resolveFileListToTree(topNode.ProjArchives, topNode.FolderName) | |||
); | |||
} | |||
return oList; | |||
}, []); | |||
this.rightPanelItemList = fileTreeList; | |||
}, | |||
toggleCheck(node) { | |||
const tempMap = this.selectedKeyMap; | |||
if (node.nodeType === "file") { | |||
this.selectedKeyMap = { ...tempMap, [node.id]: !tempMap[node.id] }; | |||
} else { | |||
// folder | |||
const relationKeys = []; | |||
let checkFlag = true; | |||
recursionForEach(node.children, (fileNode) => { | |||
relationKeys.push(fileNode.id); | |||
checkFlag = checkFlag && tempMap[fileNode.id]; | |||
}); | |||
const stateMap = relationKeys.reduce( | |||
(h, key) => ((h[key] = !checkFlag), h), | |||
{} | |||
); | |||
this.selectedKeyMap = { ...tempMap, ...stateMap }; | |||
} | |||
}, | |||
}, | |||
}; | |||
function generateFolder(folderMap, filePath) { | |||
const paths = filePath.split("/"); | |||
paths.forEach((_, idx) => { | |||
const fullRelativePath = paths.slice(0, idx + 1).join("/"); | |||
if (folderMap[fullRelativePath]) return; | |||
const folder = new VirtualFolder(fullRelativePath); | |||
folder.children = []; | |||
folder.nodeType = "folder"; | |||
const parentRelativePath = folder.parentFolderPath; | |||
folderMap[fullRelativePath] = folder; | |||
if (folderMap[parentRelativePath]) { | |||
folderMap[parentRelativePath].children.push(folder); | |||
} | |||
}); | |||
} | |||
function recursionForEach(list, f) { | |||
list.forEach((iNode) => { | |||
if (iNode.nodeType === "file") { | |||
f(iNode); | |||
return; | |||
} | |||
recursionForEach(iNode.children, f); | |||
}); | |||
} | |||
function resolveFileListToTree(upperFileList, nodeName) { | |||
const folderMap = {}; // [key: folderPath]: folder | |||
const headList = []; | |||
upperFileList.forEach((upperFile) => { | |||
const file = firstCharToLowerCase(upperFile); | |||
file.nodeType = "file"; | |||
file.nodeFolderName = nodeName; | |||
// delete file.nodeName; | |||
if (!file.nodeFolderName) { | |||
headList.push(file); | |||
return; | |||
} | |||
const filePath = `${file.nodeFolderName}${ | |||
file.relativePath ? `/${file.relativePath}` : "" | |||
}`; | |||
generateFolder(folderMap, filePath); | |||
const folder = folderMap[filePath]; | |||
folder.children.push(file); | |||
}); | |||
// const headFolder = []; | |||
Object.values(folderMap).forEach((folder) => { | |||
// 取顶级文件夹 | |||
if (!folder.parentFolderPath) { | |||
headList.push(folder); | |||
} | |||
// 排序 | |||
folder.children = folder.children | |||
.filter((i) => i.nodeType === "file") | |||
.concat(folder.children.filter((i) => i.nodeType !== "file")); | |||
}); | |||
return headList; | |||
} | |||
function recursionEvery(list, checkedMap) { | |||
return list.every((node) => { | |||
if (node.nodeType === "file") return checkedMap[node.id]; | |||
return recursionEvery(node.children, checkedMap); | |||
}); | |||
} | |||
</script> | |||
<style lang="scss" scoped> | |||
.recycle_content { | |||
padding: 0 40px; | |||
height: 100%; | |||
box-sizing: border-box; | |||
$leftViewWidth: 328px; | |||
.view-left { | |||
display: inline-flex; | |||
flex-direction: column; | |||
vertical-align: top; | |||
width: $leftViewWidth; | |||
height: 100%; | |||
padding-top: 8px; | |||
box-sizing: border-box; | |||
} | |||
.view-right { | |||
display: inline-block; | |||
vertical-align: top; | |||
width: calc(100% - #{$leftViewWidth} - 32px); | |||
height: 100%; | |||
margin-left: 32px; | |||
// padding-top: 14px; | |||
box-sizing: border-box; | |||
background-color: rgba(252, 252, 252, 1); | |||
border-radius: 8px 8px 0 0; | |||
overflow: hidden; | |||
box-shadow: 0px 4px 10px 1px rgba(0, 0, 0, 0.1), | |||
0px 1px 3px 0px rgba(0, 0, 0, 0.1); | |||
&-title { | |||
position: relative; | |||
height: 56px; | |||
line-height: 56px; | |||
color: rgba(50, 50, 60, 100); | |||
font-size: 20px; | |||
padding-left: 24px; | |||
background-color: rgba(248, 248, 248, 1); | |||
border-bottom: 1px solid rgba(0, 0, 0, 0.2); | |||
&-extra { | |||
position: absolute; | |||
top: 12px; | |||
right: 24px; | |||
} | |||
} | |||
&-button { | |||
margin-left: calc(50% - #{$leftViewWidth} / 2 - 120px); | |||
box-shadow: 0px 4px 10px 0px rgba(0, 0, 0, 0.1), | |||
0px 2px 5px 0px rgba(0, 0, 0, 0.16); | |||
margin-bottom: 6px; | |||
} | |||
&-bottom { | |||
height: 80px; | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
.bottom-button { | |||
width: calc(100% - 40px); | |||
height: 40px; | |||
} | |||
} | |||
} | |||
.table-like { | |||
height: calc(100% - 80px - 56px); | |||
overflow: auto; | |||
.table-header { | |||
display: flex; | |||
flex-direction: row; | |||
border-bottom: 1px solid rgba(0, 0, 0, 0.2); | |||
.table-th { | |||
position: relative; | |||
box-sizing: border-box; | |||
color: #32323c; | |||
// flex: 124; | |||
font-size: 12px; | |||
height: 44px; | |||
line-height: 44px; | |||
&:nth-child(1) { | |||
flex: 1; | |||
padding-left: 24px; | |||
} | |||
&:nth-child(2), | |||
&:nth-child(3) { | |||
flex: 0 0 121px; | |||
} | |||
&:nth-child(4) { | |||
flex: 0 0 181px; | |||
} | |||
&:nth-child(5) { | |||
flex: 0 0 121px; | |||
} | |||
// &:nth-child(5) { | |||
// flex: 90; | |||
// } | |||
&:not(:first-child):not(:last-child) { | |||
&:after { | |||
content: ""; | |||
position: absolute; | |||
left: 0; | |||
top: 0; | |||
bottom: 0; | |||
margin: auto 0; | |||
width: 1px; | |||
height: 35px; | |||
background-color: rgba(17, 17, 17, 0.1); | |||
} | |||
&:before { | |||
content: ""; | |||
display: inline-block; | |||
width: 1px; | |||
height: 1px; | |||
margin-right: 10px; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
.panel { | |||
&:not(:first-child) { | |||
border-top: 1px solid rgba(0, 0, 0, 0.2); | |||
} | |||
&-wrapper { | |||
border-top-color: transparent; | |||
border-bottom-color: transparent; | |||
} | |||
::v-deep .el-collapse-item__header, | |||
::v-deep .el-collapse-item__wrap { | |||
background-color: transparent; | |||
// border-bottom-color: transparent; | |||
border-bottom: 0; | |||
} | |||
// ::v-deep .el-collapse-item__wrap { | |||
// } | |||
::v-deep .el-collapse-item__header { | |||
padding-left: 24px; | |||
height: 43px; | |||
line-height: 43px; | |||
} | |||
.list-item { | |||
position: relative; | |||
padding-left: 24px; | |||
height: 44px; | |||
line-height: 44px; | |||
cursor: pointer; | |||
> span { | |||
position: relative; | |||
z-index: 2; | |||
} | |||
&:before { | |||
content: ""; | |||
position: absolute; | |||
top: 0px; | |||
left: 24px; | |||
right: 0; | |||
height: 1px; | |||
background-color: rgba(0, 0, 0, 0.2); | |||
transform: scaleY(0.5); | |||
} | |||
&.disabled { | |||
cursor: default; | |||
} | |||
&:not(.disabled):hover, | |||
&-active { | |||
&:after { | |||
content: ""; | |||
position: absolute; | |||
z-index: 1; | |||
top: 0; | |||
bottom: 0; | |||
left: 10px; | |||
right: 0px; | |||
background-color: rgba(#cbcbce, 0.5); | |||
border-radius: 10px 0 0 10px; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
</style> |
@@ -0,0 +1,23 @@ | |||
import { fetchApi, wrapErrorHint } from "@/utils/request"; | |||
import { firstCharToLowerCase } from "@/utils/tool"; | |||
/** | |||
* 查询删除的文件 | |||
*/ | |||
export async function queryFilesFromRecycleBin() { | |||
const res = await fetchApi('file/queryFilesFromRecycleBin'); | |||
wrapErrorHint(res); | |||
if (res.Code !== 0) return null; | |||
const fileList = (res.Data || []).map(file => { | |||
const lower = firstCharToLowerCase(file); | |||
return lower; | |||
}); | |||
return fileList; | |||
} | |||
/** | |||
* 文件放回原处 | |||
*/ | |||
export async function removeFromRecycleBin(id) { | |||
const res = await fetchApi('file/removeFromRecycleBin', { fileId: id }); | |||
return wrapErrorHint(res); | |||
} |
@@ -19,26 +19,6 @@ export async function fetchWorkFlow(projectId, userId) { | |||
}, []); | |||
return list; | |||
} | |||
/** | |||
* 查询删除的文件 | |||
*/ | |||
export async function queryFilesFromRecycleBin() { | |||
const res = await fetchApi('file/queryFilesFromRecycleBin'); | |||
wrapErrorHint(res); | |||
if (res.Code !== 0) return null; | |||
const fileList = (res.Data || []).map(file => { | |||
const lower = firstCharToLowerCase (file); | |||
return lower; | |||
}); | |||
return fileList; | |||
} | |||
/** | |||
* 文件放回原处 | |||
*/ | |||
export async function removeFromRecycleBin(id){ | |||
const res = await fetchApi('file/removeFromRecycleBin',{fileId:id}); | |||
return wrapErrorHint(res); | |||
} | |||
/** | |||
* 查询文件夹下边的文件(包含子文件夹以及协同文件) | |||