|
|
|
<template>
|
|
|
|
<div class="firmware-management-wrap">
|
|
|
|
<EdfsWrap class="firmware-table" :customLeft="true">
|
|
|
|
<template #title-left>
|
|
|
|
<el-breadcrumb :separator-icon="ArrowRight">
|
|
|
|
<template v-for="(item, index) in breadcrumbList" :key="index">
|
|
|
|
<el-breadcrumb-item
|
|
|
|
:class="{ active: index + 1 < breadcrumbList.length }"
|
|
|
|
@click="onCrumb(item)"
|
|
|
|
>{{ item.name }}</el-breadcrumb-item
|
|
|
|
>
|
|
|
|
</template>
|
|
|
|
</el-breadcrumb>
|
|
|
|
</template>
|
|
|
|
<EdfsContextMenu
|
|
|
|
eventSourceClass="SourceClass"
|
|
|
|
:disabledEmpty="false"
|
|
|
|
@visibleChange="onVisibleChange"
|
|
|
|
ref="contextMenuRef"
|
|
|
|
:menuList="dropdownMenu"
|
|
|
|
@beforeContextmenu="onBeforeContextmenu"
|
|
|
|
>
|
|
|
|
<div class="file-list">
|
|
|
|
<div v-for="item in dataList" :key="item.id" @click="onFileOpen(item)">
|
|
|
|
<div class="item SourceClass" v-setItem="item">
|
|
|
|
<div class="file-header">
|
|
|
|
<div></div>
|
|
|
|
<Icon
|
|
|
|
class="icon"
|
|
|
|
icon="solar:hamburger-menu-outline"
|
|
|
|
@click="onFile"
|
|
|
|
></Icon>
|
|
|
|
</div>
|
|
|
|
<div class="file-icon">
|
|
|
|
<img
|
|
|
|
:src="
|
|
|
|
item.type === floeType.folder
|
|
|
|
? Folder
|
|
|
|
: item.isDraft === 0
|
|
|
|
? Document
|
|
|
|
: Document2
|
|
|
|
"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div class="file-name">
|
|
|
|
<el-input
|
|
|
|
class="edit-input"
|
|
|
|
@click.stop="() => {}"
|
|
|
|
v-if="!!item?.isEdit"
|
|
|
|
v-model="editFileName"
|
|
|
|
:key="item.id + '_edit'"
|
|
|
|
:ref="el => setInputRefs(el, item.id)"
|
|
|
|
@blur="onSaveRename(item)"
|
|
|
|
@keyup.enter="onSaveRename(item)"
|
|
|
|
/>
|
|
|
|
<span v-else>{{ item.name }}</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<template #menu="{ eventData, menuData }">
|
|
|
|
<div
|
|
|
|
v-for="menu in menuData"
|
|
|
|
:key="menu.command"
|
|
|
|
@click="onCommand(menu.command, eventData)"
|
|
|
|
>
|
|
|
|
<img
|
|
|
|
v-if="menu?.icon"
|
|
|
|
:src="menu?.icon"
|
|
|
|
width="20"
|
|
|
|
style="margin-right: 8px"
|
|
|
|
/>
|
|
|
|
<span :style="{ color: menu.command === 'delete' ? 'red' : 'inherit' }">{{
|
|
|
|
menu.label
|
|
|
|
}}</span>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</EdfsContextMenu>
|
|
|
|
</EdfsWrap>
|
|
|
|
</div>
|
|
|
|
<markdownDrawer
|
|
|
|
v-model="isShowMdDrawer"
|
|
|
|
v-if="isShowMdDrawer"
|
|
|
|
:data="curMarkdown"
|
|
|
|
:isRootMd="isRootMd"
|
|
|
|
@onSave="onSaveMd"
|
|
|
|
/>
|
|
|
|
<UploadMDDlg
|
|
|
|
:is-show="isShowMdDlg"
|
|
|
|
@on-close="isShowMdDlg = false"
|
|
|
|
@on-save="onUpdatedMdSave"
|
|
|
|
/>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
import {
|
|
|
|
floeType,
|
|
|
|
operationDropdownMenu,
|
|
|
|
breadcrumbList,
|
|
|
|
fileDropdownMenu,
|
|
|
|
} from './utils'
|
|
|
|
import EdfsWrap from '@/components/dashboard/Edfs-wrap.vue'
|
|
|
|
import {
|
|
|
|
getFileList,
|
|
|
|
createFolder,
|
|
|
|
updateFolder,
|
|
|
|
createdFile,
|
|
|
|
updateFile,
|
|
|
|
deleteFolder,
|
|
|
|
deleteFile,
|
|
|
|
deleteFolderAndFile,
|
|
|
|
getMarkdown,
|
|
|
|
updateMarkdown,
|
|
|
|
type ContentType,
|
|
|
|
} from '@/api/module/eam/device/document'
|
|
|
|
import { isResError, useMessage } from '@/hooks/useMessage.js'
|
|
|
|
import { ArrowRight } from '@element-plus/icons-vue'
|
|
|
|
import Folder from '@/assets/image/dashboard/file/folder.svg'
|
|
|
|
import Upload from '@/assets/image/dashboard/file/upload.svg'
|
|
|
|
import Document from '@/assets/image/dashboard/file/document.svg'
|
|
|
|
import Document2 from '@/assets/image/dashboard/file/document2.svg'
|
|
|
|
import UploadMDDlg from './components/uploadMDDlg.vue'
|
|
|
|
|
|
|
|
import { Icon } from '@/components/dashboard/Icon'
|
|
|
|
import EdfsContextMenu from '@/components/dashboard/Edfs-context-menu/index.vue'
|
|
|
|
import markdownDrawer from './components/markdownDrawer.vue'
|
|
|
|
|
|
|
|
const dropdownMenu = computed(() => {
|
|
|
|
if (isRootMd.value) {
|
|
|
|
return fileDropdownMenu.filter(v => v.command === 'open')
|
|
|
|
}
|
|
|
|
return menuTarget.value
|
|
|
|
? fileDropdownMenu
|
|
|
|
: currentFolderId.value === 0
|
|
|
|
? operationDropdownMenu.filter(v => v.command === 'newFolder')
|
|
|
|
: operationDropdownMenu.filter(v => ['uploadMD', 'newMarkdown'].includes(v.command))
|
|
|
|
})
|
|
|
|
|
|
|
|
const message = useMessage()
|
|
|
|
|
|
|
|
const currentFolderId = ref(0)
|
|
|
|
watch(
|
|
|
|
() => breadcrumbList.value.length,
|
|
|
|
() => {
|
|
|
|
currentFolderId.value = breadcrumbList.value[breadcrumbList.value.length - 1].id
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
const isRootMd = computed(
|
|
|
|
() => currentMenu.value?.type === floeType.file && currentFolderId.value === 0
|
|
|
|
)
|
|
|
|
|
|
|
|
const dataList = ref<any>([])
|
|
|
|
const loading = ref(false)
|
|
|
|
async function loadData(id: number = 0) {
|
|
|
|
loading.value = true
|
|
|
|
const res = await getFileList({
|
|
|
|
parentId: id,
|
|
|
|
})
|
|
|
|
loading.value = false
|
|
|
|
if (isResError(res)) {
|
|
|
|
// 错误 删除最后一个面包屑
|
|
|
|
if (breadcrumbList.value.length > 1) {
|
|
|
|
breadcrumbList.value.pop()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
dataList.value = res.data
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onDelete(item: any) {
|
|
|
|
try {
|
|
|
|
await message.delConfirm()
|
|
|
|
// switch (item.type) {
|
|
|
|
// case floeType.folder:
|
|
|
|
// res = await deleteFolder(item.id)
|
|
|
|
// break
|
|
|
|
// case floeType.file:
|
|
|
|
// res = await deleteFile(item.id)
|
|
|
|
// break
|
|
|
|
// }
|
|
|
|
const res = await deleteFolderAndFile(item.id)
|
|
|
|
|
|
|
|
if (isResError(res)) return
|
|
|
|
message.success('删除成功')
|
|
|
|
loadData(currentFolderId.value)
|
|
|
|
} catch (error) {}
|
|
|
|
}
|
|
|
|
|
|
|
|
const contextMenuRef = ref<any>(null)
|
|
|
|
function onFile(e: any) {
|
|
|
|
contextMenuRef.value.onContextmenu(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onNewFolder() {
|
|
|
|
const folder = {
|
|
|
|
name: '未命名文件夹',
|
|
|
|
type: floeType.folder,
|
|
|
|
isEdit: true,
|
|
|
|
}
|
|
|
|
dataList.value.push(folder)
|
|
|
|
onRename(folder)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onNewMarkdown() {
|
|
|
|
const markdown = {
|
|
|
|
name: '未命名文档',
|
|
|
|
type: floeType.file,
|
|
|
|
isEdit: true,
|
|
|
|
}
|
|
|
|
dataList.value.push(markdown)
|
|
|
|
onRename(markdown)
|
|
|
|
}
|
|
|
|
const curCommand = ref('')
|
|
|
|
function onCommand(command: string, item: any) {
|
|
|
|
curCommand.value = command
|
|
|
|
switch (command) {
|
|
|
|
case 'delete':
|
|
|
|
onDelete(item)
|
|
|
|
break
|
|
|
|
case 'rename':
|
|
|
|
onRename(item)
|
|
|
|
break
|
|
|
|
case 'open':
|
|
|
|
onFileOpen(item)
|
|
|
|
break
|
|
|
|
case 'newFolder':
|
|
|
|
onNewFolder()
|
|
|
|
break
|
|
|
|
case 'newMarkdown':
|
|
|
|
onNewMarkdown()
|
|
|
|
break
|
|
|
|
case 'uploadMD':
|
|
|
|
onUpdatedMd(item)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const isShowMdDlg = ref(false)
|
|
|
|
function onUpdatedMd(item: any) {
|
|
|
|
isShowMdDlg.value = true
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onUpdatedMdSave(fileName: string, fileContent: string) {
|
|
|
|
const id = await saveFile(true, {
|
|
|
|
name: fileName,
|
|
|
|
type: floeType.file,
|
|
|
|
})
|
|
|
|
if (id) {
|
|
|
|
curMdId.value = id
|
|
|
|
curMarkdown.value = {
|
|
|
|
fileName: fileName,
|
|
|
|
content: fileContent,
|
|
|
|
} as ContentType & { fileName: string }
|
|
|
|
isShowMdDrawer.value = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const menuTarget = ref<HTMLElement | null>(null)
|
|
|
|
function onVisibleChange(visible: boolean, currentElement: HTMLElement | null) {
|
|
|
|
menuTarget.value = currentElement
|
|
|
|
}
|
|
|
|
|
|
|
|
const currentMenu = ref<any>(null)
|
|
|
|
|
|
|
|
function onBeforeContextmenu(item: any) {
|
|
|
|
currentMenu.value = item
|
|
|
|
}
|
|
|
|
|
|
|
|
function onCrumb(item: any) {
|
|
|
|
const isLast = breadcrumbList.value[breadcrumbList.value.length - 1].id === item.id
|
|
|
|
if (isLast) return
|
|
|
|
const index = breadcrumbList.value.findIndex(v => v.id === item.id)
|
|
|
|
breadcrumbList.value = breadcrumbList.value.slice(0, index + 1)
|
|
|
|
loadData(item.id)
|
|
|
|
}
|
|
|
|
|
|
|
|
function onFileOpen(item: any) {
|
|
|
|
if (item.isEdit) return
|
|
|
|
if (item.type === floeType.folder) {
|
|
|
|
breadcrumbList.value.push(item)
|
|
|
|
loadData(item.id)
|
|
|
|
}
|
|
|
|
if (item.type === floeType.file) {
|
|
|
|
onOpenMarkdownDrawer(item.id)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const editInputRefs = ref<any>({})
|
|
|
|
function setInputRefs(el: any, id: number) {
|
|
|
|
if (el) {
|
|
|
|
editInputRefs.value[`editInputRef_${id}`] = el
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const editFileName = ref('')
|
|
|
|
async function onSaveRename(item: any) {
|
|
|
|
const find = findItem(item.id)
|
|
|
|
if (!find.isEdit) return
|
|
|
|
await nextTick()
|
|
|
|
debugger
|
|
|
|
find.isEdit = false
|
|
|
|
if (find.type === floeType.file && !editFileName.value.endsWith('.md')) {
|
|
|
|
editFileName.value += '.md'
|
|
|
|
}
|
|
|
|
if (find.name !== editFileName.value) {
|
|
|
|
find.name = editFileName.value
|
|
|
|
await onSaveFile(find)
|
|
|
|
}
|
|
|
|
|
|
|
|
editFileName.value = ''
|
|
|
|
}
|
|
|
|
async function onRename(item: any) {
|
|
|
|
if (!item) return
|
|
|
|
const find = findItem(item.id)
|
|
|
|
find.isEdit = true
|
|
|
|
editFileName.value = find.name
|
|
|
|
await nextTick()
|
|
|
|
editInputRefs.value[`editInputRef_${item.id}`].focus()
|
|
|
|
editInputRefs.value[`editInputRef_${item.id}`].select()
|
|
|
|
}
|
|
|
|
|
|
|
|
const findItem = (id: number) => dataList.value.find((v: any) => v.id === id)
|
|
|
|
|
|
|
|
async function onSaveFile(item: any) {
|
|
|
|
const isAdd = !item.id
|
|
|
|
loading.value = true
|
|
|
|
switch (item.type) {
|
|
|
|
case floeType.folder:
|
|
|
|
await saveFolder(isAdd, item)
|
|
|
|
break
|
|
|
|
case floeType.file:
|
|
|
|
await saveFile(isAdd, item)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
loadData(currentFolderId.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
function getPath() {
|
|
|
|
return currentFolderId.value === 0
|
|
|
|
? ''
|
|
|
|
: breadcrumbList.value[breadcrumbList.value.length - 1].path
|
|
|
|
}
|
|
|
|
|
|
|
|
async function saveFolder(isAdd: boolean, item: any) {
|
|
|
|
getPath()
|
|
|
|
let res
|
|
|
|
if (isAdd) {
|
|
|
|
res = await createFolder({
|
|
|
|
name: item.name,
|
|
|
|
parentId: currentFolderId.value,
|
|
|
|
path: getPath(),
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
res = await updateFolder({
|
|
|
|
id: item.id,
|
|
|
|
name: item.name,
|
|
|
|
parentId: currentFolderId.value,
|
|
|
|
path: getPath(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (isResError(res)) {
|
|
|
|
// 删除新增的文件夹
|
|
|
|
if (isAdd) {
|
|
|
|
dataList.value.pop()
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
async function saveFile(isAdd: boolean, item: any) {
|
|
|
|
let res
|
|
|
|
if (isAdd) {
|
|
|
|
res = await createdFile({
|
|
|
|
name: item.name,
|
|
|
|
parentId: currentFolderId.value,
|
|
|
|
isDraft: 1,
|
|
|
|
path: getPath(),
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
res = await updateFile({
|
|
|
|
id: item.id,
|
|
|
|
name: item.name,
|
|
|
|
parentId: currentFolderId.value,
|
|
|
|
path: getPath(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (isResError(res)) return ''
|
|
|
|
return res.data.id
|
|
|
|
}
|
|
|
|
|
|
|
|
const fullscreenLoading = ref()
|
|
|
|
|
|
|
|
function openFullScreen() {
|
|
|
|
fullscreenLoading.value = ElLoading.service({
|
|
|
|
lock: true,
|
|
|
|
text: '数据加载中请稍等...',
|
|
|
|
target: document.querySelector('.firmware-management-wrap') as HTMLElement,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
watch(loading, val => {
|
|
|
|
if (val) {
|
|
|
|
openFullScreen()
|
|
|
|
} else {
|
|
|
|
fullscreenLoading.value?.close()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// markdown 操作
|
|
|
|
const curMarkdown = ref() as Ref<ContentType & { fileName: string }>
|
|
|
|
const curMdId = ref()
|
|
|
|
|
|
|
|
const isShowMdDrawer = ref(false)
|
|
|
|
async function onOpenMarkdownDrawer(id: number) {
|
|
|
|
curMdId.value = id
|
|
|
|
const res = await getMarkdown({ folderId: id })
|
|
|
|
if (isResError(res)) return
|
|
|
|
curMarkdown.value = Object.assign({}, res.data, { fileName: findItem(id).name })
|
|
|
|
|
|
|
|
isShowMdDrawer.value = true
|
|
|
|
}
|
|
|
|
|
|
|
|
async function onSaveMd(isDraft: 0 | 1, data: string) {
|
|
|
|
const res = await updateMarkdown({
|
|
|
|
content: data,
|
|
|
|
folderId: curMdId.value,
|
|
|
|
isDraft,
|
|
|
|
})
|
|
|
|
|
|
|
|
if (isResError(res)) return
|
|
|
|
message.success(isDraft === 1 ? '保存成功' : '发布成功')
|
|
|
|
isShowMdDrawer.value = false
|
|
|
|
curMarkdown.value = null as any
|
|
|
|
loadData(currentFolderId.value)
|
|
|
|
}
|
|
|
|
onMounted(() => {
|
|
|
|
loadData()
|
|
|
|
})
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
|
.firmware-management-wrap {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
:deep(.el-breadcrumb) {
|
|
|
|
margin-left: 4px;
|
|
|
|
}
|
|
|
|
.active {
|
|
|
|
:deep(.el-breadcrumb__inner) {
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
font-weight: 800;
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.file-list {
|
|
|
|
user-select: none;
|
|
|
|
display: flex;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
gap: 20px;
|
|
|
|
.item {
|
|
|
|
width: 90px;
|
|
|
|
height: 110px;
|
|
|
|
display: flex;
|
|
|
|
cursor: pointer;
|
|
|
|
align-items: center;
|
|
|
|
flex-direction: column;
|
|
|
|
justify-content: center;
|
|
|
|
border-radius: 3px;
|
|
|
|
padding-bottom: 4px;
|
|
|
|
.file-header {
|
|
|
|
visibility: hidden;
|
|
|
|
width: 100%;
|
|
|
|
height: calc(100% - 66px - 24px);
|
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
|
|
|
padding: 0 8px;
|
|
|
|
box-sizing: border-box;
|
|
|
|
justify-content: space-between;
|
|
|
|
.icon {
|
|
|
|
flex-direction: end;
|
|
|
|
color: var(--icon-color);
|
|
|
|
:hover {
|
|
|
|
color: var(--icon-hover-color);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.file-icon {
|
|
|
|
width: 66px;
|
|
|
|
height: 66px;
|
|
|
|
img {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.file-name {
|
|
|
|
height: 24px;
|
|
|
|
line-height: 24px;
|
|
|
|
font-size: 14px;
|
|
|
|
color: var(--label-color);
|
|
|
|
overflow: hidden;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
white-space: nowrap;
|
|
|
|
width: 100%;
|
|
|
|
text-align: center;
|
|
|
|
.edit-input {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
margin-bottom: 4px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&:hover {
|
|
|
|
background-color: var(--mask-bg);
|
|
|
|
.file-header {
|
|
|
|
visibility: visible;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|