123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619 |
- <template>
- <div class="knowledge-retrieval-container layout-padding">
- <el-card shadow="never" class="h100">
- <el-tabs v-model="state.queryParams.Attribution" @tab-change="handleClick" v-if="userInfos.isCenter">
- <el-tab-pane label="全部" name=" " :disabled="centerLoading"></el-tab-pane>
- <el-tab-pane label="中心知识库" name="中心知识库" :disabled="centerLoading"></el-tab-pane>
- <el-tab-pane label="部门知识库" name="部门知识库" :disabled="centerLoading"></el-tab-pane>
- </el-tabs>
- <splitpanes class="h100" Vertical>
- <pane min-size="16" max-size="25" size="16" class="left-container">
- <template v-if="userInfos.isCenter">
- <el-tabs v-model="state.activeName" stretch @tab-change="resetNode">
- <el-tab-pane label="知识分类" name="1" :disabled="centerLoading">
- <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable @input="onQueryChangedType" :disabled="state.typeLoading">
- </el-input>
- </el-tab-pane>
- <el-tab-pane label="部门" name="0" :disabled="centerLoading">
- <el-input v-model="filterOrg" placeholder="请填写部门名称" class="input-with-select mb10" clearable @input="onQueryChanged" :disabled="state.orgLoading">
- </el-input>
- </el-tab-pane>
- <el-tab-pane label="热点" name="2" :disabled="centerLoading">
- <el-input v-model="filterHot" placeholder="请填写热点名称" class="input-with-select mb10" clearable @input="inputHotspot" :disabled="state.hotspotLoading"> </el-input>
- </el-tab-pane>
- </el-tabs>
- <el-scrollbar style="height: calc(100% - 160px);'" ref="scrollBarRef">
- <el-skeleton :loading="state.orgLoading" animated :rows="10" v-if="state.activeName === '0'">
- <template #default>
- <el-auto-resizer>
- <template #default="{ height, width }">
- <el-tree-v2
- :data="state.orgData"
- highlight-current
- :expand-on-click-node="false"
- :props="{ children: 'children', label: 'name' }"
- @node-click="handleNodeClick"
- ref="orgRef"
- :filter-method="filterNode"
- :item-size="32"
- empty-text="暂无组织数据"
- :height="height"
- >
- <template #default="{ node }">
- <text-tooltip :content="node.label + '(' + node.data.knowledgeNum + ')'" effect="dark" placement="top"></text-tooltip>
- </template>
- </el-tree-v2>
- </template>
- </el-auto-resizer>
- </template>
- </el-skeleton>
- <el-skeleton :loading="state.typeLoading" animated :rows="10" v-if="state.activeName === '1'">
- <template #default>
- <el-auto-resizer>
- <template #default="{ height, width }">
- <el-tree-v2
- :data="state.knowledgeOptions"
- highlight-current
- :expand-on-click-node="false"
- :props="{ children: 'children', label: 'name' }"
- @node-click="handleNodeClick"
- ref="typeRef"
- :filter-method="filterNodeType"
- :item-size="32"
- empty-text="暂无知识分类"
- :height="height"
- >
- <template #default="{ node }">
- <text-tooltip :content="node.label+'('+node.data.knowledgeNum+')'" effect="dark" placement="top"></text-tooltip>
- </template>
- </el-tree-v2>
- </template>
- </el-auto-resizer>
- </template>
- </el-skeleton>
- <el-skeleton :loading="state.hotspotLoading" animated :rows="10" v-if="state.activeName === '2'">
- <template #default>
- <el-tree
- node-key="id"
- :load="loadNode"
- lazy
- v-if="lazyShow"
- :props="{
- label: 'hotSpotFullName',
- children: 'children',
- isLeaf: 'hasChild',
- }"
- :filter-node-method="filterNodeHot"
- @node-click="handleNodeClick"
- highlight-current
- check-strictly
- :expand-on-click-node="false"
- ref="hotRef"
- > <template #default="{ node }">
- <text-tooltip :content="node.label + '(' + node.data.knowledgeNum + ')'" effect="dark" placement="top"></text-tooltip>
- </template>
- </el-tree>
- <el-tree
- ref="hotRef"
- :data="state.hotSpotData"
- node-key="id"
- v-else
- default-expand-all
- highlight-current
- :props="{
- label: 'hotSpotFullName',
- children: 'children',
- }"
- :filter-node-method="filterNodeHot"
- @node-click="handleNodeClick"
- :expand-on-click-node="false"
- check-strictly
- > <template #default="{ node }">
- <text-tooltip :content="node.label + '(' + node.data.knowledgeNum + ')'" effect="dark" placement="top"></text-tooltip>
- </template>
- </el-tree>
- </template>
- </el-skeleton>
- </el-scrollbar>
- </template>
- <template v-else>
- <el-input v-model="filterType" placeholder="请填写知识分类名称" class="input-with-select mb10" clearable> </el-input>
- <el-scrollbar ref="scrollBarRef" :style="userInfos.isCenter ? 'height: calc(100% - 90px);' : 'height: calc(100% - 50px)'">
- <el-skeleton :loading="state.typeLoading" animated :rows="10">
- <template #default>
- <el-auto-resizer>
- <template #default="{ height, width }">
- <el-tree-v2
- :data="state.knowledgeOptions"
- highlight-current
- :expand-on-click-node="false"
- :props="{ children: 'children', label: 'name' }"
- @node-click="handleNodeClick"
- ref="typeRef"
- :filter-method="filterNodeType"
- :item-size="32"
- empty-text="暂无知识分类"
- :height="height"
- >
- <template #default="{ node }">
- <text-tooltip :content="node.label+'('+node.data.knowledgeNum+')'" effect="dark" placement="top"></text-tooltip>
- </template>
- </el-tree-v2>
- </template>
- </el-auto-resizer>
- </template>
- </el-skeleton>
- </el-scrollbar>
- </template>
- </pane>
- <pane class="center-container">
- <div class="input-box">
- <el-select v-model="state.queryParams.RetrievalType" placeholder="请选择" class="width120" @change="handleQuery" :disabled="centerLoading">
- <el-option v-for="item in knowledgeRetrievalType" :key="item.key" :label="item.value" :value="item.key" />
- </el-select>
- <div class="input-with-button w100">
- <div class="flex">
- <el-input
- v-model="state.queryParams.Keyword"
- placeholder="多个关键词请用逗号或空格分割"
- clearable
- class="mr10 w100"
- @keyup.enter="handleQuery"
- :disabled="centerLoading"
- >
- </el-input>
- <el-button type="primary" class="btn" :loading="centerLoading" @click="handleQuery"
- ><SvgIcon name="ele-Search" class="mr5" />搜索</el-button
- >
- <el-button @click="resetQuery" class="default-button" :loading="centerLoading"> <SvgIcon name="ele-Refresh" class="mr5" />重置</el-button>
- </div>
- <div class="mt10" style="display: flex">
- <div style="display: flex; align-items: flex-start; flex-wrap: wrap">
- <div style="height: 18px; line-height: 18px">猜你想搜:</div>
- <div class="keyword-box">
- <span v-for="(v, i) in state.hotWordsList" :key="i" class="keyword-item" @click="keyWordSearch(v.keyWord)">{{ v.keyWord }}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- <div style="display: flex; margin: 10px 15px 0">
- <div style="height: 32px; line-height: 32px">排序:</div>
- <el-radio-group v-model="state.queryParams.Sort" @change="handleQuery" style="align-items: normal">
- <el-radio value="1">浏览量</el-radio>
- <el-radio value="2">评分</el-radio>
- <el-radio value="3">创建时间</el-radio>
- </el-radio-group>
- </div>
- <div
- v-loading="centerLoading"
- class="center-container-box"
- :style="userInfos.isCenter ? 'height: calc(100% - 200px)' : 'height: calc(100% - 160px)'"
- >
- <template v-if="state.retrievalList.length">
- <el-scrollbar>
- <div v-for="(v, i) in state.retrievalList" :key="i" class="retrieval-content-item" @click="onPreview(v)" title="查看详情">
- <h4 class="mb10 text-no-wrap retrieval-content-item-title">{{ v.title }}</h4>
- <!-- <div class="text-ellipsis2">{{ v.summary }}</div>-->
- <div class="flex-center-between mt10 color-info">
- <div>
- <span class="mr10">创建部门:{{ v.creatorOrgName }}</span>
- <span>创建时间:{{ formatDate(v.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
- </div>
- <div class="flex-center-align">
- <span class="flex-center-align"><SvgIcon name="ele-StarFilled" size="18px" class="mr3" />{{ v.score }}</span>
- <!-- <span class="flex-center-align ml10"><SvgIcon name="ele-ChatDotSquare" size="16px" class="mr3" />{{ v.commentNum }}</span>-->
- <span class="flex-center-align ml10"><SvgIcon name="ele-View" size="16px" class="mr3" />{{ v.pageView }}</span>
- </div>
- </div>
- </div>
- </el-scrollbar>
- </template>
- <el-empty v-else description="暂无结果" />
- <pagination
- @pagination="queryList"
- :total="state.total"
- v-model:current-page="state.queryParams.PageIndex"
- v-model:page-size="state.queryParams.PageSize"
- :disabled="centerLoading"
- />
- </div>
- </pane>
- <pane min-size="20" max-size="30" size="20" class="right-container">
- <p class="flex-center-between pt10">
- <span class="font16">常用知识前10</span>
- <el-button link type="primary" @click="querySearchNum"><SvgIcon name="ele-Refresh" class="mr4" /> 刷新</el-button>
- </p>
- <el-divider />
- <p class="flex-center-between">
- <span>排名</span>
- <span>阅读量</span>
- </p>
- <el-skeleton :loading="rightLoading" animated :rows="10">
- <template #default>
- <div class="top10 mt10" :style="userInfos.isCenter ? 'height: calc(100% - 160px);' : 'height: calc(100% - 100px)'">
- <template v-if="topList.length">
- <el-scrollbar>
- <div class="flex-center-between top10-items" v-for="(item, index) in topList" :key="item.id">
- <p class="flex-center-align top10-items-title" @click="onPreview(item)">
- {{ index + 1 }}.
- <el-text class="text-no-wrap color-primary cursor-pointer" @click="onPreview(item)">
- <TextTooltip :content="item.title" placement="top" effect="dark" />
- </el-text>
- </p>
- <span class="top10-items-num">{{ item.pageView }}</span>
- </div>
- </el-scrollbar>
- </template>
- <el-empty v-else />
- </div>
- </template>
- </el-skeleton>
- </pane>
- </splitpanes>
- </el-card>
- </div>
- </template>
- <script setup lang="ts" name="knowledgeRetrieval">
- import { onMounted, reactive, ref, watch, defineAsyncComponent } from 'vue';
- import { useRouter } from 'vue-router';
- import { knowledgeRetrieval, searchNumList, knowledgeRetrievalBaseData } from '@/api/knowledge/retrieval';
- import { knowledgeDepartmentList, knowledgeHotSpotList, knowledgeHotSpotSearch, treeList } from '@/api/knowledge/type';
- import { formatDate } from '@/utils/formatTime';
- import { debounce, throttle } from '@/utils/tools';
- import { Splitpanes, Pane } from 'splitpanes';
- import 'splitpanes/dist/splitpanes.css';
- import { useUserInfo } from '@/stores/userInfo';
- import { storeToRefs } from 'pinia';
- import { getKnowledgeHotWordsList } from '@/api/knowledge/hotWords';
- const pagination = defineAsyncComponent(() => import('@/components/ProTable/components/Pagination.vue')); // 分页
- const TextTooltip = defineAsyncComponent(() => import('@/components/TextTooltip/index.vue'));
- const router = useRouter(); // 路由
- const storesUserInfo = useUserInfo();
- const { userInfos } = storeToRefs(storesUserInfo); // 用户信息
- const state = reactive<any>({
- queryParams: {
- // 查询条件
- PageIndex: 1, // 当前页
- PageSize: 10, // 每页条数
- Attribution: userInfos.value.isCenter ? ' ' : '部门知识库',
- Keyword: null, // 关键词
- RetrievalType: 0, // 检索类型
- Sort: '1',
- },
- activeName: '1', //tab切换 默认知识分类
- orgData: [], // 部门
- knowledgeOptions: [], // 知识类型
- total: 0, // 总条数
- loading: false, // 加载状态
- retrievalList: [], // 检索列表
- hotSpotData: [], // 热点数据
- typeLoading: false, // 知识类型loading
- hotspotLoading:false,
- orgLoading:false,
- hotWordsList: [], // 获取热词
- });
- const topList = ref<EmptyArrayType>([]); // 常用知识前10
- const handleClick = () => {
- handleQuery();
- };
- // 部门查询
- const filterOrg = ref('');
- const orgRef = ref<RefType>();
- const onQueryChanged = (query: string) => {
- if (query) {
- orgRef.value!.filter(query);
- } else {
- orgRef.value!.filter(query);
- orgRef.value?.setExpandedKeys([]);
- }
- };
- const filterNode = (value: string, data: any) => {
- if (!value) return true;
- return data.name.includes(value);
- };
- // 知识分类查询
- const filterType = ref('');
- const typeRef = ref<RefType>();
- const filterNodeType = (value: string, data: any) => {
- if (!value) return true;
- return data.name.includes(value);
- };
- const onQueryChangedType = (query: string) => {
- if (query) {
- typeRef.value!.filter(query);
- } else {
- typeRef.value!.filter(query);
- typeRef.value?.setExpandedKeys([]);
- }
- };
- // 热点查询
- const filterHot = ref('');
- const hotRef = ref<RefType>();
- watch(filterHot, (val) => {
- if (val) {
- lazyShow.value = false;
- } else if (val == '' || val == ' ' || val == null) {
- lazyShow.value = true; // 懒加载树显示
- }
- });
- const filterNodeHot = (value: string, data: any) => {
- if (!value) return true;
- return data.hotSpotName.includes(value);
- };
- const inputHotspot = debounce((val:string)=>{
- state.hotspotLoading = true;
- if (val) {
- knowledgeHotSpotSearch({name:val,Attribution:state.queryParams.Attribution})
- .then((res) => {
- //获取后端搜索的数据
- state.hotSpotData.length = 0;
- state.hotSpotData = res.result ?? [];
- state.hotspotLoading = false;
- })
- .catch((e) => {
- console.log(e);
- state.hotspotLoading = false;
- });
- } else if (val == '' || val == ' ' || val == null) {
- state.hotspotLoading = false;
- }
- },500)
- // 热点分类懒加载
- const lazyShow = ref(true);
- const loadNode = async (node: any, resolve: any) => {
- try {
- if (node.isLeaf) return resolve([]);
- const {result} = await knowledgeHotSpotList({ id: node.data.id ? node.data.id : null,Attribution:state.queryParams.Attribution });
- resolve(result);
- } catch (error) {
- resolve([]);
- }
- };
- // 获取所有组织结构 和基础数据
- const getOrgListApi = async () => {
- state.orgLoading = true;
- try {
- const { result } = await knowledgeDepartmentList({ Attribution: state.queryParams.Attribution });
- state.orgData = result ?? []; //部门
- state.orgLoading = false;
- } catch (error) {
- state.orgLoading = false;
- }
- };
- // 获取知识分类
- const getKnowledgeType = async () => {
- state.typeLoading = true;
- try {
- const { result } = await treeList({ IsEnable: true,Attribution: state.queryParams.Attribution,status:3 });
- state.knowledgeOptions = result ?? [];
- state.typeLoading = false;
- } catch (error) {
- state.typeLoading = false;
- }
- };
- // 点击节点
- const handleNodeClick = (data: any) => {
- if (userInfos.value.isCenter) {
- switch (state.activeName) {
- case '0':
- state.queryParams.CreateOrgId = data.id;
- break;
- case '1':
- state.queryParams.KnowledgeTypeId = data.id;
- break;
- case '2':
- state.queryParams.HotspotId = data.id;
- break;
- default:
- break;
- }
- } else {
- state.queryParams.KnowledgeTypeId = data.id;
- }
- handleQuery();
- };
- // 预览
- const onPreview = (row: any) => {
- router.push({
- name: 'knowledgePreview',
- params: {
- id: row.id,
- isAddPv: 'isAddPv',
- tagsViewName: row.title,
- },
- });
- };
- // 切换tab 查询列表
- const rightLoading = ref(false); // 右侧加载状态
- // 常用知识前10
- const querySearchNum = () => {
- rightLoading.value = true;
- searchNumList({ Keyword: state.queryParams.Keyword })
- .then((res: any) => {
- topList.value = res.result?.items ?? [];
- rightLoading.value = false;
- })
- .catch(() => {
- rightLoading.value = false;
- });
- };
- const centerLoading = ref(false); // 中间加载状态
- /** 搜索按钮操作 */
- const handleQuery = () => {
- state.queryParams.PageIndex = 1;
- queryList();
- };
- const queryList = () => {
- centerLoading.value = true;
- knowledgeRetrieval(state.queryParams)
- .then((res: any) => {
- state.retrievalList = res.result?.items ?? [];
- /* state.retrievalList = [
- ...res.result?.items,
- ...res.result?.items,
- ...res.result?.items,
- ...res.result?.items,
- ...res.result?.items,
- ...res.result?.items,
- ...res.result?.items,
- ];*/
- state.total = res.result?.total ?? 0;
- centerLoading.value = false;
- })
- .catch(() => {
- centerLoading.value = false;
- state.retrievalList = [];
- state.total = 0;
- });
- };
- /** 重置按钮操作 */
- const resetQuery = throttle(() => {
- state.queryParams.PageIndex = 1;
- state.queryParams.PageSize = 10;
- state.queryParams.Keyword = null;
- state.queryParams.RetrievalType = 0;
- state.queryParams.Sort = '1';
- state.queryParams.Attribution = ' ';
- state.activeName = '1';
- state.queryParams.CreateOrgId = null;
- state.queryParams.KnowledgeTypeId = null;
- state.queryParams.HotspotId = null;
- filterOrg.value = '';
- filterType.value = '';
- filterHot.value = '';
- typeRef.value?.setCurrentKey(null);
- orgRef.value?.setCurrentKey(null);
- hotRef.value?.setCurrentKey(null);
- orgRef.value?.filter();
- orgRef.value?.setExpandedKeys([]);
- typeRef.value?.filter();
- typeRef.value?.setExpandedKeys([]);
- hotRef.value?.filter();
- queryList();
- }, 500);
- // 重置选中的节点
- const resetNode = () => {
- state.queryParams.CreateOrgId = null;
- state.queryParams.KnowledgeTypeId = null;
- state.queryParams.HotspotId = null;
- filterOrg.value = '';
- filterType.value = '';
- filterHot.value = '';
- typeRef.value?.setCurrentKey(null);
- orgRef.value?.setCurrentKey(null);
- hotRef.value?.setCurrentKey(null);
- queryList();
- };
- // 获取热词
- const getHotWords = async () => {
- try {
- const {result} = await getKnowledgeHotWordsList({ PageIndex: 1, PageSize: 10, IsEnable: true });
- state.hotWordsList = result?.items ?? [];
- } catch (error) {
- console.log(error);
- }
- };
- // 点击关键词检索
- const keyWordSearch = (word: string) => {
- state.queryParams.Keyword = word;
- handleQuery();
- };
- // 获取基础信息
- const knowledgeRetrievalType = ref<EmptyArrayType>([]);
- const getBaseData = async () => {
- try {
- const { result } = await knowledgeRetrievalBaseData();
- knowledgeRetrievalType.value = result.knowledgeRetrievalType;
- } catch (error) {
- console.log(error);
- }
- };
- onMounted(() => {
- getBaseData();
- getKnowledgeType();
- getOrgListApi();
- queryList();
- querySearchNum();
- getHotWords();
- });
- </script>
- <style scoped lang="scss">
- .knowledge-retrieval-container {
- .left-container {
- height: 100%;
- }
- .center-container {
- height: 100%;
- display: flex;
- flex-direction: column;
- .input-box {
- display: flex;
- }
- .retrieval-content {
- &-item {
- border-bottom: var(--el-border);
- padding: 10px 15px;
- margin-bottom: 10px;
- cursor: pointer;
- &:last-child {
- margin-bottom: 0;
- border: none;
- }
- &:hover {
- color: var(--el-color-primary);
- }
- }
- }
- }
- .right-container {
- height: 100%;
- .top10 {
- &-items {
- margin-bottom: 20px;
- &:last-child {
- margin-bottom: 0;
- }
- &-title {
- flex: 1;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- &-num {
- display: inline-block;
- width: 50px;
- text-align: center;
- }
- }
- }
- }
- :deep(.el-tree-node__content) {
- height: 32px;
- }
- :deep(.el-card__body) {
- height: 100%;
- }
- .keyword-box {
- display: flex;
- flex: 1;
- flex-wrap: wrap;
- line-height: 18px;
- .keyword-item {
- margin-right: 5px;
- cursor: pointer;
- color: var(--el-color-info);
- font-size: var(--el-font-size-extra-small);
- &:last-child {
- margin-right: 0;
- }
- &:hover {
- color: var(--el-color-primary);
- }
- }
- }
- }
- </style>
|