Kaynağa Gözat

修改目录及页面

yangg 8 ay önce
ebeveyn
işleme
175a8bbb32

+ 1 - 1
.env.development

@@ -2,5 +2,5 @@
 ENV = 'development'
 port = 8080
 # base api
-VUE_APP_BASE_API = 'http://58.246.234.210:8084'
+VUE_APP_BASE_API = 'http://192.168.1.199:8084'
 #192.168.1.199

+ 1 - 1
package.json

@@ -17,6 +17,7 @@
   "dependencies": {
     "@handsontable-pro/vue": "^3.1.1",
     "@handsontable/vue": "^14.1.0",
+    "@jiaminghi/data-view": "^2.10.0",
     "axios": "0.18.1",
     "ckeditor4": "^4.23.0",
     "ckeditor4-vue": "^3.0.0",
@@ -62,7 +63,6 @@
     "vue": "2.6.10",
     "vue-class-component": "^7.2.6",
     "vue-count-to": "1.0.13",
-    "vue-data-ui": "^2.3.25",
     "vue-property-decorator": "^9.1.2",
     "vue-router": "^3.5.3",
     "vue-splitpane": "1.0.4",

+ 9 - 1
src/components/webAi/css/ChatBox.css

@@ -3,6 +3,7 @@
     position: relative;
     display: flex;
     flex-direction: column;
+    margin: 10px 20px 0;
     margin-bottom: 150px;
      /* 或者按照实际需要调整高度 */
 }
