Browse Source

feat:新增知识收藏和知识检索排行

zhangchong 1 năm trước cách đây
mục cha
commit
46df825582

+ 17 - 0
src/api/knowledge/collect.ts

@@ -0,0 +1,17 @@
+/*
+ * @Author: zc
+ * @description 知识管理 收藏
+ */
+import request from '/@/utils/request';
+/**
+ * @description 知识收藏列表
+ * @param params
+ * @return {*}
+ */
+export const collectList = (params: object) => {
+    return request({
+        url: '/api/v1/Knowledge/knowledge_collect/list',
+        method: 'get',
+        params
+    });
+};

+ 24 - 4
src/api/knowledge/retrieval.ts

@@ -1,10 +1,6 @@
 /*
  * @Author: zc
  * @description 知识管理 检索
- * @version:
- * @Date: 2022-08-09 16:19:55
- * @LastEditors: Please set LastEditors
- * @LastEditTime: 2022-11-15 10:21:44
  */
 import request from '/@/utils/request';
 /**
@@ -18,4 +14,28 @@ export const knowledgeRetrieval = (params: object) => {
 		method: 'get',
 		params
 	});
+};
+/**
+ * @description 知识检索-top10
+ * @param params
+ * @return {*}
+ */
+export const searchNumList = (params?: object) => {
+	return request({
+		url: '/api/v1/Knowledge/search_num/list',
+		method: 'get',
+		params
+	});
+};
+/**
+ * @description 知识检索-增加搜索量
+ * @param data
+ * @return {*}
+ */
+export const searchNumAdd = (data: object) => {
+	return request({
+		url: '/api/v1/Knowledge/search_num',
+		method: 'post',
+		data
+	});
 };

+ 2 - 2
src/views/business/order/accept/Knowledge.vue

@@ -12,8 +12,8 @@
         class="mr10 w100 knowledge-input"
         clearable
         value-key="title"
-
     >
+
       <template #prefix>
         <SvgIcon name="ele-Search" size="16px" />
       </template>
@@ -111,7 +111,7 @@ const knowledgeRetrievalPaged = async () => {
 		state.loading = false;
 	}
 };
