feat: folder
This commit is contained in:
parent
449aa63f85
commit
de22ffabc1
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
:title="$t('components.folder.addFolder')"
|
:title="title"
|
||||||
v-model="dialogVisible"
|
v-model="dialogVisible"
|
||||||
width="720"
|
width="720"
|
||||||
append-to-body
|
append-to-body
|
||||||
@ -54,11 +54,19 @@ import { MsgSuccess, MsgAlert } from '@/utils/message'
|
|||||||
import { t } from '@/locales'
|
import { t } from '@/locales'
|
||||||
const emit = defineEmits(['refresh'])
|
const emit = defineEmits(['refresh'])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: t('components.folder.addFolder'),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
const FolderFormRef = ref()
|
const FolderFormRef = ref()
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const dialogVisible = ref<boolean>(false)
|
const dialogVisible = ref<boolean>(false)
|
||||||
const sourceType = ref<any>('')
|
const sourceType = ref<any>('')
|
||||||
|
const isEdit = ref<boolean>(false)
|
||||||
|
|
||||||
const folderForm = ref<any>({
|
const folderForm = ref<any>({
|
||||||
name: '',
|
name: '',
|
||||||
@ -84,24 +92,38 @@ watch(dialogVisible, (bool) => {
|
|||||||
desc: '',
|
desc: '',
|
||||||
parent_id: '',
|
parent_id: '',
|
||||||
}
|
}
|
||||||
|
isEdit.value = false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const open = (source: string, id: string) => {
|
const open = (source: string, id: string, data?: any) => {
|
||||||
sourceType.value = source
|
sourceType.value = source
|
||||||
folderForm.value.parent_id = id
|
folderForm.value.parent_id = id
|
||||||
|
if (data) {
|
||||||
|
folderForm.value.name = data.name
|
||||||
|
folderForm.value.desc = data.desc
|
||||||
|
isEdit.value = true
|
||||||
|
}
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
const submitHandle = async () => {
|
const submitHandle = async () => {
|
||||||
await FolderFormRef.value.validate((valid: any) => {
|
await FolderFormRef.value.validate((valid: any) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
if (isEdit.value) {
|
||||||
|
folderApi.putFolder(sourceType.value, folderForm.value, loading).then((res) => {
|
||||||
|
MsgSuccess(t('common.editSuccess'))
|
||||||
|
emit('refresh')
|
||||||
|
dialogVisible.value = false
|
||||||
|
})
|
||||||
|
} else {
|
||||||
folderApi.postFolder(sourceType.value, folderForm.value, loading).then((res) => {
|
folderApi.postFolder(sourceType.value, folderForm.value, loading).then((res) => {
|
||||||
MsgSuccess(t('common.createSuccess'))
|
MsgSuccess(t('common.createSuccess'))
|
||||||
emit('refresh')
|
emit('refresh')
|
||||||
dialogVisible.value = false
|
dialogVisible.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="folder-tree">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="filterText"
|
v-model="filterText"
|
||||||
:placeholder="$t('common.search')"
|
:placeholder="$t('common.search')"
|
||||||
@ -28,19 +28,54 @@
|
|||||||
node-key="id"
|
node-key="id"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<div class="custom-tree-node flex align-center">
|
<div class="flex-between w-full" @mouseenter.stop="handleMouseEnter(data)">
|
||||||
|
<div class="flex align-center">
|
||||||
<AppIcon iconName="app-folder" style="font-size: 16px"></AppIcon>
|
<AppIcon iconName="app-folder" style="font-size: 16px"></AppIcon>
|
||||||
<span class="ml-8">{{ node.label }}</span>
|
<span class="ml-8">{{ node.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
@click.stop
|
||||||
|
v-show="hoverNodeId === data.id"
|
||||||
|
@mouseenter.stop="handleMouseEnter(data)"
|
||||||
|
@mouseleave.stop="handleMouseleave"
|
||||||
|
class="mr-16"
|
||||||
|
>
|
||||||
|
<el-dropdown trigger="click" :teleported="false">
|
||||||
|
<el-button text class="w-full">
|
||||||
|
<el-icon class="rotate-90"><MoreFilled /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click.stop="openCreateFolder(data)">
|
||||||
|
<el-icon><EditPen /></el-icon>
|
||||||
|
{{ '添加子文件夹' }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click.stop="openEditFolder(data)">
|
||||||
|
<el-icon><EditPen /></el-icon>
|
||||||
|
{{ $t('common.edit') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item divided @click.stop="deleteFolder(data)">
|
||||||
|
<el-icon><Delete /></el-icon>
|
||||||
|
{{ $t('common.delete') }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
|
<CreateFolderDialog ref="CreateFolderDialogRef" @refresh="refreshFolder" :title="title" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import type { TreeInstance } from 'element-plus'
|
import type { TreeInstance } from 'element-plus'
|
||||||
|
import CreateFolderDialog from '@/components/folder-tree/CreateFolderDialog.vue'
|
||||||
import { t } from '@/locales'
|
import { t } from '@/locales'
|
||||||
|
import folderApi from '@/api/folder'
|
||||||
defineOptions({ name: 'FolderTree' })
|
defineOptions({ name: 'FolderTree' })
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
@ -51,6 +86,10 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: 'root',
|
default: 'root',
|
||||||
},
|
},
|
||||||
|
source: {
|
||||||
|
type: String,
|
||||||
|
default: 'APPLICATION',
|
||||||
|
},
|
||||||
isShared: {
|
isShared: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@ -68,6 +107,7 @@ interface Tree {
|
|||||||
name: string
|
name: string
|
||||||
children?: Tree[]
|
children?: Tree[]
|
||||||
id?: string
|
id?: string
|
||||||
|
show?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
@ -75,15 +115,23 @@ const defaultProps = {
|
|||||||
label: 'name',
|
label: 'name',
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['handleNodeClick'])
|
const emit = defineEmits(['handleNodeClick', 'refreshTree'])
|
||||||
|
|
||||||
const treeRef = ref<TreeInstance>()
|
const treeRef = ref<TreeInstance>()
|
||||||
const filterText = ref('')
|
const filterText = ref('')
|
||||||
|
const hoverNodeId = ref<string | undefined>('')
|
||||||
|
const title = ref('')
|
||||||
|
|
||||||
watch(filterText, (val) => {
|
watch(filterText, (val) => {
|
||||||
treeRef.value!.filter(val)
|
treeRef.value!.filter(val)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function handleMouseEnter(data: Tree) {
|
||||||
|
hoverNodeId.value = data.id
|
||||||
|
}
|
||||||
|
function handleMouseleave() {
|
||||||
|
hoverNodeId.value = ''
|
||||||
|
}
|
||||||
const filterNode = (value: string, data: Tree) => {
|
const filterNode = (value: string, data: Tree) => {
|
||||||
if (!value) return true
|
if (!value) return true
|
||||||
return data.name.includes(value)
|
return data.name.includes(value)
|
||||||
@ -97,6 +145,26 @@ const handleSharedNodeClick = () => {
|
|||||||
treeRef.value?.setCurrentKey(undefined)
|
treeRef.value?.setCurrentKey(undefined)
|
||||||
emit('handleNodeClick', { id: 'share', name: t(props.shareTitle) })
|
emit('handleNodeClick', { id: 'share', name: t(props.shareTitle) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deleteFolder(row: Tree) {
|
||||||
|
folderApi.delFolder(row.id as string, props.source).then(() => {
|
||||||
|
emit('refreshTree')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const CreateFolderDialogRef = ref()
|
||||||
|
function openCreateFolder(row: Tree) {
|
||||||
|
title.value = '添加子文件夹'
|
||||||
|
CreateFolderDialogRef.value.open(props.source, row.id)
|
||||||
|
}
|
||||||
|
function openEditFolder(row: Tree) {
|
||||||
|
title.value = '编辑文件夹'
|
||||||
|
CreateFolderDialogRef.value.open(props.source, row.id, row)
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshFolder() {
|
||||||
|
emit('refreshTree')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.shared-knowledge {
|
.shared-knowledge {
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
export enum DeviceType {
|
export enum DeviceType {
|
||||||
Mobile = 'Mobile',
|
Mobile = 'Mobile',
|
||||||
Desktop = 'Desktop'
|
Desktop = 'Desktop',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ValidType {
|
export enum ValidType {
|
||||||
Application = 'application',
|
Application = 'application',
|
||||||
Knowledge = 'knowledge',
|
Knowledge = 'knowledge',
|
||||||
User = 'user'
|
User = 'user',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum ValidCount {
|
export enum ValidCount {
|
||||||
Application = 5,
|
Application = 5,
|
||||||
Knowledge = 50,
|
Knowledge = 50,
|
||||||
User = 2
|
User = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum FolderSource {
|
||||||
|
KNOWLEDGE = 'KNOWLEDGE',
|
||||||
|
APPLICATION = 'APPLICATION',
|
||||||
|
TOOL = 'TOOL',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,9 +52,9 @@
|
|||||||
>
|
>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<div class="flex-between">
|
<div class="flex-between">
|
||||||
<auto-tooltip :content="row.abstract">
|
<span :title="row.abstract">
|
||||||
{{ row.abstract }}
|
{{ row.abstract }}
|
||||||
</auto-tooltip>
|
</span>
|
||||||
<div @click.stop v-show="mouseId === row.id && row.id !== 'new'">
|
<div @click.stop v-show="mouseId === row.id && row.id !== 'new'">
|
||||||
<el-dropdown trigger="click" :teleported="false">
|
<el-dropdown trigger="click" :teleported="false">
|
||||||
<el-icon class="rotate-90 mt-4"><MoreFilled /></el-icon>
|
<el-icon class="rotate-90 mt-4"><MoreFilled /></el-icon>
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
ref="treeRef"
|
ref="treeRef"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<div class="custom-tree-node flex align-center lighter">
|
<div class="flex align-center lighter">
|
||||||
<img
|
<img
|
||||||
src="@/assets/fileType/file-icon.svg"
|
src="@/assets/fileType/file-icon.svg"
|
||||||
alt=""
|
alt=""
|
||||||
|
|||||||
@ -3,11 +3,13 @@
|
|||||||
<template #left>
|
<template #left>
|
||||||
<h4 class="p-16 pb-0">{{ $t('views.knowledge.title') }}</h4>
|
<h4 class="p-16 pb-0">{{ $t('views.knowledge.title') }}</h4>
|
||||||
<folder-tree
|
<folder-tree
|
||||||
|
:source="FolderSource.KNOWLEDGE"
|
||||||
:data="folderList"
|
:data="folderList"
|
||||||
:currentNodeKey="currentFolder?.id"
|
:currentNodeKey="currentFolder?.id"
|
||||||
@handleNodeClick="folderClickHandel"
|
@handleNodeClick="folderClickHandel"
|
||||||
class="p-8"
|
class="p-8"
|
||||||
isShared
|
isShared
|
||||||
|
@refreshTree="refreshFolder"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<SharedWorkspace v-if="currentFolder.id === 'share'"></SharedWorkspace>
|
<SharedWorkspace v-if="currentFolder.id === 'share'"></SharedWorkspace>
|
||||||
@ -44,8 +46,13 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<el-button type="primary" class="ml-8"
|
<el-button
|
||||||
v-hasPermission="[RoleConst.ADMIN.getWorkspaceRole,PermissionConst.KNOWLEDGE_CREATE.getWorkspacePermission]"
|
type="primary"
|
||||||
|
class="ml-8"
|
||||||
|
v-hasPermission="[
|
||||||
|
RoleConst.ADMIN.getWorkspaceRole,
|
||||||
|
PermissionConst.KNOWLEDGE_CREATE.getWorkspacePermission,
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
{{ $t('common.create') }}
|
{{ $t('common.create') }}
|
||||||
<el-icon class="el-icon--right">
|
<el-icon class="el-icon--right">
|
||||||
@ -217,8 +224,13 @@
|
|||||||
<template #mouseEnter>
|
<template #mouseEnter>
|
||||||
<div @click.stop>
|
<div @click.stop>
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<el-button text @click.stop
|
<el-button
|
||||||
v-hasPermission="[RoleConst.ADMIN.getWorkspaceRole,PermissionConst.KNOWLEDGE_EDIT.getWorkspacePermission]"
|
text
|
||||||
|
@click.stop
|
||||||
|
v-hasPermission="[
|
||||||
|
RoleConst.ADMIN.getWorkspaceRole,
|
||||||
|
PermissionConst.KNOWLEDGE_EDIT.getWorkspacePermission,
|
||||||
|
]"
|
||||||
>
|
>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<MoreFilled />
|
<MoreFilled />
|
||||||
@ -297,6 +309,7 @@ import useStore from '@/stores'
|
|||||||
import { numberFormat } from '@/utils/common'
|
import { numberFormat } from '@/utils/common'
|
||||||
import { t } from '@/locales'
|
import { t } from '@/locales'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
import { FolderSource } from '@/enums/common'
|
||||||
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
||||||
import { hasPermission } from '@/utils/permission/index'
|
import { hasPermission } from '@/utils/permission/index'
|
||||||
|
|
||||||
@ -378,7 +391,7 @@ function getList() {
|
|||||||
|
|
||||||
function getFolder() {
|
function getFolder() {
|
||||||
const params = {}
|
const params = {}
|
||||||
folder.asyncGetFolder('KNOWLEDGE', params, loading).then((res: any) => {
|
folder.asyncGetFolder(FolderSource.KNOWLEDGE, params, loading).then((res: any) => {
|
||||||
folderList.value = res.data
|
folderList.value = res.data
|
||||||
currentFolder.value = res.data?.[0] || {}
|
currentFolder.value = res.data?.[0] || {}
|
||||||
getList()
|
getList()
|
||||||
@ -401,7 +414,7 @@ function clickFolder(item: any) {
|
|||||||
const CreateFolderDialogRef = ref()
|
const CreateFolderDialogRef = ref()
|
||||||
|
|
||||||
function openCreateFolder() {
|
function openCreateFolder() {
|
||||||
CreateFolderDialogRef.value.open('KNOWLEDGE', currentFolder.value.parent_id)
|
CreateFolderDialogRef.value.open(FolderSource.KNOWLEDGE, currentFolder.value.parent_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const GenerateRelatedDialogRef = ref<InstanceType<typeof GenerateRelatedDialog>>()
|
const GenerateRelatedDialogRef = ref<InstanceType<typeof GenerateRelatedDialog>>()
|
||||||
|
|||||||
@ -169,7 +169,7 @@ const searchType = ref('title')
|
|||||||
|
|
||||||
const handleClick = (e: MouseEvent, ele: any) => {
|
const handleClick = (e: MouseEvent, ele: any) => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
document.querySelector(`${ele}`).scrollIntoView({ behavior: 'smooth', block: 'start' })
|
document.querySelector(`${ele}`)?.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量操作
|
// 批量操作
|
||||||
|
|||||||
@ -52,7 +52,7 @@
|
|||||||
ref="treeRef"
|
ref="treeRef"
|
||||||
>
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<div class="custom-tree-node flex align-center lighter">
|
<div class="flex align-center lighter">
|
||||||
<img
|
<img
|
||||||
src="@/assets/fileType/file-icon.svg"
|
src="@/assets/fileType/file-icon.svg"
|
||||||
alt=""
|
alt=""
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user