@@ -70,7 +71,7 @@
 }
 .title{
   width: 90%;
-  margin: 0 auto 15px;
+ /*  margin: 0 auto 15px; */
   display: flex;
   align-items: center;
 
@@ -451,4 +452,11 @@ textarea {
 }
 .footer_right{
   color: #1296db;
+}
+
+::v-deep .el-collapse{
+  border: none;
+}
+::v-deep .el-collapse-item__wrap{
+  border-bottom: none;
 }

+ 163 - 131
src/components/webAi/index.vue

@@ -1,19 +1,21 @@
 <template>
   <div class="chat-container">
-    <div class="header" style="margin-top: 15px" v-if="$route.name !== 'ai'">
-      <el-form
-        :inline="true"
-        :model="AIform"
-        :rules="rules"
-        ref="AIformRef"
-        class="demo-form-inline"
-        style="margin-top: 15px"
-        label-position="right"
-        label-width="90px"
-      >
-        <el-row :gutter="24">
-          <el-col :span="8">
-            <!--  <el-form-item label="模型库:" prop="modelLibrary">
+    <el-collapse v-model="activeNames" v-if="$route.name !== 'ai'">
+      <el-collapse-item title="应用配置" name="1">
+        <div class="header" style="margin-top: 15px">
+          <el-form
+            :inline="true"
+            :model="AIform"
+            :rules="rules"
+            ref="AIformRef"
+            class="demo-form-inline"
+            style="margin-top: 15px"
+            label-position="right"
+            label-width="90px"
+          >
+            <el-row :gutter="24">
+              <el-col :span="8">
+                <!--  <el-form-item label="模型库:" prop="modelLibrary">
               <el-select
                 v-model="AIform.modelLibrary"
                 placeholder="ollama"
@@ -22,15 +24,15 @@
                 <el-option label="ollama" value="ollama"></el-option>
               </el-select>
             </el-form-item> -->
-            <el-form-item label="应用名称:" prop="chat_name">
-              <el-input
-                v-model="AIform.chat_name"
-                placeholder="请输入应用名称"
-              ></el-input>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <!-- <el-form-item label="模型类型:" prop="model_type">
+                <el-form-item label="应用名称:" prop="chat_name">
+                  <el-input
+                    v-model="AIform.chat_name"
+                    placeholder="请输入应用名称"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <!-- <el-form-item label="模型类型:" prop="model_type">
               <el-select
                 v-model="AIform.model_type"
                 placeholder="请输入选择"
@@ -39,102 +41,108 @@
                 <el-option label="chat" value="chat"></el-option>
               </el-select>
             </el-form-item> -->
-            <el-form-item label="模型名称:" prop="model_name">
-              <el-select
-                v-model="AIform.model_name"
-                placeholder="请输入选择"
-                style="width: 100%"
-              >
-                <el-option
-                  v-for="(item, index) in modelNameList"
-                  :label="item.name"
-                  :value="item.name"
-                  :key="index"
-                ></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8">
-            <el-form-item label="知识库:" prop="knowledge_base_names">
-              <el-select
-                v-model="AIform.knowledge_base_names"
-                multiple
-                placeholder="请选择知识库"
-                style="width: 100%"
-                @change="handleKnowledgeBaseChange"
-              >
-                <el-option
-                  v-for="(item, index) in kneList"
-                  :label="item.name"
-                  :value="item.id"
-                  :key="index"
-                ></el-option>
-              </el-select> </el-form-item
-          ></el-col>
-        </el-row>
-        <el-row :gutter="24">
-          <el-col :span="8">
-            <el-form-item label="文档目录:" prop="document_directories">
-              <el-select
-                v-model="AIform.document_directories"
-                placeholder="请选择文档目录"
-                style="width: 100%"
-                :disabled="!AIform.knowledge_base_names.length"
-                @change="handleDirectoryChange"
-              >
-                <el-option
-                  v-for="(dir, index) in directoryList"
-                  :label="dir.name"
-                  :value="dir.id"
-                  :key="index"
-                ></el-option>
-              </el-select> </el-form-item
-          ></el-col>
-          <el-col :span="8">
-            <el-form-item label="文  档:" prop="documents">
-              <el-select
-                v-model="AIform.documents"
-                multiple
-                placeholder="请选择文档"
-                style="width: 100%"
-                :disabled="!AIform.document_directories"
-              >
-                <el-option
-                  v-for="(doc, index) in documentList"
-                  :label="doc.name"
-                  :value="doc.id"
-                  :key="index"
-                ></el-option>
-              </el-select>
-            </el-form-item>
-          </el-col>
-          <el-col :span="8"> 
-            <el-form-item label="描 述:">
-              <el-input v-model="AIform.role_description" type="textarea" style="width: 350px;"></el-input>
-            </el-form-item> 
-          </el-col>
-        </el-row>
-      </el-form>
-      <div class="selection-summary">
-        <div class="summary-content">
-          <span class="summary-label">当前选择了:</span>
-          <p class="summary-text">
-            模型库: OLLAMA 模型类型: CHAT 模型名称:
-            <span>{{ AIform.model_name }}</span>
-          </p>
-          <p class="summary-text">
-            知识库:<span>{{ getKnowledgeBaseNames }}</span> 文档:
-            <span>{{ getDocumentNames }}</span>
-          </p>
+                <el-form-item label="模型名称:" prop="model_name">
+                  <el-select
+                    v-model="AIform.model_name"
+                    placeholder="请输入选择"
+                    style="width: 100%"
+                  >
+                    <el-option
+                      v-for="(item, index) in modelNameList"
+                      :label="item.name"
+                      :value="item.name"
+                      :key="index"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="知识库:" prop="knowledge_base_names">
+                  <el-select
+                    v-model="AIform.knowledge_base_names"
+                    multiple
+                    placeholder="请选择知识库"
+                    style="width: 100%"
+                    @change="handleKnowledgeBaseChange"
+                  >
+                    <el-option
+                      v-for="(item, index) in kneList"
+                      :label="item.name"
+                      :value="item.id"
+                      :key="index"
+                    ></el-option>
+                  </el-select> </el-form-item
+              ></el-col>
+            </el-row>
+            <el-row :gutter="24">
+              <el-col :span="8">
+                <el-form-item label="文档目录:" prop="document_directories">
+                  <el-select
+                    v-model="AIform.document_directories"
+                    placeholder="请选择文档目录"
+                    style="width: 100%"
+                    :disabled="!AIform.knowledge_base_names.length"
+                    @change="handleDirectoryChange"
+                  >
+                    <el-option
+                      v-for="(dir, index) in directoryList"
+                      :label="dir.name"
+                      :value="dir.id"
+                      :key="index"
+                    ></el-option>
+                  </el-select> </el-form-item
+              ></el-col>
+              <el-col :span="8">
+                <el-form-item label="文  档:" prop="documents">
+                  <el-select
+                    v-model="AIform.documents"
+                    multiple
+                    placeholder="请选择文档"
+                    style="width: 100%"
+                    :disabled="!AIform.document_directories"
+                  >
+                    <el-option
+                      v-for="(doc, index) in documentList"
+                      :label="doc.name"
+                      :value="doc.id"
+                      :key="index"
+                    ></el-option>
+                  </el-select>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8">
+                <el-form-item label="描 述:">
+                  <el-input
+                    v-model="AIform.role_description"
+                    type="textarea"
+                    style="width: 350px"
+                  ></el-input>
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+          <div class="selection-summary">
+            <div class="summary-content">
+              <span class="summary-label">当前选择了:</span>
+              <p class="summary-text">
+                模型库: OLLAMA 模型类型: CHAT 模型名称:
+                <span>{{ AIform.model_name }}</span>
+              </p>
+              <p class="summary-text">
+                知识库:<span>{{ getKnowledgeBaseNames }}</span> 文档:
+                <span>{{ getDocumentNames }}</span>
+              </p>
+            </div>
+            <el-button
+              type="primary"
+              class="generate-button"
+              @click="generateApplication"
+              >生成应用</el-button
+            >
+          </div>
         </div>
-        <el-button
-          type="primary"
-          class="generate-button"
-          @click="generateApplication"
-          >生成应用</el-button
-        >
-      </div>
-    </div>
+      </el-collapse-item></el-collapse
+    >
     <div class="title" v-if="$route.name !== 'ai'">
       <h1>聊天应用列表</h1>
       <!-- <span class="title_info">选择其他应用</span> -->
@@ -142,12 +150,7 @@
 
     <div class="content_card">
       <div class="card-container">
-        <div
-          class="card"
-          v-for="(card, index) in knowledgeBases"
-          :key="index"
-         
-        >
+        <div class="card" v-for="(card, index) in knowledgeBases" :key="index">
           <div class="card-header">
             <h2>{{ card.chat_name }}</h2>
             <el-dropdown>
@@ -155,6 +158,7 @@
                 <i class="el-icon-more"></i>
               </span>
               <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item @click.native="viewApplication(card)">查看</el-dropdown-item>
                 <el-dropdown-item @click.native="editApplication(card)"
                   >编辑</el-dropdown-item
                 >
@@ -182,7 +186,9 @@
               <img src="../../assets/images/u5.png" alt="" />
             </div>
             <div class="footer_right">
-              <span  @click="openChatDialog(card)" style="cursor: pointer;">进入应用</span>
+              <span @click="openChatDialog(card)" style="cursor: pointer"
+                >进入应用</span
+              >
               <span style="margin-left: 20px">默认选择</span>
             </div>
             <!-- <span class="update-time"></span> -->
@@ -270,11 +276,11 @@
         <el-row :gutter="24">
           <el-col :span="8">
             <el-form-item label="应用名称:" prop="chat_name">
-          <el-input
-            v-model="editForm.chat_name"
-            placeholder="请输入应用名称"
-          ></el-input>
-        </el-form-item>
+              <el-input
+                v-model="editForm.chat_name"
+                placeholder="请输入应用名称"
+              ></el-input>
+            </el-form-item>
             <!-- <el-form-item label="模型库:" prop="modelLibrary">
               <el-select
                 v-model="editForm.modelLibrary"
@@ -373,7 +379,11 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="描 述:">
-              <el-input v-model="editForm.role_description" type="textarea" style="width: 350px;"></el-input>
+              <el-input
+                v-model="editForm.role_description"
+                type="textarea"
+                style="width: 350px"
+              ></el-input>
             </el-form-item>
           </el-col>
         </el-row>
@@ -383,6 +393,28 @@
         <el-button type="primary" @click="submitEdit">确 定</el-button>
       </span>
     </el-dialog>
+    <!-- 查看 -->
+    <el-dialog
+      title="应用详情"
+      :visible.sync="viewDialogVisible"
+      width="80%"
+      :append-to-body="true"
+    >
+      <div v-if="viewForm" style="padding:0 20px;">
+        <p><strong>应用名称:</strong> {{ viewForm.chat_name }}</p>
+        <p><strong>模型名称:</strong> {{ viewForm.model_name }}</p>
+        <p>
+          <strong>知识库:</strong>
+          {{ viewForm.knowledge_base_names.join(", ") }}
+        </p>
+        <p>
+          <strong>文档目录:</strong>
+          {{ viewForm.document_directories.join(", ") }}
+        </p>
+        <p><strong>文档:</strong> {{ viewForm.documents.join(", ") }}</p>
+        <p><strong>描述:</strong> {{ viewForm.role_description }}</p>
+      </div>
+    </el-dialog>
     <!-- 添加 LoginModal 组件 -->
     <LoginModal
       :visible.sync="showLoginModal"

+ 10 - 0
src/components/webAi/js/ChatBox.js

@@ -11,6 +11,7 @@ export default {
   },
   data() {
     return {
+      activeNames: ['0'],
       isThinking: false,
       thinkingDots: '',
       messages: [
@@ -120,6 +121,9 @@ export default {
       },
       editDirectoryList: [],
       editDocumentList: [],
+      /* 查看 */
+      viewDialogVisible: false,
+      viewForm: null,
     };
   },
   created() {
@@ -166,6 +170,12 @@ export default {
     }
   },
   methods: {
+    /* 查看 */
+    viewApplication(card) {
+      this.viewForm = { ...card };
+      this.viewDialogVisible = true;
+    },
+
     /* 删除 */
     deleteApplication(card) {
       this.$confirm('确定要删除这个应用吗?', '提示', {

+ 1 - 1
src/icons/svg/AI.svg

@@ -1 +1 @@
-<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1725526739339" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5795" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24"><path d="M354.40128 0c-87.04 0-157.44 70.55872-157.44 157.59872v275.68128H78.72c-21.6576 0-39.36256 17.69984-39.36256 39.36256v236.31872c0 21.6576 17.69984 39.35744 39.36256 39.35744h118.24128v118.08256c0 87.04 70.4 157.59872 157.44 157.59872h472.63744c87.04 0 157.59872-70.55872 157.59872-157.59872V315.0336c0-41.74848-38.9888-81.93024-107.52-149.27872l-29.11744-29.12256L818.87744 107.52C751.5392 38.9888 711.39328 0 669.59872 0H354.4064z m0 78.72h287.20128c28.35456 7.0912 27.99616 42.1376 27.99616 76.8v120.16128c0 21.6576 17.69984 39.35744 39.36256 39.35744h118.07744c39.38816 0 78.87872-0.0256 78.87872 39.36256v512c0 43.32032-35.55328 78.87872-78.87872 78.87872H354.4064c-43.32544 0-78.72-35.5584-78.72-78.87872v-118.08256h393.91744c21.66272 0 39.36256-17.69472 39.36256-39.35744V472.64256c0-21.66272-17.69984-39.36256-39.36256-39.36256H275.68128V157.59872c0-43.32032 35.39456-78.87872 78.72-78.87872z m-25.92256 427.67872h20.16256l65.28 176.64h-23.04l-19.2-54.71744h-65.28l-19.2 54.71744h-23.04l64.31744-176.64z m95.04256 0.96256H487.8336v12.47744l-21.12 4.80256v141.11744l21.12 4.80256v12.47744H423.5264v-12.47744l21.12-4.80256V524.6464l-21.12-4.80256v-12.47744z m-84.48 23.04c-1.92 8.96-4.80256 18.23744-8.64256 27.83744l-17.28 50.88256h51.84l-18.23744-50.88256c-3.84-10.88-6.4-20.15744-7.68-27.83744z" p-id="5796" fill="#2c2c2c"></path></svg>
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1729073804644" class="icon" viewBox="0 0 1052 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="14601" xmlns:xlink="http://www.w3.org/1999/xlink" width="24.65625" height="24"><path d="M725.333333 355.555556a56.888889 56.888889 0 0 1 56.888889 56.888888v341.333334a56.888889 56.888889 0 0 1-56.888889 56.888889h-398.222222a56.888889 56.888889 0 0 1-56.888889-56.888889v-341.333334a56.888889 56.888889 0 0 1 56.888889-56.888888h398.222222z m-398.222222-56.888889a113.777778 113.777778 0 0 0-113.777778 113.777777v341.333334a113.777778 113.777778 0 0 0 113.777778 113.777778h398.222222a113.777778 113.777778 0 0 0 113.777778-113.777778v-341.333334a113.777778 113.777778 0 0 0-113.777778-113.777777h-398.222222zM890.908444 512a28.444444 28.444444 0 1 1 56.888889 0v142.222222a28.444444 28.444444 0 1 1-56.888889 0v-142.222222z" fill="#000000" p-id="14602"></path><path d="M497.777778 192.113778a28.444444 28.444444 0 1 1 56.888889 0v113.777778a28.444444 28.444444 0 1 1-56.888889 0v-113.777778zM104.647111 512a28.444444 28.444444 0 1 1 56.888889 0v142.222222a28.444444 28.444444 0 1 1-56.888889 0v-142.222222z" fill="#000000" p-id="14603"></path><path d="M597.333333 163.669333a71.111111 71.111111 0 1 1-142.222222 0 71.111111 71.111111 0 0 1 142.222222 0zM455.111111 583.111111a42.666667 42.666667 0 1 1-85.333333 0 42.666667 42.666667 0 0 1 85.333333 0zM682.666667 583.111111a42.666667 42.666667 0 1 1-85.333334 0 42.666667 42.666667 0 0 1 85.333334 0z" fill="#000000" p-id="14604"></path></svg>

+ 1 - 1
src/views/chatPage/index.vue

@@ -56,7 +56,7 @@
 }
 ::v-deep .title {
   width: 98%;
-  margin: 0 20px 15px;
+  /* margin: 0 20px 15px; */
   display: flex;
   align-items: center;
 }

+ 116 - 60
src/views/dashboard/admin/components/BarChart.vue

@@ -1,102 +1,158 @@
 <template>
-  <div :class="className" :style="{height:height,width:width}" />
+  <div :class="className" :style="{ height: height, width: width }" />
 </template>
 
 <script>
-import echarts from 'echarts'
-require('echarts/theme/macarons')
-import resize from './mixins/resize'
-
-const animationDuration = 6000
+import echarts from "echarts";
+require("echarts/theme/macarons");
+import resize from "./mixins/resize";
 
 export default {
   mixins: [resize],
   props: {
     className: {
       type: String,
-      default: 'chart'
+      default: "chart"
     },
     width: {
       type: String,
-      default: '100%'
+      default: "100%"
     },
     height: {
       type: String,
-      default: '300px'
+      default: "350px"
     }
   },
   data() {
     return {
-      chart: null
-    }
+      chart: null,
+      chartData: [
+        {
+          category: "Customer",
+          Document: 8,
+          Video: 77,
+          Audio: 22,
+          Image: 76,
+          Text: 11,
+          Other: 88
+        },
+        {
+          category: "Developer",
+          Document: 23,
+          Video: 52,
+          Audio: 80,
+          Image: 30,
+          Text: 22,
+          Other: 20
+        },
+        {
+          category: "Manager",
+          Document: 98,
+          Video: 65,
+          Audio: 18,
+          Image: 92,
+          Text: 71,
+          Other: 90
+        },
+        {
+          category: "Designer",
+          Document: 93,
+          Video: 33,
+          Audio: 98,
+          Image: 10,
+          Text: 36,
+          Other: 11
+        }
+      ]
+    };
   },
   mounted() {
     this.$nextTick(() => {
-      this.initChart()
-    })
+      this.initChart();
+    });
   },
   beforeDestroy() {
     if (!this.chart) {
-      return
+      return;
     }
-    this.chart.dispose()
-    this.chart = null
+    this.chart.dispose();
+    this.chart = null;
   },
   methods: {
     initChart() {
-      this.chart = echarts.init(this.$el, 'macarons')
+      this.chart = echarts.init(this.$el, "macarons");
+
+      const categories = this.chartData.map(item => item.category);
+      const series = ["Document", "Video", "Audio", "Image", "Text", "Other"].map(type => ({
+        name: type,
+        type: "bar",
+        barWidth: "10%",
+        data: this.chartData.map(item => item[type]),
+        itemStyle: { color: this.getColor(type) }
+      }));
 
       this.chart.setOption({
         tooltip: {
-          trigger: 'axis',
-          axisPointer: { // 坐标轴指示器,坐标轴触发有效
-            type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
+          trigger: "axis",
+          axisPointer: {
+            type: "shadow"
           }
         },
+        legend: {
+          data: ["Document", "Video", "Audio", "Image", "Text", "Other"],
+          bottom: 0
+        },
         grid: {
-          top: 10,
-          left: '2%',
-          right: '2%',
-          bottom: '3%',
+          left: "3%",
+          right: "4%",
+          bottom: "10%",
+          top: "3%",
           containLabel: true
         },
-        xAxis: [{
-          type: 'category',
-          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
-          axisTick: {
-            alignWithLabel: true
+        xAxis: [
+          {
+            type: "category",
+            data: categories,
+            axisTick: { show: false },
+            axisLine: { show: false },
+            axisLabel: {
+              interval: 0,
+              align: 'center',
+              margin: 20,
+              fontSize: 14
+            },
+            axisTick: {
+              alignWithLabel: true
+            },
+            splitLine: {
+              show: true,
+              lineStyle: {
+                type: 'dashed',
+                color: '#ddd'
+              }
+            }
           }
-        }],
-        yAxis: [{
-          type: 'value',
-          axisTick: {
-            show: false
+        ],
+        yAxis: [
+          {
+            type: "value",
+            max: 100
           }
-        }],
-        series: [{
-          name: 'pageA',
-          type: 'bar',
-          stack: 'vistors',
-          barWidth: '60%',
-          data: [79, 52, 200, 334, 390, 330, 220],
-          animationDuration
-        }, {
-          name: 'pageB',
-          type: 'bar',
-          stack: 'vistors',
-          barWidth: '60%',
-          data: [80, 52, 200, 334, 390, 330, 220],
-          animationDuration
-        }, {
-          name: 'pageC',
-          type: 'bar',
-          stack: 'vistors',
-          barWidth: '60%',
-          data: [30, 52, 200, 334, 390, 330, 220],
-          animationDuration
-        }]
-      })
+        ],
+        series: series
+      });
+    },
+    getColor(type) {
+      const colorMap = {
+        Document: "#FF7B7B",
+        Video: "#9D96F5",
+        Audio: "#4ADEDE",
+        Image: "#FFA400",
+        Text: "#5D7DFF",
+        Other: "#4ADEDE"
+      };
+      return colorMap[type];
     }
   }
-}
-</script>
+};
+</script>

+ 119 - 1
src/views/dashboard/admin/components/PieChart.vue

@@ -1,4 +1,4 @@
-<template>
+<!-- <template>
   <div :class="className" :style="{height:height,width:width}" />
 </template>
 
@@ -77,3 +77,121 @@ export default {
   }
 }
 </script>
+ -->
+
+ <template>
+  <div class="pie-chart-container">
+    <div class="pie-charts">
+      <div v-for="(item, index) in data" :key="index" class="pie-chart-item">
+        <div class="pie-chart" :style="getPieChartStyle(item.value, item.itemStyle.color)">
+          <span class="pie-chart-text">{{ item.value }}%</span>
+        </div>
+      </div>
+    </div>
+    <div class="legend">
+      <div v-for="(item, index) in data" :key="index" class="legend-item">
+        <span class="color-dot" :style="{ backgroundColor: item.itemStyle.color }"></span>
+        <span>{{ item.name }}</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'PieChart',
+  data() {
+    return {
+      data: [
+        { value: 70, name: "Shopping", itemStyle: { color: "#FF9F43" } },
+        { value: 46, name: "Images", itemStyle: { color: "#5E60CE" } },
+        { value: 15, name: "Document", itemStyle: { color: "#FF6B6B" } },
+        { value: 67, name: "Audio", itemStyle: { color: "#54A0FF" } },
+        { value: 23, name: "Video", itemStyle: { color: "#FF4DFF" } },
+        { value: 88, name: "Text", itemStyle: { color: "#FF9F43" } },
+        { value: 50, name: "Other", itemStyle: { color: "#1DD1A1" } },
+      ],
+    };
+  },
+  methods: {
+    getPieChartStyle(value, color) {
+      const degree = (value / 100) * 360;
+      return {
+        background: `conic-gradient(
+          ${color} 0deg ${degree}deg,
+          rgba(0, 0, 0, 0.05) ${degree}deg 360deg
+        )`,
+      };
+    },
+  },
+};
+</script>
+
+<style scoped>
+.pie-chart-container {
+  width: 100%;
+  max-width: 800px;
+  margin: 0 auto;
+}
+
+.pie-charts {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+}
+
+.pie-chart-item {
+  width: 25%;
+  padding: 10px;
+  box-sizing: border-box;
+}
+
+.pie-chart {
+  width: 100px;
+  height: 100px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  background-color: rgba(0, 0, 0, 0.05);
+}
+
+.pie-chart::before {
+  content: '';
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  right: 10px;
+  bottom: 10px;
+  background: #ccecfe;
+  border-radius: 50%;
+}
+
+.pie-chart-text {
+  position: relative;
+  font-size: 16px;
+  font-weight: bold;
+  color: #333;
+}
+
+.legend {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  margin-top: 20px;
+}
+
+.legend-item {
+  display: flex;
+  align-items: center;
+  margin: 0 10px 10px 0;
+}
+
+.color-dot {
+  width: 10px;
+  height: 10px;
+  border-radius: 50%;
+  margin-right: 5px;
+}
+</style>

