30 changed files with 1189 additions and 322 deletions
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 269 KiB |
@ -1,3 +1,4 @@ |
|||||
export enum DictEnum { |
export enum DictEnum { |
||||
QUESTION_TYPE = '问题属性', |
QUESTION_TYPE = '问题属性', |
||||
|
TAG_TYPE = '标签', |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,333 @@ |
|||||
|
<template> |
||||
|
<div class="entrance-container"> |
||||
|
<!-- 顶部导航 --> |
||||
|
<div class="header"> |
||||
|
<div class="logo"> |
||||
|
<!-- <img src="http://193.112.23.48:88/techscan/assets/onepage/img/logo/techscanlogo.png" /> --> |
||||
|
<span>太迅条码帮助中心</span> |
||||
|
</div> |
||||
|
<div class="nav-links"> |
||||
|
<a-space> |
||||
|
<a href="#" class="nav-item">返回官网</a> |
||||
|
<!-- <a href="#" class="nav-item">问题社区</a> --> |
||||
|
<!-- <a href="#" class="nav-item">更新日志</a> --> |
||||
|
<a-button type="text" class="favorite"> |
||||
|
<star-outlined /> |
||||
|
</a-button> |
||||
|
</a-space> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 主要内容区 --> |
||||
|
<div class="main-content"> |
||||
|
<!-- 快捷入口卡片 --> |
||||
|
<div class="quick-access" v-if="false"> |
||||
|
<a-row :gutter="16"> |
||||
|
<a-col :span="8"> |
||||
|
<a-card class="access-card"> |
||||
|
<template #cover> |
||||
|
<user-outlined class="card-icon" /> |
||||
|
</template> |
||||
|
<a-card-meta title="加入社区" description="发布问题和分享经验,参与讨论" /> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
<a-col :span="8"> |
||||
|
<a-card class="access-card"> |
||||
|
<template #cover> |
||||
|
<clock-circle-outlined class="card-icon" /> |
||||
|
</template> |
||||
|
<a-card-meta title="疑点帮助" description="获得即时工作答复和问题解答" /> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
<a-col :span="8"> |
||||
|
<a-card class="access-card"> |
||||
|
<template #cover> |
||||
|
<mail-outlined class="card-icon" /> |
||||
|
</template> |
||||
|
<a-card-meta title="发送邮件" description="to: support@baklib.jp" /> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 搜索框 --> |
||||
|
<div class="search-section"> |
||||
|
<h1>👋 嗨,有什么可以帮你?</h1> |
||||
|
<div class="search-wrapper"> |
||||
|
<a-input-search |
||||
|
v-model:value="searchText" |
||||
|
placeholder="在这里搜索" |
||||
|
size="large" |
||||
|
@search="onSearch" |
||||
|
class="rounded-search" |
||||
|
/> |
||||
|
</div> |
||||
|
<div class="search-tags"> |
||||
|
<a-tag v-for="tag in searchTags" :key="tag">{{ tag }}</a-tag> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 新手入门区域 --> |
||||
|
<div class="getting-started"> |
||||
|
<a-row :gutter="[24, 24]"> |
||||
|
<a-col :span="12" v-for="item in startItems" :key="item.title"> |
||||
|
<div class="start-card"> |
||||
|
<div class="card-content"> |
||||
|
<div class="icon-wrapper"> |
||||
|
<component :is="item.icon" class="card-icon" /> |
||||
|
</div> |
||||
|
<div class="text-content"> |
||||
|
<h3>{{ item.title }}</h3> |
||||
|
<p>{{ item.description }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="card-action"> |
||||
|
<a-button type="link" @click="goTo(item.route)">立即进入 →</a-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { |
||||
|
StarOutlined, |
||||
|
UserOutlined, |
||||
|
ClockCircleOutlined, |
||||
|
MailOutlined, |
||||
|
FormOutlined, |
||||
|
BookOutlined, |
||||
|
} from '@ant-design/icons-vue'; |
||||
|
import { useRouter } from 'vue-router'; |
||||
|
|
||||
|
const router = useRouter(); |
||||
|
|
||||
|
const searchText = ref(''); |
||||
|
const searchTags = ref(['快捷指南', 'KB快捷键', 'DAM', 'CMS', 'Wiki', 'Community']); |
||||
|
|
||||
|
const startItems = ref([ |
||||
|
{ |
||||
|
title: '问题工单', |
||||
|
description: '提交问题和请求,跟踪进度', |
||||
|
icon: FormOutlined, |
||||
|
route: '/issue', |
||||
|
}, |
||||
|
{ |
||||
|
title: '知识库', |
||||
|
description: '整理组织知识,构建统一内容中心,服务团队', |
||||
|
icon: BookOutlined, |
||||
|
route: '/knowledge', |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
const goTo = (route: string) => { |
||||
|
console.log(`前往 ${route}`); |
||||
|
router.push(route); |
||||
|
}; |
||||
|
|
||||
|
const onSearch = (value: string) => { |
||||
|
console.log('搜索:', value); |
||||
|
}; |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.entrance-container { |
||||
|
min-height: 100vh; |
||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); |
||||
|
|
||||
|
.header { |
||||
|
padding: 16px 24px; |
||||
|
display: flex; |
||||
|
justify-content: space-between; |
||||
|
align-items: center; |
||||
|
background: rgba(255, 255, 255, 0.9); |
||||
|
backdrop-filter: blur(10px); |
||||
|
|
||||
|
.logo { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
gap: 8px; |
||||
|
|
||||
|
img { |
||||
|
height: 32px; |
||||
|
} |
||||
|
|
||||
|
span { |
||||
|
font-size: 18px; |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.nav-links { |
||||
|
.nav-item { |
||||
|
color: rgba(0, 0, 0, 0.85); |
||||
|
padding: 0 16px; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.main-content { |
||||
|
max-width: 1200px; |
||||
|
margin: 0 auto; |
||||
|
padding: 40px 24px; |
||||
|
|
||||
|
.quick-access { |
||||
|
margin-bottom: 48px; |
||||
|
|
||||
|
.access-card { |
||||
|
text-align: center; |
||||
|
border-radius: 12px; |
||||
|
overflow: hidden; |
||||
|
transition: all 0.3s; |
||||
|
|
||||
|
&:hover { |
||||
|
transform: translateY(-5px); |
||||
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
.card-icon { |
||||
|
font-size: 36px; |
||||
|
padding: 24px 0; |
||||
|
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); |
||||
|
color: white; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.search-section { |
||||
|
text-align: center; |
||||
|
margin-bottom: 48px; |
||||
|
|
||||
|
h1 { |
||||
|
font-size: 32px; |
||||
|
margin-bottom: 24px; |
||||
|
} |
||||
|
|
||||
|
.ant-input-search { |
||||
|
max-width: 600px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
|
||||
|
.search-tags { |
||||
|
margin-top: 16px; |
||||
|
|
||||
|
.ant-tag { |
||||
|
margin: 4px; |
||||
|
cursor: pointer; |
||||
|
|
||||
|
&:hover { |
||||
|
color: #1890ff; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.getting-started { |
||||
|
.start-card { |
||||
|
background: white; |
||||
|
padding: 24px; |
||||
|
border-radius: 16px; |
||||
|
transition: all 0.3s ease; |
||||
|
border: 1px solid rgba(0, 0, 0, 0.06); |
||||
|
height: 100%; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
justify-content: space-between; |
||||
|
|
||||
|
&:hover { |
||||
|
transform: translateY(-5px); |
||||
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.08); |
||||
|
border-color: transparent; |
||||
|
} |
||||
|
|
||||
|
.card-content { |
||||
|
display: flex; |
||||
|
align-items: flex-start; |
||||
|
gap: 20px; |
||||
|
} |
||||
|
|
||||
|
.icon-wrapper { |
||||
|
width: 48px; |
||||
|
height: 48px; |
||||
|
border-radius: 12px; |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); |
||||
|
|
||||
|
.card-icon { |
||||
|
font-size: 24px; |
||||
|
color: white; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.text-content { |
||||
|
flex: 1; |
||||
|
|
||||
|
h3 { |
||||
|
font-size: 20px; |
||||
|
margin-bottom: 8px; |
||||
|
color: #1f1f1f; |
||||
|
font-weight: 600; |
||||
|
} |
||||
|
|
||||
|
p { |
||||
|
color: rgba(0, 0, 0, 0.65); |
||||
|
margin: 0; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.card-action { |
||||
|
margin-top: 20px; |
||||
|
text-align: right; |
||||
|
|
||||
|
.ant-btn { |
||||
|
padding: 0; |
||||
|
font-size: 16px; |
||||
|
|
||||
|
&:hover { |
||||
|
transform: translateX(5px); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.search-wrapper { |
||||
|
max-width: 600px; |
||||
|
margin: 0 auto; |
||||
|
|
||||
|
.rounded-search { |
||||
|
:deep(.ant-input) { |
||||
|
border-radius: 24px 0 0 24px; |
||||
|
height: 48px; |
||||
|
padding-left: 24px; |
||||
|
border: 1px solid #d9d9d9; |
||||
|
|
||||
|
&:focus, &:hover { |
||||
|
border-color: #1890ff; |
||||
|
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:deep(.ant-input-group-addon) { |
||||
|
background:none; |
||||
|
.ant-btn { |
||||
|
border-radius: 0 24px 24px 0; |
||||
|
height: 48px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,249 @@ |
|||||
|
<template> |
||||
|
<div class="knowledge-base"> |
||||
|
<a-row :gutter="16"> |
||||
|
<!-- 左侧目录树 --> |
||||
|
<a-col :span="6"> |
||||
|
<a-card class="tree-card"> |
||||
|
<template #title> |
||||
|
<span class="card-title"> <folder-outlined /> 问题工单目录 </span> |
||||
|
</template> |
||||
|
<a-tree |
||||
|
v-model:selectedKeys="selectedKeys" |
||||
|
v-model:expandedKeys="expandedKeys" |
||||
|
:tree-data="treeData" |
||||
|
:defaultExpandAll="expandAll" |
||||
|
@select="onSelect" |
||||
|
> |
||||
|
<template #switcherIcon="{ switcherCls }" |
||||
|
><down-outlined :class="switcherCls" |
||||
|
/></template> |
||||
|
</a-tree> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
|
||||
|
<!-- 右侧内容区 --> |
||||
|
<a-col :span="18"> |
||||
|
<a-card class="content-card"> |
||||
|
<template #title> |
||||
|
<div class="flex justify-between items-start"> |
||||
|
<span class="card-title"> <book-outlined /> 问题工单内容 </span> |
||||
|
<!-- 快捷操作区域 --> |
||||
|
<a-space> |
||||
|
<a-button |
||||
|
type="primary" |
||||
|
v-for="action in quickActions" |
||||
|
:key="action.title" |
||||
|
@click="action.onClick" |
||||
|
> |
||||
|
<template #icon><component :is="action.icon" /></template> |
||||
|
{{ action.title }} |
||||
|
</a-button> |
||||
|
</a-space> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<!-- 内容展示区域 --> |
||||
|
<div class="content-area"> |
||||
|
<template v-if="selectedKeys.length"> |
||||
|
<!-- 这里可以根据选中的目录显示具体内容 --> |
||||
|
<Detail :id="curRow.id" /> |
||||
|
</template> |
||||
|
<template v-else> |
||||
|
<a-empty description="请选择左侧目录" /> |
||||
|
</template> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { |
||||
|
FolderOutlined, |
||||
|
BookOutlined, |
||||
|
FileTextOutlined, |
||||
|
TeamOutlined, |
||||
|
SettingOutlined, |
||||
|
PlusOutlined, |
||||
|
EditOutlined, |
||||
|
DeleteOutlined, |
||||
|
ExportOutlined, |
||||
|
DownOutlined, |
||||
|
} from '@ant-design/icons-vue'; |
||||
|
import { fetchProdList, fetchVersionPageList } from '@/api/prodVersion'; |
||||
|
import { fetchIssuePageList } from '@/api/issue'; |
||||
|
import Detail from '@/views/question/issue/detail.vue'; |
||||
|
// 目录树数据 |
||||
|
const treeData = ref<any[]>([]); |
||||
|
const expandAll = ref(false); |
||||
|
|
||||
|
// 树选择状态 |
||||
|
const selectedKeys = ref<string[]>([]); |
||||
|
const expandedKeys = ref<string[]>(['1', '2']); |
||||
|
|
||||
|
const curRow = ref<any>({}); |
||||
|
|
||||
|
// 功能卡片数据 |
||||
|
const featureCards = ref([ |
||||
|
{ |
||||
|
title: '文档管理', |
||||
|
description: '集中管理所有知识文档', |
||||
|
icon: FileTextOutlined, |
||||
|
color: '#1890ff', |
||||
|
}, |
||||
|
{ |
||||
|
title: '团队协作', |
||||
|
description: '支持多人协同编辑', |
||||
|
icon: TeamOutlined, |
||||
|
color: '#52c41a', |
||||
|
}, |
||||
|
{ |
||||
|
title: '系统设置', |
||||
|
description: '自定义问题工单配置', |
||||
|
icon: SettingOutlined, |
||||
|
color: '#722ed1', |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// 快捷操作按钮 |
||||
|
const quickActions = ref([ |
||||
|
{ |
||||
|
title: '新建文档', |
||||
|
icon: PlusOutlined, |
||||
|
onClick: () => console.log('新建文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '编辑文档', |
||||
|
icon: EditOutlined, |
||||
|
onClick: () => console.log('编辑文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '删除文档', |
||||
|
icon: DeleteOutlined, |
||||
|
onClick: () => console.log('删除文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '导出文档', |
||||
|
icon: ExportOutlined, |
||||
|
onClick: () => console.log('导出文档'), |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// 树节点选择事件 |
||||
|
const onSelect = async (selectedKeys: string[], info: any) => { |
||||
|
console.log('selected', selectedKeys, info); |
||||
|
const { |
||||
|
node: { isLeaf }, |
||||
|
} = info; |
||||
|
|
||||
|
// 判断是否是叶子节点 |
||||
|
if (isLeaf) { |
||||
|
// 这里可以根据选中的目录显示具体内容 |
||||
|
console.log('选中叶子节点:', selectedKeys[0]); |
||||
|
curRow.value = { |
||||
|
id: selectedKeys[0], |
||||
|
}; |
||||
|
} else { |
||||
|
console.log('选中非叶子节点:', selectedKeys[0]); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const initTreeData = async () => { |
||||
|
let tree: any[] = []; |
||||
|
// 获取产品列表 |
||||
|
const res = await fetchProdList({}); |
||||
|
console.log('res: ', res); |
||||
|
if (res && Array.isArray(res) && res.length) { |
||||
|
tree = res.map((e) => { |
||||
|
return { |
||||
|
title: e.name, |
||||
|
key: e.id, |
||||
|
isLeaf: false, |
||||
|
children: [], |
||||
|
}; |
||||
|
}); |
||||
|
for (let i = 0; i < tree.length; i++) { |
||||
|
let item = tree[i]; |
||||
|
// 循环获取产品下的版本 |
||||
|
const { data } = await fetchVersionPageList({ |
||||
|
productId: item.key, |
||||
|
current: 1, |
||||
|
size: 999, |
||||
|
}); |
||||
|
item.children = (data as any).map((e) => { |
||||
|
return { |
||||
|
title: e.name, |
||||
|
key: e.uid, |
||||
|
id: e.id, |
||||
|
isLeaf: false, |
||||
|
children: [], |
||||
|
}; |
||||
|
}); |
||||
|
// 循环版本获取关联的工单 |
||||
|
for (let j = 0; j < item.children.length; j++) { |
||||
|
let childItem = item.children[j]; |
||||
|
const { |
||||
|
data: { records }, |
||||
|
} = await fetchIssuePageList({ |
||||
|
versionId: childItem.id, |
||||
|
current: 1, |
||||
|
size: 999, |
||||
|
}); |
||||
|
console.log('res: ', res); |
||||
|
|
||||
|
childItem.children = (records as any).map((e) => { |
||||
|
return { |
||||
|
title: e.title, |
||||
|
key: e.id, |
||||
|
id: e.id, |
||||
|
isLeaf: true, |
||||
|
}; |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
treeData.value = tree; |
||||
|
expandAll.value = true; |
||||
|
console.log('treeData.value: ', treeData.value); |
||||
|
}; |
||||
|
initTreeData(); |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less"> |
||||
|
.ql-editor { |
||||
|
height: 400px !important; |
||||
|
} |
||||
|
.knowledge-base { |
||||
|
padding: 24px; |
||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7eb 100%); |
||||
|
min-height: 100vh; |
||||
|
|
||||
|
.tree-card, |
||||
|
.content-card { |
||||
|
min-height: calc(100vh - 50px); |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
||||
|
|
||||
|
.quick-actions { |
||||
|
margin-bottom: 16px; |
||||
|
padding: 16px 0; |
||||
|
border-bottom: 1px solid #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.content-area { |
||||
|
min-height: 300px; |
||||
|
max-height: calc(100vh - 164px); |
||||
|
overflow: scroll; |
||||
|
|
||||
|
.selected-content { |
||||
|
padding: 16px; |
||||
|
background: #fafafa; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -0,0 +1,165 @@ |
|||||
|
<template> |
||||
|
<div class="knowledge-base"> |
||||
|
<a-row :gutter="16"> |
||||
|
<!-- 左侧目录树 --> |
||||
|
<a-col :span="6"> |
||||
|
<a-card class="tree-card"> |
||||
|
<template #title> |
||||
|
<span class="card-title"> <folder-outlined /> 知识库目录 </span> |
||||
|
</template> |
||||
|
<a-tree |
||||
|
v-model:selectedKeys="selectedKeys" |
||||
|
v-model:expandedKeys="expandedKeys" |
||||
|
:tree-data="treeData" |
||||
|
@select="onSelect" |
||||
|
/> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
|
||||
|
<!-- 右侧内容区 --> |
||||
|
<a-col :span="18"> |
||||
|
<a-card class="content-card"> |
||||
|
<template #title> |
||||
|
<span class="card-title"> <book-outlined /> 知识库内容 </span> |
||||
|
</template> |
||||
|
|
||||
|
<!-- 内容展示区域 --> |
||||
|
<div class="content-area"> |
||||
|
<template v-if="selectedKeys.length"> |
||||
|
<!-- 这里可以根据选中的目录显示具体内容 --> |
||||
|
<div class="selected-content"> 已选择: {{ selectedKeys[0] }} </div> |
||||
|
</template> |
||||
|
<template v-else> |
||||
|
<a-empty description="请选择左侧目录" /> |
||||
|
</template> |
||||
|
</div> |
||||
|
</a-card> |
||||
|
</a-col> |
||||
|
</a-row> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup lang="ts"> |
||||
|
import { ref } from 'vue'; |
||||
|
import { |
||||
|
FolderOutlined, |
||||
|
BookOutlined, |
||||
|
FileTextOutlined, |
||||
|
TeamOutlined, |
||||
|
SettingOutlined, |
||||
|
PlusOutlined, |
||||
|
EditOutlined, |
||||
|
DeleteOutlined, |
||||
|
ExportOutlined, |
||||
|
} from '@ant-design/icons-vue'; |
||||
|
import { DictEnum } from '@/enums/dictEnum'; |
||||
|
import { getDictionaryByTypeName } from '@/utils/dict'; |
||||
|
|
||||
|
// 目录树数据 |
||||
|
const treeData = ref([ |
||||
|
{ |
||||
|
title: '知识库', |
||||
|
key: '1', |
||||
|
children: [], |
||||
|
}, |
||||
|
{ |
||||
|
title: '问题工单', |
||||
|
key: '2', |
||||
|
children: [], |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// 树选择状态 |
||||
|
const selectedKeys = ref<string[]>([]); |
||||
|
const expandedKeys = ref<string[]>(['1', '2']); |
||||
|
|
||||
|
// 功能卡片数据 |
||||
|
const featureCards = ref([ |
||||
|
{ |
||||
|
title: '文档管理', |
||||
|
description: '集中管理所有知识文档', |
||||
|
icon: FileTextOutlined, |
||||
|
color: '#1890ff', |
||||
|
}, |
||||
|
{ |
||||
|
title: '团队协作', |
||||
|
description: '支持多人协同编辑', |
||||
|
icon: TeamOutlined, |
||||
|
color: '#52c41a', |
||||
|
}, |
||||
|
{ |
||||
|
title: '系统设置', |
||||
|
description: '自定义知识库配置', |
||||
|
icon: SettingOutlined, |
||||
|
color: '#722ed1', |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// 快捷操作按钮 |
||||
|
const quickActions = ref([ |
||||
|
{ |
||||
|
title: '新建文档', |
||||
|
icon: PlusOutlined, |
||||
|
onClick: () => console.log('新建文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '编辑文档', |
||||
|
icon: EditOutlined, |
||||
|
onClick: () => console.log('编辑文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '删除文档', |
||||
|
icon: DeleteOutlined, |
||||
|
onClick: () => console.log('删除文档'), |
||||
|
}, |
||||
|
{ |
||||
|
title: '导出文档', |
||||
|
icon: ExportOutlined, |
||||
|
onClick: () => console.log('导出文档'), |
||||
|
}, |
||||
|
]); |
||||
|
|
||||
|
// 树节点选择事件 |
||||
|
const onSelect = (selectedKeys: string[], info: any) => { |
||||
|
console.log('selected', selectedKeys, info); |
||||
|
}; |
||||
|
|
||||
|
const initTreeData = async () => { |
||||
|
const res = await getDictionaryByTypeName(DictEnum.TAG_TYPE); |
||||
|
console.log('res: ', res); |
||||
|
}; |
||||
|
initTreeData(); |
||||
|
</script> |
||||
|
|
||||
|
<style lang="less" scoped> |
||||
|
.knowledge-base { |
||||
|
padding: 24px; |
||||
|
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7eb 100%); |
||||
|
min-height: 100vh; |
||||
|
|
||||
|
.tree-card, |
||||
|
.content-card { |
||||
|
min-height: calc(100vh - 50px); |
||||
|
background: #fff; |
||||
|
border-radius: 8px; |
||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
||||
|
|
||||
|
.quick-actions { |
||||
|
margin-bottom: 16px; |
||||
|
padding: 16px 0; |
||||
|
border-bottom: 1px solid #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.content-area { |
||||
|
padding: 16px 0; |
||||
|
min-height: 300px; |
||||
|
|
||||
|
.selected-content { |
||||
|
padding: 16px; |
||||
|
background: #fafafa; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
@ -1,179 +0,0 @@ |
|||||
<template> |
|
||||
<div class="knowledge-base"> |
|
||||
<a-row :gutter="16"> |
|
||||
<!-- 左侧目录树 --> |
|
||||
<a-col :span="6"> |
|
||||
<a-card class="tree-card"> |
|
||||
<template #title> |
|
||||
<span class="card-title"> |
|
||||
<folder-outlined /> 知识库目录 |
|
||||
</span> |
|
||||
</template> |
|
||||
<a-tree |
|
||||
v-model:selectedKeys="selectedKeys" |
|
||||
v-model:expandedKeys="expandedKeys" |
|
||||
:tree-data="treeData" |
|
||||
@select="onSelect" |
|
||||
/> |
|
||||
</a-card> |
|
||||
</a-col> |
|
||||
|
|
||||
<!-- 右侧内容区 --> |
|
||||
<a-col :span="18"> |
|
||||
<a-card class="content-card"> |
|
||||
<template #title> |
|
||||
<span class="card-title"> |
|
||||
<book-outlined /> 知识库内容 |
|
||||
</span> |
|
||||
</template> |
|
||||
|
|
||||
<!-- 快捷操作区域 --> |
|
||||
<div class="quick-actions"> |
|
||||
<a-space> |
|
||||
<a-button type="primary" v-for="action in quickActions" :key="action.title" @click="action.onClick"> |
|
||||
<template #icon><component :is="action.icon" /></template> |
|
||||
{{ action.title }} |
|
||||
</a-button> |
|
||||
</a-space> |
|
||||
</div> |
|
||||
|
|
||||
<!-- 内容展示区域 --> |
|
||||
<div class="content-area"> |
|
||||
<template v-if="selectedKeys.length"> |
|
||||
<!-- 这里可以根据选中的目录显示具体内容 --> |
|
||||
<div class="selected-content"> |
|
||||
已选择: {{ selectedKeys[0] }} |
|
||||
</div> |
|
||||
</template> |
|
||||
<template v-else> |
|
||||
<a-empty description="请选择左侧目录" /> |
|
||||
</template> |
|
||||
</div> |
|
||||
</a-card> |
|
||||
</a-col> |
|
||||
</a-row> |
|
||||
</div> |
|
||||
</template> |
|
||||
|
|
||||
<script setup lang="ts"> |
|
||||
import { ref } from 'vue'; |
|
||||
import { |
|
||||
FolderOutlined, |
|
||||
BookOutlined, |
|
||||
FileTextOutlined, |
|
||||
TeamOutlined, |
|
||||
SettingOutlined, |
|
||||
PlusOutlined, |
|
||||
EditOutlined, |
|
||||
DeleteOutlined, |
|
||||
ExportOutlined |
|
||||
} from '@ant-design/icons-vue'; |
|
||||
|
|
||||
// 目录树数据 |
|
||||
const treeData = ref([ |
|
||||
{ |
|
||||
title: '产品文档', |
|
||||
key: '1', |
|
||||
children: [ |
|
||||
{ title: '使用指南', key: '1-1' }, |
|
||||
{ title: '常见问题', key: '1-2' }, |
|
||||
], |
|
||||
}, |
|
||||
{ |
|
||||
title: '技术文档', |
|
||||
key: '2', |
|
||||
children: [ |
|
||||
{ title: 'API文档', key: '2-1' }, |
|
||||
{ title: '开发规范', key: '2-2' }, |
|
||||
], |
|
||||
}, |
|
||||
]); |
|
||||
|
|
||||
// 树选择状态 |
|
||||
const selectedKeys = ref<string[]>([]); |
|
||||
const expandedKeys = ref<string[]>(['1', '2']); |
|
||||
|
|
||||
// 功能卡片数据 |
|
||||
const featureCards = ref([ |
|
||||
{ |
|
||||
title: '文档管理', |
|
||||
description: '集中管理所有知识文档', |
|
||||
icon: FileTextOutlined, |
|
||||
color: '#1890ff', |
|
||||
}, |
|
||||
{ |
|
||||
title: '团队协作', |
|
||||
description: '支持多人协同编辑', |
|
||||
icon: TeamOutlined, |
|
||||
color: '#52c41a', |
|
||||
}, |
|
||||
{ |
|
||||
title: '系统设置', |
|
||||
description: '自定义知识库配置', |
|
||||
icon: SettingOutlined, |
|
||||
color: '#722ed1', |
|
||||
}, |
|
||||
]); |
|
||||
|
|
||||
// 快捷操作按钮 |
|
||||
const quickActions = ref([ |
|
||||
{ |
|
||||
title: '新建文档', |
|
||||
icon: PlusOutlined, |
|
||||
onClick: () => console.log('新建文档'), |
|
||||
}, |
|
||||
{ |
|
||||
title: '编辑文档', |
|
||||
icon: EditOutlined, |
|
||||
onClick: () => console.log('编辑文档'), |
|
||||
}, |
|
||||
{ |
|
||||
title: '删除文档', |
|
||||
icon: DeleteOutlined, |
|
||||
onClick: () => console.log('删除文档'), |
|
||||
}, |
|
||||
{ |
|
||||
title: '导出文档', |
|
||||
icon: ExportOutlined, |
|
||||
onClick: () => console.log('导出文档'), |
|
||||
}, |
|
||||
]); |
|
||||
|
|
||||
// 树节点选择事件 |
|
||||
const onSelect = (selectedKeys: string[], info: any) => { |
|
||||
console.log('selected', selectedKeys, info); |
|
||||
}; |
|
||||
</script> |
|
||||
|
|
||||
<style lang="less" scoped> |
|
||||
.knowledge-base { |
|
||||
padding: 24px; |
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7eb 100%); |
|
||||
min-height: 100vh; |
|
||||
|
|
||||
.tree-card, |
|
||||
.content-card { |
|
||||
min-height: calc(100vh - 50px); |
|
||||
background: #fff; |
|
||||
border-radius: 8px; |
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
|
||||
|
|
||||
.quick-actions { |
|
||||
margin-bottom: 16px; |
|
||||
padding: 16px 0; |
|
||||
border-bottom: 1px solid #f0f0f0; |
|
||||
} |
|
||||
|
|
||||
.content-area { |
|
||||
padding: 16px 0; |
|
||||
min-height: 300px; |
|
||||
|
|
||||
.selected-content { |
|
||||
padding: 16px; |
|
||||
background: #fafafa; |
|
||||
border-radius: 4px; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
</style> |
|
||||
Loading…
Reference in new issue