-const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
+const querySearchAsync = (queryString: string | null, cb: (arg: any) => void) => {
   if (queryString) {
     state.loading = true;
     knowledgeRetrieval({

+ 0 - 2
src/views/home/component/Backlog-list.vue → src/views/home/component/Backlog.vue

@@ -1,5 +1,3 @@
-
-
 <template>
   <el-card shadow="never" class="mb20" style="position: relative" v-loading="state.tableLoading">
     <el-button link type="primary" style="position: absolute;right: 20px;top:32px;z-index:2" @click="linkList">

+ 93 - 6
src/views/home/component/Home-entrance.vue → src/views/home/component/Entrance.vue

@@ -1,5 +1,21 @@
 <template>
 	<div class="home-entrance-container">
+    <el-card shadow="never" class="right-entrance w100" v-loading="state.entranceLoading">
+      <p class="right-entrance-title">
+        常用入口
+        <span @click="openDialog"> <SvgIcon name="ele-Setting" class="mr5" />自定义 </span>
+      </p>
+      <template v-if="state.entranceArray.length">
+        <ul class="right-entrance-list">
+          <li class="right-entrance-list-item" v-for="item in state.entranceArray" :title="item.pageName" :key="item.id" :data-id="item.id" @click="goLink(item)">
+            <!--								<img v-lazy="getImageUrl(item.fastIcon)" alt="" class="my-handle" src="" />-->
+            <SvgIcon :name="item.icon" size="42px" class="my-handle" />
+            <p class="text-no-wrap">{{ item.pageName }}</p>
+          </li>
+        </ul>
+      </template>
+      <Empty descriptionData="暂无常用入口" v-else />
+    </el-card>
 		<el-dialog v-model="state.dialogVisible" draggable title="常用入口设置">
 			<div class="entrance-list">
 				<p class="entrance-list-title">首页入口</p>
@@ -67,12 +83,14 @@
 </template>
 
 <script lang="ts" setup name="homeEntrance">
-import { reactive } from 'vue';
+import {onMounted, reactive} from 'vue';
 import { ElMessage } from 'element-plus';
+import {useRouter} from "vue-router";
 import { Search } from '@element-plus/icons-vue';
 import { getImageUrl } from '/@/utils/tools';
 import { geFastMenu, fastMenu, setFastMenu } from '/@/api/home';
 import Draggable from 'vuedraggable';
+
 const state = reactive<any>({
 	dialogVisible: false,
 	searchKey: '',
@@ -81,19 +99,39 @@ const state = reactive<any>({
 	entranceSelect: [],
 	loading: false,
 	selectLoading: false,
+
+  entranceArray: <EmptyArrayType>[], // 常用入口
+  entranceLoading: false, //入口
 });
-const emit = defineEmits(['updateEntrance', 'openDialog', 'closeDialog']);
+
+// 跳转到
+const router = useRouter();
+const goLink = (item:any)=>{
+  router.push({
+    path: item.path,
+  });
+}
+//获取入口设置
+const getMyEntrance = () => {
+  state.entranceLoading = true;
+  geFastMenu()
+      .then((res: any) => {
+        state.entranceArray = res?.result ?? [];
+        state.entranceLoading = false;
+      })
+      .catch(() => {
+        state.entranceLoading = false;
+      });
+};
 // 打开弹窗
 const openDialog = () => {
 	state.dialogVisible = true;
 	getEntrance();
 	getEntranceSelect();
-	emit('openDialog');
 };
 // 关闭弹窗
 const closeDialog = () => {
 	state.dialogVisible = false;
-	emit('closeDialog');
 };
 // 获取我的入口
 const getEntrance = () => {
@@ -153,7 +191,7 @@ const onSubmit = async () => {
 			: state.entranceList.map((item: any) => item.permissionCode);
 		await setFastMenu({ fastMenuArr: req });
 		ElMessage.success('操作成功');
-		emit('updateEntrance');
+    getMyEntrance()
 	} catch {
 		// 处理错误
 		state.dialogVisible = false;
@@ -161,10 +199,59 @@ const onSubmit = async () => {
 		state.dialogVisible = false;
 	}
 };
-defineExpose({ closeDialog, openDialog }); //暴漏方法
+onMounted(() => {
+  getMyEntrance();
+});
 </script>
 <style lang="scss" scoped>
 .home-entrance-container {
+  .right-entrance {
+    &-title {
+      font-size: var(--el-font-size-medium);
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding-bottom: 20px;
+      font-weight: 600;
+      span {
+        font-size: 14px;
+        display: flex;
+        align-items: center;
+        color: var(--el-text-color-regular);
+        cursor: pointer;
+        font-weight: normal;
+      }
+    }
+    &-list {
+      display: grid;
+      justify-content: space-between;
+      grid-template-columns: repeat(auto-fill, 110px);
+      grid-gap: 15px;
+
+      &-item {
+        background: var(--hotline-bg-main-color);
+        border-radius: 8px;
+        text-align: center;
+        width: 110px;
+        height: 110px;
+        cursor: pointer;
+        color: var(--el-text-color-regular);
+        user-select: none;
+        padding: 10px 20px;
+        .my-handle {
+          display: inline-block;
+          width: 40px;
+          height: 50px;
+          margin-top: 5px;
+          margin-bottom: 10px;
+        }
+        &:hover {
+          color: var(--el-color-primary);
+          background-color: var(--el-color-primary-light-8);
+        }
+      }
+    }
+  }
 	.entrance-list {
 		color: var(--hotline-color-text-main);
 

+ 140 - 0
src/views/home/component/Notice.vue

@@ -0,0 +1,140 @@
+
+<template>
+  <el-card shadow="never" class="mt20 right-notice" v-loading="state.noticeLoading">
+    <el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
+      <el-tab-pane label="知识库" name="0"></el-tab-pane>
+      <el-tab-pane label="通知公告" name="1"></el-tab-pane>
+    </el-tabs>
+    <el-button type="primary" link @click="more(activeName)" class="more"> 更多<SvgIcon name="ele-ArrowRight" /> </el-button>
+    <template v-if="state.noticeList.length">
+      <vue3-seamless-scroll :list="state.noticeList" class="right-notice-scroll" :hover="true" :limitScrollNum="6">
+        <div class="right-notice-scroll-item" v-for="(item, index) in state.noticeList" :key="index">
+								<span class="right-notice-scroll-item-name text-no-wrap" @click="goLink(item)">
+									<SvgIcon name="iconfont icon-jiadayinliang" class="mr5 vd" />
+									{{ item.knowledgeTypeName }}
+									{{ item.title }}</span>
+          <span class="right-notice-scroll-item-date"
+          >{{ formatDate(item.creationTime, 'YYYY-mm-dd') }}
+									<SvgIcon name="ele-DArrowRight" class="ml5" />
+								</span>
+        </div>
+      </vue3-seamless-scroll>
+    </template>
+    <Empty v-else descriptionData="暂无通知公告" />
+  </el-card>
+</template>
+<script setup lang="ts">
+import {onMounted, reactive, ref} from "vue";
+import { Vue3SeamlessScroll } from 'vue3-seamless-scroll';
+import {formatDate} from "/@/utils/formatTime";
+import {useRouter} from "vue-router";
+import {KnowledgePaged} from "/@/api/knowledge";
+const state = reactive({
+  noticeList: [], // 通知公告
+  noticeLoading: false, // 公告
+});
+
+const router = useRouter();
+const activeName = ref('0');
+// 知识库公告切换
+const handleClick = (val: string) => {
+  state.noticeLoading = true;
+  state.noticeList = [];
+  switch (val) {
+    case '0':
+      KnowledgePaged({ PageIndex: 1, PageSize: 10 })
+          .then((response: any) => {
+            state.noticeList = response?.result.items ?? [];
+            state.noticeLoading = false;
+          })
+          .catch(() => {
+            state.noticeLoading = false;
+          });
+      break;
+    case '1':
+      state.noticeLoading = false;
+      break;
+    default:
+      break;
+  }
+};
+// 知识库和通知公告详情
+const goLink = (item:any)=>{
+  switch (activeName.value) {
+    case '0':
+      router.push({
+        name: 'knowledgePreview',
+        params: {
+          id: item.id,
+          tagsViewName: '知识查看',
+        },
+      });
+      break;
+    case '1':
+      // const tagsViewName = listType.value === '0' ? '通知详情' : '公告详情';
+      router.push({
+        name: 'auxiliaryNoticeDetail',
+        params: {
+          id: item.id,
+          isRead: 0,
+          tagsViewName:'通知详情',
+        },
+      });
+      break;
+  }
+}
+// 更多
+const more = (val: string) => {
+  switch (val) {
+    case '0':
+      router.push({ path: '/knowledge/index' });
+      break;
+    case '1':
+      router.push({ path: '/auxiliary/notice' });
+      break;
+    default:
+      break;
+  }
+};
+onMounted(()=>{
+  handleClick('0');
+})
+</script>
+
+
+<style scoped lang="scss">
+.right-notice {
+  position: relative;
+  .more {
+    position: absolute;
+    right: 20px;
+    top: 30px;
+    z-index: 2;
+  }
+  &-scroll {
+    height: 400px;
+    overflow: hidden;
+    &-item {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      border-top: 1px solid var(--el-border-color);
+      cursor: pointer;
+      height: 50px;
+      &-name {
+        flex: 1;
+        max-width: 70%;
+      }
+      &-date {
+        display: flex;
+        align-items: center;
+        color: var(--el-color-info);
+        text-align: right;
+      }
+      &:hover {
+        color: var(--el-color-primary);
+      }
+    }
+  }
+}
+</style>

+ 114 - 0
src/views/home/component/Numbers.vue

@@ -0,0 +1,114 @@
+<template>
+  <el-row :gutter="20">
+    <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+      <el-card shadow="never" v-loading="state.loading" class="statistics-item">
+        <div class="statistics-title">
+          <img v-lazy="getImageUrl('home/Call.png')" alt="" src="" />
+          今日来电
+        </div>
+        <div class="statistics-number">
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>520</b></p>
+            <p class="statistics-number-item-tips">全部</p>
+          </div>
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>200</b></p>
+            <p class="statistics-number-item-tips">有效</p>
+          </div>
+        </div>
+      </el-card>
+    </el-col>
+    <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+      <el-card shadow="never" v-loading="state.loading" class="statistics-item">
+        <div class="statistics-title">
+          <img v-lazy="getImageUrl('home/connectionRate.png')" alt="" src="" />
+          今日接通率
+        </div>
+        <div class="statistics-number">
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>198</b></p>
+            <p class="statistics-number-item-tips">接通</p>
+          </div>
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>90%</b></p>
+            <p class="statistics-number-item-tips">接通率</p>
+          </div>
+        </div>
+      </el-card>
+    </el-col>
+    <el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
+      <el-card shadow="never" v-loading="state.loading" class="statistics-item">
+        <div class="statistics-title">
+          <img v-lazy="getImageUrl('home/workOrder.png')" alt="" src="" />
+          今日受理工单
+        </div>
+        <div class="statistics-number">
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>980</b></p>
+            <p class="statistics-number-item-tips">受理工单量</p>
+          </div>
+          <div class="statistics-number-item">
+            <p class="statistics-number-item-number"><b>730</b></p>
+            <p class="statistics-number-item-tips">今日直办工单量</p>
+          </div>
+        </div>
+      </el-card>
+    </el-col>
+  </el-row>
+</template>
+<script setup lang="ts">
+import {getImageUrl} from "/@/utils/tools";
+import {reactive} from "vue";
+const state = reactive({
+  entranceList: <EmptyArrayType>[], // 常用入口
+  noticeList: [], // 通知公告
+  loading: false, //头部
+  entranceLoading: false, //入口
+  noticeLoading: false, // 公告
+});
+</script>
+<style scoped lang="scss">
+.statistics {
+  display: flex;
+  justify-content: space-between;
+  &-item {
+    height: 200px;
+    margin-bottom: 20px;
+  }
+  &-title {
+    background: var(--hotline-bg-main-color);
+    border-radius: 16px;
+    height: 60px;
+    position: relative;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    font-size: var(--el-font-size-medium);
+    img {
+      width: 83px;
+      height: 83px;
+      position: absolute;
+      left: -22px;
+      top: -2px;
+    }
+  }
+  &-number {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 40px 20px 0 20px;
+    text-align: center;
+    &-item-number {
+      font-size: 30px;
+    }
+    &-item-tips {
+      margin-top: 12px;
+      color: var(--hotline-color-text-main-light);
+    }
+    &-item-total {
+      flex: 1;
+      font-size: 30px;
+    }
+  }
+}
+</style>

+ 14 - 324
src/views/home/index.vue

@@ -1,125 +1,30 @@
 <template>
 	<div class="home-container layout-pd">
 		<el-row :gutter="20">
-			<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16" class="left-content">
-				<el-row :gutter="20">
-					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
-						<el-card shadow="never" v-loading="state.loading" class="statistics-item">
-							<div class="statistics-title">
-								<img v-lazy="getImageUrl('home/Call.png')" alt="" src="" />
-								今日来电
-							</div>
-							<div class="statistics-number">
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>520</b></p>
-									<p class="statistics-number-item-tips">全部</p>
-								</div>
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>200</b></p>
-									<p class="statistics-number-item-tips">有效</p>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
-						<el-card shadow="never" v-loading="state.loading" class="statistics-item">
-							<div class="statistics-title">
-								<img v-lazy="getImageUrl('home/connectionRate.png')" alt="" src="" />
-								今日接通率
-							</div>
-							<div class="statistics-number">
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>198</b></p>
-									<p class="statistics-number-item-tips">接通</p>
-								</div>
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>90%</b></p>
-									<p class="statistics-number-item-tips">接通率</p>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-					<el-col :xs="24" :sm="12" :md="12" :lg="8" :xl="8">
-						<el-card shadow="never" v-loading="state.loading" class="statistics-item">
-							<div class="statistics-title">
-								<img v-lazy="getImageUrl('home/workOrder.png')" alt="" src="" />
-								今日受理工单
-							</div>
-							<div class="statistics-number">
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>980</b></p>
-									<p class="statistics-number-item-tips">受理工单量</p>
-								</div>
-								<div class="statistics-number-item">
-									<p class="statistics-number-item-number"><b>730</b></p>
-									<p class="statistics-number-item-tips">今日直办工单量</p>
-								</div>
-							</div>
-						</el-card>
-					</el-col>
-				</el-row>
-
-				<backlog-list />
+			<el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16">
+        <!-- 统计 -->
+        <numbers />
+        <!-- 待办工作台 -->
+				<backlog/>
 			</el-col>
-			<!-- 常用入口 -->
-			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8" class="right-content">
-				<el-card shadow="never" class="right-entrance w100" v-loading="state.entranceLoading">
-					<p class="right-entrance-title">
-						常用入口
-						<span @click="customEntry"> <SvgIcon name="ele-Setting" class="mr5" />自定义 </span>
-					</p>
-					<template v-if="state.entranceList.length">
-						<ul class="right-entrance-list">
-							<li class="right-entrance-list-item" v-for="item in state.entranceList" :key="item.id" :data-id="item.id" @click="goLink(item.path)">
-								<!--								<img v-lazy="getImageUrl(item.fastIcon)" alt="" class="my-handle" src="" />-->
-								<SvgIcon :name="item.icon" size="42px" class="my-handle" />
-								<p>{{ item.pageName }}</p>
-							</li>
-						</ul>
-					</template>
-					<Empty descriptionData="暂无常用入口" v-else />
-				</el-card>
+			<el-col :xs="24" :sm="24" :md="24" :lg="8" :xl="8">
+        <!-- 常用入口 -->
+        <entrance />
 				<!-- 通知公告 -->
-				<el-card shadow="never" class="mt20 right-notice" v-loading="state.noticeLoading">
-					<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClick">
-						<el-tab-pane label="知识库" name="0"></el-tab-pane>
-						<el-tab-pane label="通知公告" name="1"></el-tab-pane>
-					</el-tabs>
-					<el-button type="primary" link @click="more(activeName)" class="more"> 更多<SvgIcon name="ele-ArrowRight" /> </el-button>
-					<template v-if="state.noticeList.length">
-						<vue3-seamless-scroll :list="state.noticeList" class="right-notice-scroll" :hover="true" :limitScrollNum="6">
-							<div class="right-notice-scroll-item" v-for="(item, index) in state.noticeList" :key="index">
-								<span class="right-notice-scroll-item-name text-no-wrap" @click="goLink(item)">
-									<SvgIcon name="iconfont icon-jiadayinliang" class="mr5 vd" />
-									{{ item.knowledgeTypeName }}
-									{{ item.title }}</span>
-								<span class="right-notice-scroll-item-date"
-									>{{ formatDate(item.creationTime, 'YYYY-mm-dd') }}
-									<SvgIcon name="ele-DArrowRight" class="ml5" />
-								</span>
-							</div>
-						</vue3-seamless-scroll>
-					</template>
-					<Empty v-else descriptionData="暂无通知公告" />
-				</el-card>
+				<notice />
 			</el-col>
 		</el-row>
-		<!--  常用入口  -->
-		<home-entrance ref="entranceRef" @updateEntrance="getEntrance" />
 	</div>
 </template>
 
 <script lang="ts" setup name="home">
-import { defineAsyncComponent, reactive, ref, onMounted } from 'vue';
+import { defineAsyncComponent, reactive} from 'vue';
 import { useRouter } from 'vue-router';
-import { Vue3SeamlessScroll } from 'vue3-seamless-scroll';
-import { getImageUrl } from '/@/utils/tools';
-import { formatDate } from '/@/utils/formatTime';
-import { geFastMenu } from '/@/api/home';
-import { KnowledgePaged } from '/@/api/knowledge';
 // 引入组件
-const HomeEntrance = defineAsyncComponent(() => import('/@/views/home/component/Home-entrance.vue'));
-const BacklogList = defineAsyncComponent(() => import('/@/views/home/component/Backlog-list.vue'));
+const Numbers = defineAsyncComponent(() => import('/@/views/home/component/Numbers.vue'));
+const Entrance = defineAsyncComponent(() => import('/src/views/home/component/Entrance.vue'));
+const Backlog = defineAsyncComponent(() => import('/src/views/home/component/Backlog.vue'));
+const Notice = defineAsyncComponent(() => import('/@/views/home/component/Notice.vue'));
 const router = useRouter();
 const state = reactive({
 	entranceList: <EmptyArrayType>[], // 常用入口
@@ -128,221 +33,6 @@ const state = reactive({
 	entranceLoading: false, //入口
 	noticeLoading: false, // 公告
 });
-const entranceRef = ref<RefType>(); // 常用入口ref
-// 自定义入口
-const customEntry = () => {
-	entranceRef.value.openDialog();
-};
-//获取入口设置
-const getEntrance = () => {
-	state.entranceLoading = true;
-	geFastMenu()
-		.then((res: any) => {
-			state.entranceList = res?.result ?? [];
-			state.entranceLoading = false;
-		})
-		.catch(() => {
-			state.entranceLoading = false;
-		});
-};
-const activeName = ref<string>('0'); // tab切换
-// 知识库公告切换
-const handleClick = (val: string) => {
-  state.noticeLoading = true;
-  state.noticeList = [];
-  switch (val) {
-    case '0':
-      KnowledgePaged({ PageIndex: 1, PageSize: 10 })
-          .then((response: any) => {
-            state.noticeList = response?.result.items ?? [];
-            state.noticeLoading = false;
-          })
-          .catch(() => {
-            state.noticeLoading = false;
-          });
-      break;
-    case '1':
-      state.noticeLoading = false;
-      break;
-    default:
-      break;
-  }
-};
-// 知识库和通知公告详情
-const goLink = (item:any)=>{
-  switch (activeName.value) {
-    case '0':
-      router.push({
-        name: 'knowledgePreview',
-        params: {
-          id: item.id,
-          tagsViewName: '知识查看',
-        },
-      });
-      break;
-      case '1':
-        // const tagsViewName = listType.value === '0' ? '通知详情' : '公告详情';
-        router.push({
-          name: 'auxiliaryNoticeDetail',
-          params: {
-            id: item.id,
-            isRead: 0,
-            tagsViewName:'通知详情',
-          },
-        });
-        break;
-  }
-}
-// 更多
-const more = (val: string) => {
-	switch (val) {
-		case '0':
-			router.push({ path: '/knowledge/index' });
-			break;
-		case '1':
-			router.push({ path: '/auxiliary/notice' });
-			break;
-		default:
-			break;
-	}
-};
-onMounted(() => {
-	getEntrance();
-	handleClick('0');
-});
 </script>
 <style lang="scss" scoped>
-.vd {
-	vertical-align: middle;
-}
-.home-container {
-	.left-content {
-		.statistics {
-			display: flex;
-			justify-content: space-between;
-			&-item {
-				height: 200px;
-				margin-bottom: 20px;
-			}
-			&-title {
-				background: var(--hotline-bg-main-color);
-				border-radius: 16px;
-				height: 60px;
-				position: relative;
-				display: flex;
-				align-items: center;
-				justify-content: center;
-				font-size: var(--el-font-size-medium);
-				img {
-					width: 83px;
-					height: 83px;
-					position: absolute;
-					left: -22px;
-					top: -2px;
-				}
-			}
-			&-number {
-				display: flex;
-				align-items: center;
-				justify-content: space-between;
-				padding: 40px 20px 0 20px;
-				text-align: center;
-				&-item-number {
-					font-size: 30px;
-				}
-				&-item-tips {
-					margin-top: 12px;
-					color: var(--hotline-color-text-main-light);
-				}
-				&-item-total {
-					flex: 1;
-					font-size: 30px;
-				}
-			}
-		}
-	}
-	.right-content {
-		.right-entrance {
-			&-title {
-				font-size: var(--el-font-size-medium);
-				display: flex;
-				align-items: center;
-				justify-content: space-between;
-				padding-bottom: 20px;
-				font-weight: 600;
-				span {
-					font-size: 14px;
-					display: flex;
-					align-items: center;
-					color: var(--el-text-color-regular);
-					cursor: pointer;
-					font-weight: normal;
-				}
-			}
-			&-list {
-				display: grid;
-				justify-content: space-between;
-				grid-template-columns: repeat(auto-fill, 110px);
-				grid-gap: 15px;
-
-				&-item {
-					background: var(--hotline-bg-main-color);
-					border-radius: 8px;
-					text-align: center;
-					width: 110px;
-					height: 110px;
-					cursor: pointer;
-					color: var(--el-text-color-regular);
-					user-select: none;
-					padding: 10px 20px;
-					.my-handle {
-						display: inline-block;
-						width: 40px;
-						height: 50px;
-						margin-top: 5px;
-						margin-bottom: 10px;
-					}
-					&:hover {
-						color: var(--el-color-primary);
-						background-color: var(--el-color-primary-light-8);
-					}
-				}
-			}
-		}
-		.right-notice {
-			position: relative;
-			.more {
-				position: absolute;
-				right: 20px;
-				top: 30px;
-				z-index: 2;
-			}
-			&-scroll {
-				height: 400px;
-				overflow: hidden;
-				&-item {
-					display: flex;
-					align-items: center;
-					justify-content: space-between;
-					border-top: 1px solid var(--el-border-color);
-					cursor: pointer;
-					height: 50px;
-					&-name {
-						flex: 1;
-						max-width: 70%;
-					}
-					&-date {
-						display: flex;
-						align-items: center;
-						color: var(--el-color-info);
-						text-align: right;
-					}
-					&:hover {
-						color: var(--el-color-primary);
-					}
-				}
-			}
-		}
-	}
-}
 </style>

+ 112 - 0
src/views/knowledge/collect/index.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="knowledge-question-container layout-pd">
+    <el-card shadow="never">
+      <el-form :model="state.queryParams" ref="ruleFormRef" :inline="true" @submit.native.prevent>
+        <el-form-item label="关键词" prop="Keyword">
+          <el-input v-model="state.queryParams.Keyword" placeholder="关键词" clearable @keyup.enter="queryList" style="width: 250px" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="queryList" :loading="state.loading"> <SvgIcon name="ele-Search" class="mr5" />查询 </el-button>
+          <el-button @click="resetQuery(ruleFormRef)" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置 </el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+    <el-card shadow="never">
+      <!-- 表格 -->
+      <el-table :data="state.tableData" v-loading="state.loading">
+        <el-table-column prop="knowledge.title" label="知识标题" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="knowledgeTypeText" label="知识分类" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="knowledge.statusText" label="知识状态" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="score" label="知识评分" show-overflow-tooltip></el-table-column>
+        <el-table-column prop="creatorName" label="收藏人" show-overflow-tooltip></el-table-column>
+        <el-table-column  label="收藏时间" show-overflow-tooltip width="170">
+          <template #default="{ row }">
+            <span>{{ formatDate(row.creationTime, 'YYYY-mm-dd HH:MM:SS') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="140" fixed="right" align="center">
+          <template #default="{ row }">
+            <el-button link type="primary" @click="onPreview(row)" v-auth="'knowledge:index:preview'" title="知识详情"> 知识详情 </el-button>
+          </template>
+        </el-table-column>
+        <template #empty>
+          <Empty />
+        </template>
+      </el-table>
+      <!-- 分页 -->
+      <pagination
+          :total="state.total"
+          v-model:page="state.queryParams.PageIndex"
+          v-model:limit="state.queryParams.PageSize"
+          @pagination="queryList"
+      />
+    </el-card>
+  </div>
+</template>
+
+<script lang="ts" setup name="knowledgeCollect">
+import { reactive, ref, onMounted } from 'vue';
+import { ElMessage, FormInstance } from 'element-plus';
+import { formatDate } from '/@/utils/formatTime';
+import { auth } from '/@/utils/authFunction';
+import {useRouter} from "vue-router";
+import {collectList} from '/@/api/knowledge/collect';
+
+// 定义变量内容
+const state = reactive<any>({
+  loading: false, // 加载状态
+  queryParams: {
+    // 查询参数
+    PageIndex: 1,
+    PageSize: 10,
+    Keyword: null, // 知识分类
+  },
+  total: 0, // 总条数
+  tableData: [], // 表格数据
+  typeData: [], // 知识分类
+});
+const ruleFormRef = ref<RefType>(null); // 表单ref
+// 获取参数列表
+const queryList = () => {
+  state.loading = true;
+  if (!auth('knowledge:collect:query')) ElMessage.error('抱歉,您没有权限获取知识收藏列表!');
+  else {
+    collectList(state.queryParams)
+        .then((res) => {
+          state.loading = false;
+          state.tableData = res.result.items ?? [];
+          state.total = res.result.total ?? 0;
+        })
+        .finally(() => {
+          state.loading = false;
+        });
+  }
+};
+// 重置表单
+const resetQuery = (formEl: FormInstance | undefined) => {
+  if (!formEl) return;
+  formEl.resetFields();
+  queryList();
+};
+// 知识详情
+const router = useRouter();
+const onPreview = (row: any) => {
+  router.push({
+    name: 'knowledgePreview',
+    params: {
+      id: row.knowledge.id,
+      tagsViewName: '知识详情',
+    },
+  });
+};
+
+// 页面加载时
+onMounted(() => {
+  queryList();
+});
+</script>
+
+<style lang="scss" scoped>
+.knowledge-question-container {
+}
+</style>

+ 1 - 1
src/views/knowledge/index/preview.vue

@@ -27,8 +27,8 @@
 				<el-divider style="margin: 15px 0" />
         正文
 				<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mt5 editor-content-view"> <div v-html="state.info.content" class="lineHeight24"></div></el-col>
-        <el-divider style="margin: 15px 0" />
         <template v-if="state.info.knowledgeDtos && state.info.knowledgeDtos.length">
+          <el-divider style="margin: 15px 0" />
           关联知识
           <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mt5">
             <div v-for="item in state.info.knowledgeDtos" @click="onPreview(item)" class="relevance">

+ 125 - 116
src/views/knowledge/retrieval/index.vue

@@ -78,24 +78,45 @@
 
 				<el-col :xs="12" :sm="12" :md="14" :lg="14" :xl="14" class="center-container">
 					<div class="input-box">
-						<el-select v-model="state.queryParams.RetrievalType" placeholder="请选择" style="width: 120px">
-							<el-option v-for="item in state.typeList" :key="item.value" :label="item.label" :value="item.value" class="w1" />
+						<el-select v-model="state.queryParams.RetrievalType" placeholder="请选择" style="width: 120px" @change="queryList">
+							<el-option label="全文" :value="0" />
+							<el-option label="标题" :value="1" />
+							<el-option label="知识内容" :value="2" />
+							<el-option label="摘要" :value="3" />
 						</el-select>
 						<div class="input-with-button w100">
 							<div class="flex">
-                <el-autocomplete
-                    v-model="state.queryParams.Keyword"
-                    :fetch-suggestions="querySearchAsync"
-                    placeholder="关键词"
-                    @select="handleSelect"
-                    class="mr10 w100"
-                    clearable
-                    value-key="title"
-                >
-                </el-autocomplete>
-                <el-button type="primary" class="btn" :loading="state.loading" @click="queryList"><SvgIcon name="ele-Search" class="mr5" />搜索</el-button>
-                <el-button @click="resetQuery" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置</el-button>
-              </div>
+								<el-autocomplete
+									v-model="state.queryParams.Keyword"
+									:fetch-suggestions="querySearchAsync"
+									placeholder="关键词"
+									@select="handleSelect"
+									class="mr10 w100"
+									clearable
+                  value-key="title"
+								>
+									<template #default="{ item }">
+										<template v-if="state.queryParams.RetrievalType === 0">
+											<div class="text-no-wrap">{{ item.title }}</div>
+											<span class="text-no-wrap color-info">{{ item.summary }}</span>
+										</template>
+										<template v-if="state.queryParams.RetrievalType === 1">
+											<div class="text-no-wrap">{{ item.title }}</div>
+										</template>
+										<template v-if="state.queryParams.RetrievalType === 2">
+											<div class="text-no-wrap">{{ item.title }}</div>
+											<span class="text-no-wrap color-info">{{ item.summary }}</span>
+										</template>
+										<template v-if="state.queryParams.RetrievalType === 3">
+											<span class="text-no-wrap color-info">{{ item.summary }}</span>
+										</template>
+									</template>
+								</el-autocomplete>
+								<el-button type="primary" class="btn" :loading="state.loading" @click="queryList"
+									><SvgIcon name="ele-Search" class="mr5" />搜索</el-button
+								>
+								<el-button @click="resetQuery" class="default-button"> <SvgIcon name="ele-Refresh" class="mr5" />重置</el-button>
+							</div>
 							<div class="flex-center-align mt5">
 								<div style="height: 32px; line-height: 32px">排序:</div>
 								<el-radio-group v-model="state.queryParams.Sort" @change="queryList">
@@ -111,18 +132,18 @@
 							<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">{{ 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 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>
@@ -141,7 +162,7 @@
 				<el-col :xs="6" :sm="6" :md="6" :lg="6" :xl="6" class="right-container">
 					<p class="flex-center-between pt10">
 						<span class="font16">常用知识前10</span>
-						<el-button link type="primary" @click="onRefresh"><SvgIcon name="ele-Refresh" class="mr4" /> 刷新</el-button>
+						<el-button link type="primary" @click="querySearchNum"><SvgIcon name="ele-Refresh" class="mr4" /> 刷新</el-button>
 					</p>
 					<el-divider />
 					<p class="flex-center-between">
@@ -155,7 +176,7 @@
 									<p class="flex-center-align top10-items-title" @click="onPreview(item)">
 										{{ index + 1 }}.<el-link type="primary" :underline="false">{{ item.title }}</el-link>
 									</p>
-									<span class="top10-items-num">{{ item.num }}</span>
+									<span class="top10-items-num">{{ item.searchNum }}</span>
 								</div>
 							</el-scrollbar>
 						</template>
@@ -172,9 +193,9 @@
 <script setup lang="ts" name="knowledgeRetrieval">
 import { onMounted, reactive, ref, watch } from 'vue';
 import { useRouter } from 'vue-router';
-import {ElMessage, FormInstance} from 'element-plus';
+import { ElMessage } from 'element-plus';
 import { auth } from '/@/utils/authFunction';
-import { knowledgeRetrieval } from '/@/api/knowledge/retrieval';
+import { knowledgeRetrieval, searchNumList,searchNumAdd } from '/@/api/knowledge/retrieval';
 import { hotSpotType } from '/@/api/business/order';
 import { getOrgList } from '/@/api/system/organize';
 import { treeList } from '/@/api/knowledge/type';
@@ -186,36 +207,17 @@ const state = reactive<any>({
 		// 查询条件
 		PageIndex: 1, // 当前页
 		PageSize: 10, // 每页条数
-    Attribution: ' ',
+		Attribution: ' ',
 		Keyword: null, // 关键词
 		RetrievalType: 0, // 检索类型
-    Sort: '1',
+		Sort: '1',
 	},
 	activeName: '0',
 	orgData: [], // 部门
 	knowledgeOptions: [], // 知识类型
 	total: 0, // 总条数
 	loading: false, // 加载状态
-	typeList: [
-		// 检索类型
-		{
-			label: '全文',
-			value: 0,
-		},
-		{
-			label: '标题',
-			value: 1,
-		},
-    {
-      label: '知识内容',
-      value: 2,
-    },
-		{
-			label: '摘要',
-			value: 3,
-		}
-	],
-	retrievalList: [],	// 检索列表
+	retrievalList: [], // 检索列表
 });
 const router = useRouter(); // 路由
 const topList = ref<EmptyArrayType>([]); // 常用知识前10
@@ -304,51 +306,58 @@ const onPreview = (row: any) => {
 };
 // 切换tab 查询列表
 const rightLoading = ref(false); // 右侧加载状态
-const onRefresh = () => {
+// 常用知识前10
+const querySearchNum = () => {
 	rightLoading.value = true;
-	setTimeout(() => {
-		rightLoading.value = false;
-	}, 1000);
+	searchNumList({ Keyword: state.queryParams.Keyword })
+		.then((res: any) => {
+			topList.value = res.result?.items ?? [];
+			rightLoading.value = false;
+		})
+		.catch(() => {
+			rightLoading.value = false;
+		});
 };
 const queryTitleLight = (titleInfo: string) => {
 	return titleInfo.replace(new RegExp(state.queryParams.Keyword, 'g'), `<span class="color-danger">${state.queryParams.Keyword}</span>`);
 };
 const centerLoading = ref(false); // 中间加载状态
 const querySearchAsync = (queryString: string, cb: (arg: any) => void) => {
-  if (queryString) {
-    centerLoading.value = true;
-    knowledgeRetrieval({
-      ...state.queryParams,
-      Keyword: queryString,
-    })
-      .then((res: any) => {
-        centerLoading.value = false;
-        cb(res.result?.items ?? []);
-      })
-      .catch(() => {
-        centerLoading.value = false;
-        cb([]);
-      });
-  } else {
-    cb([]);
-  }
-}
+	if (queryString) {
+		centerLoading.value = true;
+		knowledgeRetrieval({
+			...state.queryParams,
+			Keyword: queryString,
+		})
+			.then((res: any) => {
+				centerLoading.value = false;
+				cb(res.result?.items ?? []);
+			})
+			.catch(() => {
+				centerLoading.value = false;
+				cb([]);
+			});
+	} else {
+		cb([]);
+	}
+};
 const handleSelect = (item: Record<string, any>) => {
-  state.queryParams.Keyword = item.title;
-  queryList();
-}
+	state.queryParams.Keyword = item.title;
+  searchNumAdd({id: item.id});
+	queryList();
+};
 const queryList = () => {
 	if (!auth('knowledge:retrieval')) ElMessage.error('抱歉,您没有权限知识检索');
 	else {
-    centerLoading.value = true;
+		centerLoading.value = true;
 		knowledgeRetrieval(state.queryParams)
 			.then((res: any) => {
 				state.retrievalList = res.result?.items ?? [];
 				state.total = res.result?.total ?? 0;
-        centerLoading.value = false;
+				centerLoading.value = false;
 			})
 			.catch(() => {
-        centerLoading.value = false;
+				centerLoading.value = false;
 				state.retrievalList = [];
 				state.total = 0;
 			});
@@ -356,27 +365,28 @@ const queryList = () => {
 };
 /** 重置按钮操作 */
 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 = '0';
-  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();
+	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 = '0';
+	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();
 }, 500);
 onMounted(() => {
 	getOrgListApi();
-  queryList();
+	queryList();
+	querySearchNum();
 });
 </script>
 
@@ -392,24 +402,24 @@ onMounted(() => {
 		.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);
-        }
-      }
-    }
+		.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%;
+		height: 100%;
 		.top10 {
 			&-items {
 				margin-bottom: 20px;
@@ -436,6 +446,5 @@ onMounted(() => {
 	:deep(.el-card__body) {
 		height: 100%;
 	}
-
 }
 </style>