+ 60 - 0
src/views/dashboard/admin/components/recentFile.vue

@@ -0,0 +1,60 @@
+<template>
+    <div class="recent-file-list">
+      <el-table
+        :data="fileList"
+        style="width: 100%"
+        height="350"
+        :default-sort="{ prop: 'modified', order: 'descending' }"
+      >
+        <el-table-column prop="name" label="File name">
+          <template #default="scope">
+            <i :class="getFileIcon(scope.row.name)"></i>
+            {{ scope.row.name }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="size" label="Size" width="120" />
+        <el-table-column prop="modified" label="Modified" width="180" sortable />
+        <el-table-column prop="category" label="Category" width="120" />
+      </el-table>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    name: 'RecentFile',
+    data() {
+      return {
+        fileList: [
+          { name: 'dahsboard_design.fig', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'macbook_pro.jpg', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'index.html', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'code.zip', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'sound_bird.mp3', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'full_trailer_2.mp4', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+          { name: 'router.js', size: '2.4Mb', modified: 'Aug 5th,2022', category: 'Mac Image' },
+        ]
+      }
+    },
+    methods: {
+      getFileIcon(fileName) {
+        const extension = fileName.split('.').pop().toLowerCase()
+        switch (extension) {
+          case 'fig': return 'el-icon-picture'
+          case 'jpg': case 'png': return 'el-icon-picture-outline'
+          case 'html': return 'el-icon-document'
+          case 'zip': return 'el-icon-folder'
+          case 'mp3': return 'el-icon-headset'
+          case 'mp4': return 'el-icon-video-camera'
+          case 'js': return 'el-icon-tickets'
+          default: return 'el-icon-document'
+        }
+      }
+    }
+  }
+  </script>
+  
+  <style scoped>
+  .recent-file-list {
+    /* Add any additional styling here */
+  }
+  </style>

+ 35 - 0
src/views/dashboard/admin/components/tagCloud.vue

@@ -0,0 +1,35 @@
+<template>
+    <div class="tag-cloud">
+      <span v-for="tag in tags" :key="tag" class="tag">
+        {{ tag }}
+      </span>
+    </div>
+  </template>
+  
+  <script>
+  export default {
+    name: 'TagCloud',
+    props: {
+      tags: {
+        type: Array,
+        required: true
+      }
+    }
+  }
+  </script>
+  
+  <style scoped>
+  .tag-cloud {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 10px;
+  }
+  
+  .tag {
+    background-color: #e8edf2;
+    color: #7e7e8f;
+    padding: 10px 18px;
+    border-radius: 50px;
+    font-size: 10px;
+  }
+  </style>

+ 74 - 28
src/views/dashboard/admin/index.vue

@@ -2,45 +2,82 @@
   <div class="dashboard-editor-container">
     <!-- <github-corner class="github-corner" /> -->
 
-    <panel-group @handleSetLineChartData="handleSetLineChartData" />
-   <transaction-table />
-<!-- <BarChart></BarChart> -->
+    <!--  <panel-group @handleSetLineChartData="handleSetLineChartData" />-->
+    <el-row :gutter="20">
+      <el-col :span="16">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>知识库构成</span>
+          </div>
+          <BarChart style="height: 350px;"></BarChart>
+        </el-card>
+      </el-col>
+      <el-col :span="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>文件种类占比</span>
+          </div>
+          <pie-chart style="height: 350px;"/>
+        </el-card>
+      </el-col>
+    </el-row>
+    <el-row :gutter="20" style="margin-top: 20px;">
+      <el-col :span="8">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>知识库热门标签</span>
+          </div>
+          <TagCloud :tags="tags"  />
+        </el-card>
+      </el-col>
+      <el-col :span="16">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>最近访问的文件</span>
+          </div>
+          <RecentFile style="height: 350px;"/>
+        </el-card>
+      </el-col>
+    </el-row>
 
+    <transaction-table />
   </div>
 </template>
 
 <script>
-import GithubCorner from '@/components/GithubCorner'
-import PanelGroup from './components/PanelGroup'
-import LineChart from './components/LineChart'
-import RaddarChart from './components/RaddarChart'
-import PieChart from './components/PieChart'
-import BarChart from './components/BarChart'
-import TransactionTable from './components/TransactionTable'
-import TodoList from './components/TodoList'
-import BoxCard from './components/BoxCard'
+import GithubCorner from "@/components/GithubCorner";
+import PanelGroup from "./components/PanelGroup";
+import LineChart from "./components/LineChart";
+import RaddarChart from "./components/RaddarChart";
+import PieChart from "./components/PieChart";
+import BarChart from "./components/BarChart";
+import TransactionTable from "./components/TransactionTable";
+import TodoList from "./components/TodoList";
+import BoxCard from "./components/BoxCard";
+import TagCloud from './components/tagCloud.vue'
+import RecentFile from './components/recentFile.vue'
 
 const lineChartData = {
   newVisitis: {
     expectedData: [100, 120, 161, 134, 105, 160, 165],
-    actualData: [120, 82, 91, 154, 162, 140, 145]
+    actualData: [120, 82, 91, 154, 162, 140, 145],
   },
   messages: {
     expectedData: [200, 192, 120, 144, 160, 130, 140],
-    actualData: [180, 160, 151, 106, 145, 150, 130]
+    actualData: [180, 160, 151, 106, 145, 150, 130],
   },
   purchases: {
     expectedData: [80, 100, 121, 104, 105, 90, 100],
-    actualData: [120, 90, 100, 138, 142, 130, 130]
+    actualData: [120, 90, 100, 138, 142, 130, 130],
   },
   shoppings: {
     expectedData: [130, 140, 141, 142, 145, 150, 160],
-    actualData: [120, 82, 91, 154, 162, 140, 130]
-  }
-}
+    actualData: [120, 82, 91, 154, 162, 140, 130],
+  },
+};
 
 export default {
-  name: 'DashboardAdmin',
+  name: "DashboardAdmin",
   components: {
     GithubCorner,
     PanelGroup,
@@ -50,26 +87,29 @@ export default {
     BarChart,
     TransactionTable,
     TodoList,
-    BoxCard
+    BoxCard,
+    TagCloud,
+    RecentFile
   },
   data() {
     return {
-      lineChartData: lineChartData.newVisitis
-    }
+      lineChartData: lineChartData.newVisitis,
+      tags: ['Figma', 'Adobe XD', 'PSD Editor', 'Employer', 'Online Jobs', 'Remote Work', 'Salary', 'Tips', 'Income', 'Develop', 'App', 'Digital', 'Marketing', 'CEO']
+    };
   },
   methods: {
     handleSetLineChartData(type) {
-      this.lineChartData = lineChartData[type]
-    }
-  }
-}
+      this.lineChartData = lineChartData[type];
+    },
+  },
+};
 </script>
 
 <style lang="scss" scoped>
 .dashboard-editor-container {
   padding: 32px;
   min-height: 100%;
-/*   background-color: rgb(240, 242, 245); */
+  /*   background-color: rgb(240, 242, 245); */
   position: relative;
 
   .github-corner {
@@ -78,6 +118,12 @@ export default {
     border: 0;
     right: 0;
   }
+  .clearfix{
+    span{
+      font-size: 16px;
+      font-weight: 600;
+    }
+  }
 
   .chart-wrapper {
     background: #fff;
@@ -86,7 +132,7 @@ export default {
   }
 }
 
-@media (max-width:1024px) {
+@media (max-width: 1024px) {
   .chart-wrapper {
     padding: 8px;
   }

+ 1 - 1
src/views/document/com/menus.vue

@@ -236,7 +236,7 @@ export default {
             {
               key: "ai",
               name: "AI模块",
-              icon: "AI模块",
+              icon: "AI",
             },
             /*  {
                 key:"aiEs",