瀏覽代碼

修改登录页及首页新增项目管理页面并添加根据接口获取项目输入列表信息

yangg 8 月之前
父節點
當前提交
33ccf1ed63
共有 57 個文件被更改,包括 1071 次插入450 次删除
  1. 1 1
      .env.development
  2. 0 0
      dist/index.html
  3. 0 0
      dist/static/css/app.6ea77193.css
  4. 0 0
      dist/static/css/chunk-043b1151.79985b25.css
  5. 0 0
      dist/static/css/chunk-04ba33be.e30e9787.css
  6. 1 0
      dist/static/css/chunk-07b076ac.1ffa2008.css
  7. 0 0
      dist/static/css/chunk-293ff8b0.21a1df1a.css
  8. 0 1
      dist/static/css/chunk-3154a7cd.ac5ab027.css
  9. 0 0
      dist/static/css/chunk-5bc2c8fb.dd9f2d1a.css
  10. 1 0
      dist/static/css/chunk-6b1eb1ea.e30e9787.css
  11. 0 0
      dist/static/css/chunk-727cb4e9.6f8877c6.css
  12. 0 0
      dist/static/css/chunk-77a58a9f.1d59ca2f.css
  13. 1 0
      dist/static/css/chunk-94c1ef28.88a762a9.css
  14. 0 0
      dist/static/js/app.3b96737d.js
  15. 0 0
      dist/static/js/app.50c59add.js
  16. 0 0
      dist/static/js/chunk-043b1151.9a6904ec.js
  17. 0 0
      dist/static/js/chunk-04ba33be.f6b73bba.js
  18. 0 0
      dist/static/js/chunk-07b076ac.20d1147b.js
  19. 0 0
      dist/static/js/chunk-138f7583.d7e12a33.js
  20. 0 0
      dist/static/js/chunk-276e7119.f3055277.js
  21. 0 0
      dist/static/js/chunk-293ff8b0.cf41af87.js
  22. 0 0
      dist/static/js/chunk-3154a7cd.f57c0e47.js
  23. 0 0
      dist/static/js/chunk-386d37cb.4ebc1a30.js
  24. 0 0
      dist/static/js/chunk-3d8a6649.94c920fe.js
  25. 0 0
      dist/static/js/chunk-4ac7f82e.22be1c79.js
  26. 0 0
      dist/static/js/chunk-4ac7f82e.d3ae498c.js
  27. 0 0
      dist/static/js/chunk-5bc2c8fb.630ca21e.js
  28. 0 0
      dist/static/js/chunk-5c105b45.5c2ad2c5.js
  29. 0 0
      dist/static/js/chunk-632c3578.869f67c1.js
  30. 0 0
      dist/static/js/chunk-6b1eb1ea.34dc52ed.js
  31. 0 0
      dist/static/js/chunk-708604c0.61df9e1c.js
  32. 0 0
      dist/static/js/chunk-712c0160.bf7ef4df.js
  33. 0 0
      dist/static/js/chunk-727cb4e9.cef6e336.js
  34. 0 0
      dist/static/js/chunk-77a58a9f.b7849931.js
  35. 0 0
      dist/static/js/chunk-7bb2ee4e.ee008593.js
  36. 0 0
      dist/static/js/chunk-9235c1ae.68c75969.js
  37. 0 0
      dist/static/js/chunk-9235c1ae.ff5eeec8.js
  38. 0 0
      dist/static/js/chunk-94c1ef28.8a49a277.js
  39. 0 0
      dist/static/js/chunk-b9d5d1c4.8122833a.js
  40. 0 0
      dist/static/js/chunk-b9d5d1c4.ed2702ab.js
  41. 0 0
      dist/static/js/chunk-d09dbc1a.15e9f254.js
  42. 0 0
      dist/static/js/chunk-d4c547ca.1741e83f.js
  43. 0 0
      dist/static/js/chunk-d9ef2ea8.65a0dbe6.js
  44. 0 0
      dist/static/js/chunk-ec55d346.a898277d.js
  45. 33 0
      src/api/knowledge.js
  46. 1 1
      src/components/chartIcon/index.vue
  47. 2 2
      src/router/index.js
  48. 3 1
      src/store/index.js
  49. 26 0
      src/store/modules/project.js
  50. 102 33
      src/views/dashboard/admin/chart.vue
  51. 81 10
      src/views/document/com/components/sourceEs/index.vue
  52. 0 6
      src/views/document/com/menus.vue
  53. 97 69
      src/views/login/index.vue
  54. 191 184
      src/views/project/components/dataInfo.vue
  55. 4 4
      src/views/project/components/dataList.vue
  56. 4 4
      src/views/role/components/dataInfo.vue
  57. 523 134
      src/views/templateLoca/index.vue

+ 1 - 1
.env.development

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

文件差異過大導致無法顯示
+ 0 - 0
dist/index.html


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/app.6ea77193.css


文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/chunk-043b1151.79985b25.css


+ 0 - 0
dist/static/css/chunk-d4c547ca.e30e9787.css → dist/static/css/chunk-04ba33be.e30e9787.css


+ 1 - 0
dist/static/css/chunk-07b076ac.1ffa2008.css

@@ -0,0 +1 @@
+.sub-imgs{padding:0;margin:0}.sub-imgs li{float:left;margin-right:10px;width:100px;height:100px;list-style:none}.avatar-uploader .avatar{width:178px;height:178px;display:block}.avatar-uploader .el-upload{border:1px dashed var(--el-border-color);border-radius:6px;cursor:pointer;position:relative;overflow:hidden;-webkit-transition:var(--el-transition-duration-fast);transition:var(--el-transition-duration-fast)}.avatar-uploader .el-upload:hover{border-color:var(--el-color-primary)}.el-icon.avatar-uploader-icon{font-size:28px;color:#8c939d;width:178px;height:178px;text-align:center}.data-search{padding:20px 10px 0 10px}.data-list .btns,.data-list .page-info{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.data-list .page-info{margin-top:10px}.data-list .page-info .opt{width:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.data-list .page-info .opt .pick{width:100px}.data-list .page-info .opt .section{margin-left:10px}.data-list .page-info .page-data{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.data-list .page-info .page-data .page-item{width:100%}.data-list .page-info .page-data .page-opt{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.project-search{padding:30px;font-size:12px}

文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/chunk-293ff8b0.21a1df1a.css


+ 0 - 1
dist/static/css/chunk-3154a7cd.ac5ab027.css

@@ -1 +0,0 @@
-.template-location-container[data-v-1cb16a0f]{padding:20px}.operation-bar[data-v-1cb16a0f]{margin-bottom:20px}.pagination-container[data-v-1cb16a0f]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:end}

文件差異過大導致無法顯示
+ 0 - 0
dist/static/css/chunk-5bc2c8fb.dd9f2d1a.css


+ 1 - 0
dist/static/css/chunk-6b1eb1ea.e30e9787.css

@@ -0,0 +1 @@
+.sub-imgs{padding:0;margin:0}.sub-imgs li{float:left;margin-right:10px;width:100px;height:100px;list-style:none}.data-search{padding:20px 10px 0 10px}.data-list .btns,.data-list .page-info{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.data-list .page-info{margin-top:10px}.data-list .page-info .opt{width:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.data-list .page-info .opt .pick{width:100px}.data-list .page-info .opt .section{margin-left:10px}.data-list .page-info .page-data{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.data-list .page-info .page-data .page-item{width:100%}.data-list .page-info .page-data .page-opt{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.project-search{padding:30px;font-size:12px}

+ 0 - 0
dist/static/css/chunk-d09dbc1a.6f8877c6.css → dist/static/css/chunk-727cb4e9.6f8877c6.css


+ 0 - 0
dist/static/css/chunk-712c0160.1d59ca2f.css → dist/static/css/chunk-77a58a9f.1d59ca2f.css


+ 1 - 0
dist/static/css/chunk-94c1ef28.88a762a9.css

@@ -0,0 +1 @@
+.project-selector[data-v-f84941e4]{margin-bottom:20px}.template-location-container[data-v-f84941e4]{padding:20px}.operation-bar[data-v-f84941e4]{margin-bottom:20px}.pagination-container[data-v-f84941e4]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:end}.delete-warning[data-v-f84941e4]{padding:12px 16px;background-color:#fdf6ec;border-radius:4px;color:#e6a23c;line-height:1.4;font-size:14px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}[data-v-f84941e4] .el-tabs__nav-wrap:after{width:13%}

文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/app.3b96737d.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/app.50c59add.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-043b1151.9a6904ec.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-04ba33be.f6b73bba.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-07b076ac.20d1147b.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-138f7583.d7e12a33.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-276e7119.f3055277.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-293ff8b0.cf41af87.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-3154a7cd.f57c0e47.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-386d37cb.4ebc1a30.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-3d8a6649.94c920fe.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-4ac7f82e.22be1c79.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-4ac7f82e.d3ae498c.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-5bc2c8fb.630ca21e.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-5c105b45.5c2ad2c5.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-632c3578.869f67c1.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-6b1eb1ea.34dc52ed.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-708604c0.61df9e1c.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-712c0160.bf7ef4df.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-727cb4e9.cef6e336.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-77a58a9f.b7849931.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-7bb2ee4e.ee008593.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-9235c1ae.68c75969.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-9235c1ae.ff5eeec8.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-94c1ef28.8a49a277.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-b9d5d1c4.8122833a.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-b9d5d1c4.ed2702ab.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-d09dbc1a.15e9f254.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-d4c547ca.1741e83f.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-d9ef2ea8.65a0dbe6.js


文件差異過大導致無法顯示
+ 0 - 0
dist/static/js/chunk-ec55d346.a898277d.js


+ 33 - 0
src/api/knowledge.js

@@ -608,4 +608,37 @@ export function doc_status(data) {
     method: 'get',
     data
   })
+}
+
+/* 新建项目内容  */
+
+export function create_items(data) {
+  return request({
+    timeout:100000,
+    url: 'project-input/create-items',
+    method: 'post',
+    data
+  })
+}
+
+/* 删除项目  project-input/delete-items */
+
+export function delete_items(data) {
+  return request({
+    timeout:100000,
+    url: 'project-input/delete-items',
+    method: 'post',
+    data
+  })
+}
+
+/* 更新项目 project-input/update-items */
+
+export function update_items(data) {
+  return request({
+    timeout:100000,
+    url: 'project-input/update-items',
+    method: 'post',
+    data
+  })
 }

+ 1 - 1
src/components/chartIcon/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="chat-icon" @click="toggleChat">
     <i class="el-icon-chat-dot-round animate-pulse"></i>
-    <div v-if="$store.state.app.showChat" class="chat-window" :style="chatWindowStyle" ref="chatWindow" @click.stop>
+    <div v-show="$store.state.app.showChat" class="chat-window" :style="chatWindowStyle" ref="chatWindow" @click.stop>
       <div class="chat-header">
         <div class="resize-handle" @mousedown="startResize">
           <i class="el-icon-d-caret"></i>

+ 2 - 2
src/router/index.js

@@ -158,7 +158,7 @@ export const constantRoutes = [
  * the routes that need to be dynamically loaded based on user roles
  */
 export const asyncRoutes = [
-/*   {
+  {
     path: '/project',
     component: Layout,
     type:1,
@@ -181,7 +181,7 @@ export const asyncRoutes = [
         meta: { title: '项目分类',  noCache: true ,roles: ['admin']}
       }
     ]
-  }, */
+  },
   {
     path: '/customer',
     component: Layout,

+ 3 - 1
src/store/index.js

@@ -1,6 +1,7 @@
 import Vue from 'vue'
 import Vuex from 'vuex'
 import getters from './getters'
+import project from './modules/project'
 
 Vue.use(Vuex)
 // https://webpack.js.org/guides/dependency-management/#requirecontext
@@ -16,7 +17,8 @@ const modules = modulesFiles.keys().reduce((modules, modulePath) => {
 
 const store = new Vuex.Store({
   modules,
-  getters
+  getters,
+  project
 })
 
 export default store

+ 26 - 0
src/store/modules/project.js

@@ -0,0 +1,26 @@
+const state = {
+    currentProjectId: null,
+    currentProjectName: ''
+  }
+  
+  const mutations = {
+    SET_CURRENT_PROJECT: (state, { id, name }) => {
+      state.currentProjectId = id
+      state.currentProjectName = name
+    }
+  }
+  
+  const actions = {
+    setCurrentProject({ commit }, project) {
+      commit('SET_CURRENT_PROJECT', project)
+      // 保存到 localStorage,以便刷新后保持状态
+      localStorage.setItem('currentProject', JSON.stringify(project))
+    }
+  }
+  
+  export default {
+    namespaced: true,
+    state,
+    mutations,
+    actions
+  }

+ 102 - 33
src/views/dashboard/admin/chart.vue

@@ -362,7 +362,7 @@
                           <div class="card">
                             <div class="card-body">
                               <span>文件未解析数量</span>
-                              <h3>{{ docList.run_0}}</h3>
+                              <h3>{{ docList.run_0 }}</h3>
                               <div
                                 ref="real1Chart"
                                 style="height: 20px; width: 100%"
@@ -431,13 +431,13 @@ import * as am4charts from "@amcharts/amcharts4/charts";
 import am4themes_animated from "@amcharts/amcharts4/themes/animated";
 import BootstrapWrapper from "@/components/BootstrapWrapper/index.vue";
 import { searchlistDoc, searchList } from "@/api/document";
-import {pageTemplate } from "@/api/template";
+import { pageTemplate } from "@/api/template";
 import {
   listBuckets,
   structure_count,
   GET_Rbq,
   gpu_info,
-  doc_status
+  doc_status,
 } from "@/api/knowledge";
 export default {
   name: "WidgetChart",
@@ -458,7 +458,9 @@ export default {
       docTotal: 0,
       temTotal: 0,
       pageTotal: 0,
-      docList:{}
+      docList: {},
+      chartUpdateInterval: null, // 添加新的数据属性用于存储定时器
+      isPageVisible: !document.hidden, // 添加新的数据属性
     };
   },
   watch: {
@@ -469,9 +471,26 @@ export default {
         this.handleRouteChange();
       },
     },
+    // 监听页面可见性
+    isPageVisible: {
+      immediate: true,
+      handler(newValue) {
+        console.log(newValue);
+        if (newValue) {
+          // 页面变为可见时
+          console.log("Page became visible");
+           this.initSiteVisitorChart();
+        } else {
+          // 页面变为不可见时
+          console.log("Page became hidden");
+          this.cleanupCharts();
+        }
+      },
+    },
   },
 
   mounted() {
+    document.addEventListener("visibilitychange", this.handleVisibilityChange);
     // 使用动画主题
     am4core.useTheme(am4themes_animated);
     this.init();
@@ -485,16 +504,40 @@ export default {
     this.initDeviceChart(); // 添加这行
   },
 
+  // 修改生命周期钩子
+  activated() {
+    console.log(1123);
+    // 当组件被激活时重新初始化图表
+    this.initSiteVisitorChart();
+  },
+
+  deactivated() {
+    // 当组件被停用时清理资源
+    this.cleanupCharts();
+  },
+
   beforeDestroy() {
-    // 销毁所有图表实例
+    // 组件销毁前清理所有资源
+    this.cleanupCharts();
+    this.closeWebSocket();
+
+    // 清理其他图表实例
     Object.values(this.charts).forEach((chart) => {
       if (chart) {
-        chart.dispose();
+        if (typeof chart.dispose === "function") {
+          chart.dispose();
+        } else if (typeof chart === "number") {
+          clearInterval(chart);
+        }
       }
     });
   },
 
   methods: {
+    // 处理页面可见性变化
+    handleVisibilityChange() {
+      this.isPageVisible = !document.hidden;
+    },
     closeWebSocket() {
       if (this.ws) {
         this.ws.close();
@@ -565,12 +608,13 @@ export default {
       chart.logo.disabled = true;
       chart.innerRadius = am4core.percent(82);
 
-      // 主轴配置
+      // 修改主轴配置
       const axis = chart.xAxes.push(new am4charts.ValueAxis());
       axis.min = 0;
       axis.max = 100;
       axis.strictMinMax = true;
-      axis.renderer.radius = am4core.percent(80);
+      // 设置固定的半径
+      axis.renderer.radius = 80; // 使用固定像素值而不是百分比
       axis.renderer.inside = true;
       axis.renderer.line.strokeOpacity = 0;
       axis.renderer.ticks.template.strokeOpacity = 1;
@@ -579,11 +623,13 @@ export default {
       axis.renderer.labels.template.radius = 40;
       axis.renderer.labels.template.adapter.add("text", () => "");
 
-      // 第二轴配置
+      // 修改第二轴配置
       const axis2 = chart.xAxes.push(new am4charts.ValueAxis());
       axis2.min = 0;
       axis2.max = 100;
-      axis2.renderer.innerRadius = 75;
+      // 设置固定的内半径
+      axis2.renderer.innerRadius = 65; // 使用固定像素值
+      axis2.renderer.radius = 80; // 设置固定的外半径
 
       axis2.strictMinMax = true;
       axis2.renderer.labels.template.disabled = true;
@@ -637,6 +683,8 @@ export default {
         range1.value = ev.target.value;
         axis2.invalidate();
       });
+      // 设置图表容器的固定大小
+      //chart.width = 160; // 设置固定宽度
 
       // 定时更新数据
       const interval = setInterval(() => {
@@ -784,6 +832,10 @@ export default {
     },
     // 修改initSiteVisitorChart方法
     initSiteVisitorChart() {
+      // 如果已存在图表实例,先销毁它
+      if (this.charts.siteVisitorChart) {
+        this.charts.siteVisitorChart.dispose();
+      }
       const chart = am4core.create(
         this.$refs.siteVisitorChart,
         am4charts.XYChart
@@ -900,32 +952,50 @@ export default {
       // 存储图表实例
       this.charts.siteVisitorChart = chart;
 
-      // 启动数据更新
+      /*  // 启动数据更新
       setTimeout(() => {
         this.startVisitorDataInterval(cpuSeries, gpuSeries);
-      }, 100);
+      }, 100); */
+      // 修改数据更新逻辑
+      this.startVisitorDataInterval(cpuSeries, gpuSeries);
     },
 
-    startVisitorDataInterval(series) {
-      let visits = 10;
-      const interval = setInterval(() => {
-        visits =
-          visits +
-          Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 5);
-        const lastDataItem = series.dataItems.getIndex(
-          series.dataItems.length - 1
-        );
-        series.chart.addData(
-          {
-            date: new Date(lastDataItem.dateX.getTime() + 1000),
-            cpuValue: this.cpuValue || 0, //value: Math.abs(visits),
-            gpuValue: this.GpuValue || 0,
-          },
-          1
+    // 修改 startVisitorDataInterval 方法
+    startVisitorDataInterval(cpuSeries, gpuSeries) {
+      // 清除已存在的定时器
+      if (this.chartUpdateInterval) {
+        clearInterval(this.chartUpdateInterval);
+      }
+
+      this.chartUpdateInterval = setInterval(() => {
+        const lastDataItem = cpuSeries.dataItems.getIndex(
+          cpuSeries.dataItems.length - 1
         );
+        if (lastDataItem && lastDataItem.dateX) {
+          cpuSeries.chart.addData(
+            {
+              date: new Date(lastDataItem.dateX.getTime() + 1000),
+              cpuValue: this.cpuValue || 0,
+              gpuValue: this.GpuValue || 0,
+            },
+            1
+          );
+        }
       }, 1000);
+    },
+    // 添加清理方法
+    cleanupCharts() {
+      // 清除定时器
+      if (this.chartUpdateInterval) {
+        clearInterval(this.chartUpdateInterval);
+        this.chartUpdateInterval = null;
+      }
 
-      this.charts.siteVisitorInterval = interval;
+      // 清除图表实例
+      if (this.charts.siteVisitorChart) {
+        this.charts.siteVisitorChart.dispose();
+        this.charts.siteVisitorChart = null;
+      }
     },
 
     handleVisitorChartVisibility() {
@@ -1107,11 +1177,10 @@ export default {
         this.pageTotal = res.data.dataList.length;
       });
       /* 获取文件解析数量 */
-      doc_status().then(res=>{
-        
-        this.docList=res.data.data.run_stats
+      doc_status().then((res) => {
+        this.docList = res.data.data.run_stats;
         console.log(this.docList.run_3);
-      })
+      });
     },
 
     /* 选择知识库 */

+ 81 - 10
src/views/document/com/components/sourceEs/index.vue

@@ -68,7 +68,7 @@ export default {
     this.initTableList();
   },
   methods: {
-    searchEx() {
+    /* searchEx() {
       let allMatches = [];
 
       this.TemList.forEach((el) => {
@@ -81,17 +81,89 @@ export default {
       });
       // 去重
       this.matchResults = [...new Set(allMatches)];
+    }, */
+    searchEx() {
+      let allMatches = [];
+
+      // 从所有模板内容中提取匹配的代码
+      this.TemList.forEach((el) => {
+        // 使用正则表达式匹配 [字母数字-字母数字-数字-数字] 格式的内容
+        const matches = el.content.match(
+          /\[[A-Z0-9]+-[A-Z0-9]+-[0-9]+-[0-9]+\]/g
+        );
+        if (matches) {
+          allMatches = [...allMatches, ...matches];
+        }
+      });
+      // 去重后存储结果
+      this.matchResults = [...new Set(allMatches)];
+
+      // 如果需要立即按类型分类,可以添加:
+      const categorized = this.categorizeByType(this.matchResults);
+      console.log("分类结果:", categorized);
     },
-    // 格式化请求参数
+
+    // 新增分类方法
+    categorizeByType(matches) {
+      const result = {
+        RP: [], // 模板位置
+        IR: [], // 中间层位置
+        WE: [], // 技术报告位置
+        other: [], // 其他
+      };
+
+      matches.forEach((match) => {
+        const cleanMatch = match.replace(/[\[\]]/g, "");
+        if (cleanMatch.includes("-RP-")) {
+          result.RP.push(match);
+        } else if (cleanMatch.includes("-IR-")) {
+          result.IR.push(match);
+        } else if (cleanMatch.includes("-WE-")) {
+          result.WE.push(match);
+        } else {
+          result.other.push(match);
+        }
+      });
+
+      return result;
+    },
+
+    // 添加新的辅助方法来判断文档类型
+    getDocumentType(code) {
+      if (code.includes("-RP-")) return "template_location";
+      if (code.includes("-IR-")) return "middle_layer_location";
+      if (code.includes("-WE-")) return "tech_report_location";
+      return "other_location";
+    },
+
+    // 修改格式化请求参数的方法
     formatRequestParams(locations) {
-      // 确保 locations 是数组
       const locationArray = Array.isArray(locations) ? locations : [locations];
-      return {
-        template_location: locationArray,
-        middle_layer_location: locationArray.map(() => ""),
-        tech_report_location: locationArray.map(() => ""),
-        other_location: locationArray.map(() => ""),
+
+      // 初始化请求参数对象
+      const params = {
+        template_location: [],
+        middle_layer_location: [],
+        tech_report_location: [],
+        other_location: [],
       };
+
+      // 根据不同类型分类存储
+      locationArray.forEach((location) => {
+        const cleanLocation = location.replace(/[\[\]]/g, "");
+        const type = this.getDocumentType(cleanLocation);
+        console.log("params", type);
+        // 为每种类型创建对应长度的空数组
+        Object.keys(params).forEach((key) => {
+          if (type === key) {
+            params[key].push(cleanLocation);
+          } else {
+            params[key].push("");
+          }
+        });
+      });
+
+      return params;
     },
 
     // 单个替换
@@ -105,8 +177,7 @@ export default {
       })
         .then(async () => {
           try {
-            // 修改这里,确保传入数组形式的参数
-            const params = this.formatRequestParams(cleanItem); /* item */
+            const params = this.formatRequestParams(cleanItem);
             const response = await axios.post(
               `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
               params,

+ 0 - 6
src/views/document/com/menus.vue

@@ -38,7 +38,6 @@
     <el-dialog
       :visible.sync="showFormula"
       append-to-body
-      v-el-drag-dialog
       width="60%"
       :close-on-click-modal="false"
       custom-class="prod-verify"
@@ -51,7 +50,6 @@
     <el-dialog
       :visible.sync="showVariable"
       append-to-body
-      v-el-drag-dialog
       width="800px"
       :close-on-click-modal="false"
       custom-class="prod-verify"
@@ -68,7 +66,6 @@
     <el-dialog
       :visible.sync="showSourceData"
       append-to-body
-      v-el-drag-dialog
       width="300"
       :close-on-click-modal="false"
       top="20px"
@@ -81,7 +78,6 @@
     <el-dialog
       :visible.sync="showSourceAi"
       append-to-body
-      v-el-drag-dialog
       width="80%"
       :close-on-click-modal="false"
       top="20px"
@@ -96,7 +92,6 @@
     <el-dialog
       :visible.sync="showSourceEs"
       append-to-body
-      v-el-drag-dialog
       width="300"
       :close-on-click-modal="false"
       custom-class="prod-verify"
@@ -108,7 +103,6 @@
     <el-dialog
       :visible.sync="showDirectoryLevelDialog"
       append-to-body
-      v-el-drag-dialog
       width="300px"
       :close-on-click-modal="false"
       custom-class="prod-verify"

+ 97 - 69
src/views/login/index.vue

@@ -114,7 +114,11 @@
                 autocomplete="on"
               />
               <span class="show-pwd">
-                <el-button type="primary" :disabled="isDisabled" @click="getCode">
+                <el-button
+                  type="primary"
+                  :disabled="isDisabled"
+                  @click="getCode"
+                >
                   {{ buttonText }}
                 </el-button>
               </span>
@@ -455,7 +459,6 @@ export default {
     Retrieve(val) {
       this.loginOrRetrieve = val;
     },
-
     /* 粒子动画 */
     initParticles() {
       const canvas = document.getElementById("canvas1");
@@ -463,112 +466,129 @@ export default {
       canvas.width = window.innerWidth;
       canvas.height = window.innerHeight;
 
-      let area = Math.sqrt(canvas.width * canvas.height);
-      let radiusLength = (canvas.width * canvas.height) / 8000;
-
-      let particlesArray;
-
       let mouse = {
         x: null,
         y: null,
-        radius: radiusLength,
+        radius: 150, // 可以调整鼠标影响范围
       };
 
-      window.addEventListener("mousemove", function (event) {
+      canvas.addEventListener("mousemove", function (event) {
         mouse.x = event.x;
         mouse.y = event.y;
       });
 
-      window.addEventListener("mouseout", function (event) {
+      canvas.addEventListener("mouseout", function () {
         mouse.x = undefined;
         mouse.y = undefined;
       });
 
-      window.addEventListener("resize", function (event) {
-        canvas.width = innerWidth;
-        canvas.height = innerHeight;
-        radiusLength = (canvas.width * canvas.height) / 9000;
-        createParticles();
-      });
-
       class Particle {
-        constructor(x, y, velX, velY, size, color) {
-          this.x = x;
-          this.y = y;
-          this.velX = velX;
-          this.velY = velY;
-          this.size = size;
-          this.color = color;
+        constructor() {
+          this.x = Math.random() * canvas.width;
+          this.y = Math.random() * canvas.height;
+          this.size = Math.random() * 3 + 1;
+          this.baseX = this.x;
+          this.baseY = this.y;
+          this.density = Math.random() * 30 + 1;
+          // 增加速度范围到 -2 到 2
+          this.speedX = (Math.random() - 0.5) * 3.5; // 从2改为4
+          this.speedY = (Math.random() - 0.5) * 3.5; // 从2改为4
+          // 添加额外的动画参数
+          this.angle = Math.random() * 360;
+          this.angleSpeed = (Math.random() - 0.5) * 2; // 旋转速度
+          this.oscillationRadius = Math.random() * 5; // 振荡幅度
         }
 
         draw() {
           ctx.beginPath();
-          ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
+          ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
           ctx.fillStyle = "#ffffff";
           ctx.fill();
         }
 
         update() {
-          if (this.x > canvas.width || this.x < 0) {
-            this.velX = -this.velX;
+          // 优化计算,减少三角函数计算频率
+          if (this.angle > 360) this.angle -= 360;
+          const angleRad = (this.angle * Math.PI) / 180;
+          const oscillation = Math.sin(angleRad) * this.oscillationRadius * 0.1;
+
+          this.baseX += this.speedX + oscillation;
+          this.baseY += this.speedY + oscillation;
+
+          // 边界检查 - 添加随机性
+          if (this.baseX > canvas.width || this.baseX < 0) {
+            this.speedX *= -1;
+            //this.speedX += (Math.random() - 0.5) * 0.5; // 添加随机速度变化
           }
-          if (this.y > canvas.height || this.y < 0) {
-            this.velY = -this.velY;
+          if (this.baseY > canvas.height || this.baseY < 0) {
+            this.speedY *= -1;
+            // this.speedY += (Math.random() - 0.5) * 0.5; // 添加随机速度变化
           }
 
+          // 限制最大速度
+          const maxSpeed = 5;
+          this.speedX = Math.max(Math.min(this.speedX, maxSpeed), -maxSpeed);
+          this.speedY = Math.max(Math.min(this.speedY, maxSpeed), -maxSpeed);
+
+          // 鼠标交互
           let dx = mouse.x - this.x;
           let dy = mouse.y - this.y;
-          let dist = Math.sqrt(dx * dx + dy * dy);
-          if (dist < mouse.radius + this.size) {
-            const buffer = this.size * 10;
-            if (mouse.x < this.x && this.x < canvas.width - buffer) {
-              this.x += 10;
-            }
-            if (mouse.x > this.x && this.x > buffer) {
-              this.x -= 10;
-            }
-            if (mouse.y < this.y && this.y < canvas.height - buffer) {
-              this.y += 10;
+          let distance = Math.sqrt(dx * dx + dy * dy);
+          let forceDirectionX = dx / distance;
+          let forceDirectionY = dy / distance;
+          let maxDistance = mouse.radius;
+          let force = (maxDistance - distance) / maxDistance;
+          let directionX = forceDirectionX * force * this.density;
+          let directionY = forceDirectionY * force * this.density;
+
+          if (distance < mouse.radius && mouse.x != undefined) {
+            // 增加鼠标排斥力
+            this.x -= directionX * 2; // 增加排斥力度
+            this.y -= directionY * 2;
+          } else {
+            // 更快地回到基准位置
+            if (this.x !== this.baseX) {
+              let dx = this.x - this.baseX;
+              this.x -= dx / 5; // 从10改为5,使回归更快
             }
-            if (mouse.y > this.y && this.y > buffer) {
-              this.y -= 10;
+            if (this.y !== this.baseY) {
+              let dy = this.y - this.baseY;
+              this.y -= dy / 5;
             }
           }
-
-          this.x += this.velX;
-          this.y += this.velY;
-          this.draw();
         }
       }
 
-      function createParticles() {
+      let particlesArray = [];
+
+      function init() {
         particlesArray = [];
-        let noOfParticles = (canvas.width * canvas.height) / 10000;
-        for (let i = 0; i < noOfParticles; i++) {
-          let size = Math.random() * 5 + 1;
-          let x = Math.random() * (innerWidth - 2 * size) + 2 * size;
-          let y = Math.random() * (innerHeight - 2 * size) + 2 * size;
-          let velX = Math.random() * 2;
-          let velY = Math.random() * 2;
-          let color = "#ffffff";
-          particlesArray.push(new Particle(x, y, velX, velY, size, color));
+        // 增加粒子数量
+        const numberOfParticles = (canvas.width * canvas.height) / 7000; // 从9000改为7000
+        for (let i = 0; i < numberOfParticles; i++) {
+          particlesArray.push(new Particle());
         }
       }
 
       function connect() {
-        let vicinityDist = (canvas.width * canvas.height) / 81;
-        for (let i = 0; i < particlesArray.length; i++) {
-          for (let j = i; j < particlesArray.length; j++) {
+        let opacityValue = 1;
+        for (let a = 0; a < particlesArray.length; a++) {
+          for (let b = a; b < particlesArray.length; b++) {
             let distance =
-              Math.pow(particlesArray[i].x - particlesArray[j].x, 2) +
-              Math.pow(particlesArray[i].y - particlesArray[j].y, 2);
-            let opacity = 1 - distance / 25000;
-            if (distance < vicinityDist) {
-              ctx.strokeStyle = "rgba(255,255,255," + opacity + ")";
+              (particlesArray[a].x - particlesArray[b].x) *
+                (particlesArray[a].x - particlesArray[b].x) +
+              (particlesArray[a].y - particlesArray[b].y) *
+                (particlesArray[a].y - particlesArray[b].y);
+
+            // 增加连线距离和可见度
+            if (distance < (canvas.width / 6) * (canvas.height / 6)) {
+              // 从7改为6
+              opacityValue = 1 - distance / 15000; // 从20000改为15000,使线条更明显
+              ctx.strokeStyle = `rgba(255,255,255,${opacityValue})`;
               ctx.lineWidth = 1;
               ctx.beginPath();
-              ctx.moveTo(particlesArray[i].x, particlesArray[i].y);
-              ctx.lineTo(particlesArray[j].x, particlesArray[j].y);
+              ctx.moveTo(particlesArray[a].x, particlesArray[a].y);
+              ctx.lineTo(particlesArray[b].x, particlesArray[b].y);
               ctx.stroke();
             }
           }
@@ -576,15 +596,23 @@ export default {
       }
 
       function animate() {
-        requestAnimationFrame(animate);
-        ctx.clearRect(0, 0, innerWidth, innerHeight);
+        ctx.clearRect(0, 0, canvas.width, canvas.height);
+
         for (let i = 0; i < particlesArray.length; i++) {
           particlesArray[i].update();
+          particlesArray[i].draw();
         }
         connect();
+        requestAnimationFrame(animate);
       }
 
-      createParticles();
+      window.addEventListener("resize", function () {
+        canvas.width = window.innerWidth;
+        canvas.height = window.innerHeight;
+        init();
+      });
+
+      init();
       animate();
     },
   },

+ 191 - 184
src/views/project/components/dataInfo.vue

@@ -2,20 +2,19 @@
   <div class="data-info">
     <el-card>
       <el-form :model="dataForm" label-width="120px">
-
         <el-form-item label="项目名称:">
           <el-input v-model="dataForm.name"></el-input>
         </el-form-item>
 
         <el-form-item label="项目介绍:">
           <el-input
-          rows="10"
-          type="textarea"
-          v-model="dataForm.intro"></el-input>
-
+            rows="10"
+            type="textarea"
+            v-model="dataForm.intro"
+          ></el-input>
         </el-form-item>
 
-        <el-form-item label="所属客户:">
+        <!--<el-form-item label="所属客户:">
           <el-select v-model="dataForm.customer_id"  placeholder="请选择客户" size="large"   style="width:100%;">
               <el-option
                 v-for="item in customerList"
@@ -34,208 +33,216 @@
               :value="item.id"
             />
           </el-select>
-      </el-form-item>
+      </el-form-item>-->
         <el-form-item label="所属分类:">
-          <el-select v-model="dataForm.category_id"  placeholder="请选择所属分类" size="large"   style="width:100%;">
-              <el-option
-                v-for="item in allCategories"
-                :key="item.id"
-                :label="item.name"
-                :value="item.id"
-              />
-            </el-select>
+          <el-select
+            v-model="dataForm.category_id"
+            placeholder="请选择所属分类"
+            size="large"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in allCategories"
+              :key="item.id"
+              :label="item.name"
+              :value="item.id"
+            />
+          </el-select>
         </el-form-item>
 
         <el-form-item label="项目状态:">
-          <el-select v-model="dataForm.status"  placeholder="请选择状态" size="large"   style="width:100%;">
-              <el-option
-                v-for="item in statusOptions"
-                :key="item.status"
-                :label="item.name"
-                :value="item.status"
-              />
-            </el-select>
+          <el-select
+            v-model="dataForm.status"
+            placeholder="请选择状态"
+            size="large"
+            style="width: 100%"
+          >
+            <el-option
+              v-for="item in statusOptions"
+              :key="item.status"
+              :label="item.name"
+              :value="item.status"
+            />
+          </el-select>
         </el-form-item>
-
-
       </el-form>
-
     </el-card>
 
-
-      <div style="text-align:right; margin-top:20px;">
-          <el-button type="warning" @click="btnSave">确认保存</el-button>
-      </div>
+    <div style="text-align: right; margin-top: 20px">
+      <el-button type="warning" @click="btnSave">确认保存</el-button>
+    </div>
   </div>
 </template>
 
 <script>
-  import Tinymce from "@/components/Tinymce";
-  import {searchCategory,createProject,updateProject,getProjectInfo} from'@/api/project'
-  import {searchCustomer} from"@/api/customer"
-  import {searchDocument} from "@/api/document"
-  export default{
-    components:{
-      Tinymce
+import Tinymce from "@/components/Tinymce";
+import {
+  searchCategory,
+  createProject,
+  updateProject,
+  getProjectInfo,
+} from "@/api/project";
+import { searchCustomer } from "@/api/customer";
+import { searchDocument } from "@/api/document";
+export default {
+  components: {
+    Tinymce,
+  },
+  emits: ["onClose"],
+  props: {
+    id: {
+      type: Number,
+      default: 0,
     },
-    emits:['onClose'],
-    props:{
-      id:{
-        type:Number,
-        default:0
+  },
+  watch: {
+    id: {
+      handler(v) {
+        let _this = this;
+        if (v == null) return;
+        if (v == 0) {
+          this.dataForm = {
+            id: 0,
+            name: "",
+            intro: "",
+            customer_id: "",
+            category_id: "",
+            status: 5,
+            /*  linkDoc:[], */
+          };
+          return;
+        }
+        _this.getInfo(v);
       },
+      immediate: true,
+      deep: true,
     },
-    watch:{
-      id:{
-        handler(v){
-            let _this=this;
-            if(v==null )return;
-            if(v==0){
-
-              this.dataForm={
-                id:0,
-                name:'',
-                intro:'',
-                customer_id:'',
-                category_id:'',
-                status:5,
-                linkDoc:[],
-              }
-              return;
-            }
-            _this.getInfo(v);
+  },
+  data() {
+    return {
+      activeName: "base",
+      currentCategory: [],
+      allCategories: [],
+      imageUrl: "",
+      customerList: [],
+      articleList: [],
+      dataForm: {
+        id: 0,
+        name: "",
+        intro: "",
+        customer_id: "",
+        category_id: "",
+        status: 5,
+        /*  linkDoc:[], */
+      },
+      statusOptions: [
+        {
+          status: 5,
+          name: "启用",
         },
-        immediate: true,
-        deep: true
-      }
-    },
-    data(){
-      return{
-        activeName:'base',
-        currentCategory:[],
-        allCategories:[],
-        imageUrl:"",
-        customerList:[],
-        articleList:[],
-        dataForm:{
-          id:0,
-          name:'',
-          intro:'',
-          customer_id:'',
-          category_id:'',
-          status:5,
-          linkDoc:[],
+        {
+          status: 6,
+          name: "停用",
         },
-        statusOptions:[
-          {
-            status:5,
-            name:'启用'
-          },
-          {
-            status:6,
-            name:'停用'
-          }
+      ],
+    };
+  },
+
+  mounted() {
+    let _this = this;
+    _this.uploadUrl = process.env.VUE_APP_BASE_API + "/upload";
+    _this.initAllCategory();
+    this.initCustomer();
+    this.initDocList();
+  },
+  methods: {
+    initDocList() {
+      let _this = this;
+      searchDocument({
+        page: 1,
+        pageSize: 10,
+      }).then((res) => {
+        if (res.status != 200) return;
+        _this.articleList = res.data.dataList;
+      });
+    },
+    //图片上传成功
+    onUploadSuccess(e) {
+      console.log("onUploadSuccess", e);
+    },
+    //保存更新
+    btnSave(e) {
+      let _this = this;
 
-        ],
+      if (_this.dataForm.title == "") {
+        _this.$alert("产品标题不能为空");
+        return;
+      }
+      /* _this.dataForm.links=JSON.stringify(_this.dataForm.linkDoc); */
+      if (_this.dataForm.id > 0) {
+        updateProject(_this.dataForm).then((res) => {
+          if (res.status !== 200) return;
+          _this.$alert("项目信息更新成功");
+          _this.$emit("onClose");
+        });
+      } else {
+        createProject(_this.dataForm).then((res) => {
+          if (res.status !== 200) return;
+          _this.$alert("项目信息创建成功");
+          _this.$emit("onClose");
+        });
       }
     },
 
-    mounted() {
-      let _this=this;
-      _this.uploadUrl=process.env.VUE_APP_BASE_API+"/upload"
-      _this.initAllCategory();
-      this.initCustomer();
-      this.initDocList();
+    //产品详情
+    getInfo(id) {
+      let _this = this;
+      let par = {
+        id: id,
+      };
+      getProjectInfo(par).then((res) => {
+        if (!res) return;
+        if (res.status != 200) return;
+        _this.dataForm = res.data;
+        _this.dataForm.category_id = res.data.categoryId;
+        _this.dataForm.customer_id = res.data.customerId;
+      });
     },
-    methods:{
-      initDocList(){
-        let _this = this;
-        searchDocument({
-          page: 1,
-          pageSize: 10
-        }).then(res => {
-          if (res.status != 200) return;
-          _this.articleList = res.data.dataList;
-        })
-      },
-      //图片上传成功
-      onUploadSuccess(e){
-        console.log("onUploadSuccess",e);
-      },
-      //保存更新
-      btnSave(e){
-          let _this=this;
-
-          if(_this.dataForm.title==''){
-            _this.$alert("产品标题不能为空");
-              return;
-          }
-          _this.dataForm.links=JSON.stringify(_this.dataForm.linkDoc);
-          if(_this.dataForm.id>0){
-            updateProject(_this.dataForm).then(res=>{
-              _this.$alert("项目信息更新成功");
-              _this.$emit("onClose")
-            })
-          }else{
-            createProject(_this.dataForm).then(res=>{
-              _this.$alert("项目信息创建成功");
-              _this.$emit("onClose");
-            })
-          }
-
-      },
-
-      //产品详情
-      getInfo(id){
-          let _this=this;
-          let par={
-            id:id,
-          };
-          getProjectInfo(par).then(res=>{
-              if(!res)return;
-              if(res.status!=200)return;
-              _this.dataForm=res.data;
-              _this.dataForm.category_id=res.data.categoryId;
-              _this.dataForm.customer_id=res.data.customerId;
 
-          })
-      },
-
-      onChangeStatus(e){
-          this.dataForm.status=e;
-      },
-      //修改分类信息
-      onChangeCategory(e){
-         let _this=this;
-         _this.dataForm.categoryId=e;
-      },
-      //初始化所有分类
-      initAllCategory(){
-          let _this=this;
-          let par={
-            page:1,
-            pageSize:9999,
-            status:5
-          };
-          searchCategory(par).then(res=>{
-            _this.allCategories=res.data.dataList;
-          })
-      },
-      initCustomer(){
-        let _this=this;
-        let par={
-          page:1,
-          pageSize:99,
-        }
-        searchCustomer(par).then(res=>{
-          _this.customerList=res.data.dataList;
-        })
-      }
-
-    }
-  }
+    onChangeStatus(e) {
+      this.dataForm.status = e;
+    },
+    //修改分类信息
+    onChangeCategory(e) {
+      let _this = this;
+      _this.dataForm.categoryId = e;
+    },
+    //初始化所有分类
+    initAllCategory() {
+      let _this = this;
+      let par = {
+        page: 1,
+        pageSize: 9999,
+        status: 5,
+      };
+      searchCategory(par).then((res) => {
+        _this.allCategories = res.data.dataList;
+      });
+    },
+    initCustomer() {
+      let _this = this;
+      let par = {
+        page: 1,
+        pageSize: 99,
+      };
+      searchCustomer(par).then((res) => {
+        _this.customerList = res.data.dataList;
+      });
+    },
+  },
+};
 </script>
 
 <style lang="scss">
- @import './dataInfo.scss'
+@import "./dataInfo.scss";
 </style>

+ 4 - 4
src/views/project/components/dataList.vue

@@ -4,8 +4,8 @@
 
       <el-table :data="dataList" style="width: 100%" header-row-class-name="headerBg" empty-text="没有项目信息">
         <el-table-column prop="id" label="ID" align="center" width="80"/>
-        <el-table-column prop="category.name" label="所属分类" align="left" min-width="180"/>
-        <el-table-column prop="customer.name" label="所属客户" align="left" min-width="180"/>
+       <el-table-column prop="categoryId" label="所属分类" align="left" min-width="180"/>
+         <!-- <el-table-column prop="customer.name" label="所属客户" align="left" min-width="180"/> -->
         <el-table-column prop="name" label="项目名称" align="left" min-width="180"/>
         <el-table-column prop="createTime" label="创建时间" align="center" width="180"/>
         <el-table-column prop="statusName" label="项目状态" align="center" width="180">
@@ -14,7 +14,7 @@
               <div v-if="scope.row.status==6">停用</div>
           </template>
         </el-table-column>
-        <el-table-column label="操作" align="center"  fixed="right" width="150">
+        <el-table-column label="操作" align="center"  fixed="right" width="200">
           <template #default="scope">
             <div class="btns">
               <el-button type="primary" size="small" @click="btnEdit(scope.row)"><svg-icon icon-class="edit"/>编辑</el-button>
@@ -28,7 +28,7 @@
 
       <div class="page-info">
       	<el-pagination
-      	v-model:currentPage="queryForm.page"
+      	:currentPage="queryForm.page"
       	:page-size="queryForm.pageSize"
       	:total="recordCount"
       	:page-count="pageTotal"

+ 4 - 4
src/views/role/components/dataInfo.vue

@@ -467,14 +467,14 @@ export default {
             label: "产品管理",
             children: [],
             sub: false,
-          },{
+          }*/
+        let data = [
+          {
             value: 1,
             label: "项目管理",
             children: [],
             sub: false,
-          },*/
-        let data = [
-          
+          },
           {
             value: 4,
             label: "客户管理",

+ 523 - 134
src/views/templateLoca/index.vue

@@ -3,151 +3,204 @@
     <el-tabs v-model="activeTab" @tab-click="handleTabClick"
       ><!-- 新增的第二个标签页 -->
       <el-tab-pane label="文献项目输入表" name="first">
-        <div class="operation-bar">
-          <el-form :inline="true" :model="gsprSearchForm" class="search-form">
-            <el-form-item label="内容">
-              <el-input
-                v-model="gsprSearchForm.keyword"
-                placeholder="请输入项目名称/技术报告位置"
-                style="width: 300px"
-                clearable
-              />
-            </el-form-item>
-            <el-form-item label="部门">
+        <!-- 项目选择器始终显示 -->
+        <div class="project-selector">
+          <el-form :inline="true">
+            <el-form-item label="当前项目">
               <el-select
-                v-model="gsprSearchForm.department"
-                placeholder="请选择部门"
-                clearable
+                v-model="selectedProjectId"
+                placeholder="请选择项目"
+                style="width: 300px"
+                @change="handleProjectConfirm"
               >
                 <el-option
-                  v-for="(item, index) in departList"
-                  :key="index"
-                  :label="item.label"
-                  :value="item.label"
+                  v-for="project in projectOptions"
+                  :key="project.id"
+                  :label="project.name"
+                  :value="project.id"
                 />
               </el-select>
             </el-form-item>
             <el-form-item>
-              <el-button type="primary" @click="handleGsprSearch"
-                >搜索</el-button
+              <!--  <el-button type="primary" @click="handleProjectConfirm"
+                >确认选择</el-button
+              > -->
+              <el-button
+                type="primary"
+                @click="handleAddGspr"
+                v-if="!hasExistingData"
+                >创建输入项目</el-button
               >
-              <el-button @click="handleGsprReset">重置</el-button>
-            </el-form-item>
-          </el-form>
-          <el-button type="primary" @click="handleAddGspr">新增</el-button>
-        </div>
-
-        <el-table
-          :data="gsprTableData"
-          style="width: 100%"
-          :default-sort="{ prop: sort_field, order: sort_order }"
-          @sort-change="handleSortChange"
-        >
-          <el-table-column prop="name" label="项目名称" sortable="custom" />
-          <el-table-column prop="tech_report_location" label="技术报告位置" />
-          <el-table-column prop="department" label="部门" sortable="custom" />
-          <el-table-column prop="content" label="内容">
-            <template slot-scope="scope">
-              <div style="display: flex; align-items: center">
-                <span style="margin-right: 10px">{{ scope.row.content }}</span>
-                <i
-                  class="el-icon-edit"
-                  @click="handleEditContent(scope.row)"
-                  style="cursor: pointer; margin-left: 5px"
-                ></i>
-              </div>
-            </template>
-          </el-table-column>
-          <el-table-column label="操作" width="200">
-            <template slot-scope="scope">
-              <el-button type="primary" @click="handleEditGspr(scope.row)"
-                >编辑</el-button
+              <el-button type="primary" @click="handleUpdateGspr" v-else
+                >更新输入项目</el-button
               >
-              <el-button type="danger" @click="handleDeleteGspr(scope.row)"
+              <el-button type="danger" @click="handleDeleteItems"
                 >删除</el-button
               >
-            </template>
-          </el-table-column>
-        </el-table>
-
-        <div class="pagination-container">
-          <el-pagination
-            @size-change="handleGsprSizeChange"
-            @current-change="handleGsprCurrentChange"
-            :current-page="gsprPageForm.page"
-            :page-sizes="[10, 20, 30, 50]"
-            :page-size="gsprPageForm.page_size"
-            layout="total, sizes, prev, pager, next, jumper"
-            :total="gsprTotal"
-          />
+            </el-form-item>
+          </el-form>
         </div>
+        <!-- 使用 v-if 控制其余内容的显示 -->
+        <template v-if="currentProjectId">
+          <div class="operation-bar">
+            <el-form :inline="true" :model="gsprSearchForm" class="search-form">
+              <el-form-item label="内容">
+                <el-input
+                  v-model="gsprSearchForm.keyword"
+                  placeholder="请输入项目名称/技术报告位置"
+                  style="width: 300px"
+                  clearable
+                />
+              </el-form-item>
+              <el-form-item label="部门">
+                <el-select
+                  v-model="gsprSearchForm.department"
+                  placeholder="请选择部门"
+                  clearable
+                >
+                  <el-option
+                    v-for="(item, index) in departList"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.label"
+                  />
+                </el-select>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" @click="handleGsprSearch"
+                  >搜索</el-button
+                >
+                <el-button @click="handleGsprReset">重置</el-button>
+              </el-form-item>
+            </el-form>
+          </div>
 
-        <!-- GSPR表单弹窗 -->
-        <el-dialog
-          :title="gsprDialogTitle"
-          :visible.sync="gsprDialogVisible"
-          width="700px"
-        >
-          <el-form
-            :model="gsprForm"
-            ref="gsprForm"
-            :rules="gsprRules"
-            label-width="120px"
+          <el-table
+            :data="gsprTableData"
+            style="width: 100%"
+            :default-sort="{ prop: sort_field, order: sort_order }"
+            @sort-change="handleSortChange"
           >
-            <el-form-item label="名称" prop="name">
-              <el-input v-model="gsprForm.name" />
-            </el-form-item>
-            <el-form-item label="技术报告位置" prop="tech_report_location">
-              <el-input v-model="gsprForm.tech_report_location" />
-            </el-form-item>
+            <el-table-column prop="name" label="项目名称" sortable="custom" />
+            <el-table-column prop="tech_report_location" label="技术报告位置" />
+            <el-table-column prop="department" label="部门" sortable="custom" />
+            <el-table-column prop="content" label="内容">
+              <template slot-scope="scope">
+                <div style="display: flex; align-items: center">
+                  <span style="margin-right: 10px">{{
+                    scope.row.content
+                  }}</span>
+                  <i
+                    class="el-icon-edit"
+                    @click="handleEditContent(scope.row)"
+                    style="cursor: pointer; margin-left: 5px"
+                  ></i>
+                </div>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" width="200">
+              <template slot-scope="scope">
+                <el-button type="primary" @click="handleEditGspr(scope.row)"
+                  >编辑</el-button
+                >
+                <el-button type="danger" @click="handleDeleteGspr(scope.row)"
+                  >删除</el-button
+                >
+              </template>
+            </el-table-column>
+          </el-table>
 
-            <el-form-item label="部门" prop="department">
-              <el-select v-model="gsprForm.department" placeholder="请选择状态">
-                <el-option
-                  v-for="(item, index) in departList"
-                  :key="index"
-                  :label="item.label"
-                  :value="item.label"
-                />
-              </el-select>
-            </el-form-item>
-            <el-form-item label="内容" prop="content">
-              <el-input
-                type="textarea"
-                v-model="gsprForm.content"
-                :rows="4"
-                placeholder="请输入内容"
-              />
-            </el-form-item>
-          </el-form>
-          <div slot="footer">
-            <el-button @click="gsprDialogVisible = false">取消</el-button>
-            <el-button type="primary" @click="handleGsprSubmit">确定</el-button>
+          <div class="pagination-container">
+            <el-pagination
+              @size-change="handleGsprSizeChange"
+              @current-change="handleGsprCurrentChange"
+              :current-page="gsprPageForm.page"
+              :page-sizes="[10, 20, 30, 50]"
+              :page-size="gsprPageForm.page_size"
+              layout="total, sizes, prev, pager, next, jumper"
+              :total="gsprTotal"
+            />
           </div>
-        </el-dialog>
-        <!-- 添加内容编辑弹窗 -->
-        <el-dialog
-          title="编辑内容"
-          :visible.sync="contentDialogVisible"
-          width="600px"
-        >
-          <el-form :model="contentForm" ref="contentForm">
-            <el-form-item label="内容" prop="content">
-              <el-input
-                type="textarea"
-                v-model="contentForm.content"
-                :rows="4"
-                placeholder="请输入内容"
-              />
-            </el-form-item>
-          </el-form>
-          <div slot="footer">
-            <el-button @click="contentDialogVisible = false">取消</el-button>
-            <el-button type="primary" @click="handleContentSubmit"
-              >确定</el-button
+
+          <!-- GSPR表单弹窗 -->
+          <el-dialog
+            :title="gsprDialogTitle"
+            :visible.sync="gsprDialogVisible"
+            width="700px"
+          >
+            <el-form
+              :model="gsprForm"
+              ref="gsprForm"
+              :rules="gsprRules"
+              label-width="120px"
             >
-          </div>
-        </el-dialog>
+              <el-form-item label="名称" prop="name">
+                <el-input v-model="gsprForm.name" />
+              </el-form-item>
+              <el-form-item label="技术报告位置" prop="tech_report_location">
+                <el-input v-model="gsprForm.tech_report_location" />
+              </el-form-item>
+
+              <el-form-item label="部门" prop="department">
+                <el-select
+                  v-model="gsprForm.department"
+                  placeholder="请选择状态"
+                >
+                  <el-option
+                    v-for="(item, index) in departList"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.label"
+                  />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="内容" prop="content">
+                <el-input
+                  type="textarea"
+                  v-model="gsprForm.content"
+                  :rows="4"
+                  placeholder="请输入内容"
+                />
+              </el-form-item>
+            </el-form>
+            <div slot="footer">
+              <el-button @click="gsprDialogVisible = false">取消</el-button>
+              <el-button type="primary" @click="handleGsprSubmit"
+                >确定</el-button
+              >
+            </div>
+          </el-dialog>
+          <!-- 添加内容编辑弹窗 -->
+          <el-dialog
+            title="编辑内容"
+            :visible.sync="contentDialogVisible"
+            width="600px"
+          >
+            <el-form :model="contentForm" ref="contentForm">
+              <el-form-item label="内容" prop="content">
+                <el-input
+                  type="textarea"
+                  v-model="contentForm.content"
+                  :rows="4"
+                  placeholder="请输入内容"
+                />
+              </el-form-item>
+            </el-form>
+            <div slot="footer">
+              <el-button @click="contentDialogVisible = false">取消</el-button>
+              <el-button type="primary" @click="handleContentSubmit"
+                >确定</el-button
+              >
+            </div>
+          </el-dialog>
+        </template>
+
+        <!-- 未选择项目时显示提示 -->
+        <el-empty
+          v-else
+          description="请先选择一个项目"
+          :image-size="200"
+        ></el-empty>
       </el-tab-pane>
       <!-- 第一个标签页 - 原有的模板位置表 -->
       <el-tab-pane label="模板位置表" name="second">
@@ -173,7 +226,7 @@
                 <el-option
                   v-for="(item, index) in typeList"
                   :key="index"
-                  :label="item.label"
+                  :label="item.value"
                   :value="item.value"
                 />
                 <!-- <el-option label="WE" value="WE" /> -->
@@ -236,6 +289,41 @@
         </div>
       </el-tab-pane>
     </el-tabs>
+    <!-- 添加删除确认对话框 -->
+    <el-dialog
+      title="删除确认"
+      :visible.sync="deleteDialogVisible"
+      width="400px"
+    >
+      <!-- 添加提示信息区域 -->
+      <div class="delete-warning" style="margin-bottom: 20px">
+        <i
+          class="el-icon-warning"
+          style="color: #e6a23c; margin-right: 8px"
+        ></i>
+        <span
+          >此操作将永久删除该项目下的所有输入项目,请输入'DELETE'确认删除</span
+        >
+      </div>
+
+      <el-form
+        :model="deleteForm"
+        :rules="deleteRules"
+        ref="deleteForm"
+        label-width="100px"
+      >
+        <el-form-item label="确认文本" prop="confirmText">
+          <el-input
+            v-model="deleteForm.confirmText"
+            placeholder="请输入'DELETE'"
+          ></el-input>
+        </el-form-item>
+      </el-form>
+      <span slot="footer" class="dialog-footer">
+        <el-button @click="deleteDialogVisible = false">取消</el-button>
+        <el-button type="danger" @click="confirmDelete">确认删除</el-button>
+      </span>
+    </el-dialog>
   </div>
 </template>
   
@@ -251,11 +339,24 @@ import {
   projectUpdate,
   projectDelete,
   get_action_types,
+  create_items,
+  delete_items,
+  update_items,
 } from "@/api/knowledge";
+import { searchProject } from "@/api/project";
 import axios from "axios";
+import { mapState } from "vuex";
 export default {
   name: "TemplateLocation",
   data() {
+    // 自定义验证规则
+    const validateDeleteConfirm = (rule, value, callback) => {
+      if (value !== "DELETE") {
+        callback(new Error("请输入正确的确认文本"));
+      } else {
+        callback();
+      }
+    };
     return {
       tableData: [],
       dialogVisible: false,
@@ -338,17 +439,279 @@ export default {
       /* 排序 */
       sort_field: "name", // 默认排序字段
       sort_order: "desc", // 默认排序方向
+      /* 新增项目 */
+      selectedProjectId: null, // 新增本地属性来存储选中的项目ID
+      projectOptions: [], // 项目选项列表
+      gsprSearchForm: {
+        keyword: "",
+        department: "",
+        project_id: null, // 添加项目ID字段
+      },
+      /* 删除逻辑 */
+      deleteDialogVisible: false,
+      deleteForm: {
+        confirmText: "",
+      },
+      deleteRules: {
+        confirmText: [
+          { required: true, message: "请输入确认文本", trigger: "blur" },
+          { validator: validateDeleteConfirm, trigger: "blur" },
+        ],
+      },
+      hasExistingData: false, // 添加标记是否有现有数据的属性
     };
   },
+  computed: {
+    ...mapState("project", ["currentProjectId"]),
+  },
+  // created 钩子中的修改
+  created() {
+    // 从 localStorage 恢复项目状态
+    const savedProject = localStorage.getItem("currentProject");
+    if (savedProject) {
+      const { id, name } = JSON.parse(savedProject);
+      this.$store.dispatch("project/setCurrentProject", { id, name });
+      this.selectedProjectId = id; // 同步设置本地选中状态
+    }
+  },
+
+  // 添加 watch 来监听 Vuex 中的 currentProjectId 变化
+  watch: {
+    currentProjectId: {
+      immediate: true, // 添加 immediate: true 确保组件创建时就执行
+      handler(newVal) {
+        if (newVal) {
+          this.selectedProjectId = newVal;
+          this.gsprSearchForm.project_id = newVal;
+          this.fetchGsprData(); // 自动加载数据
+        }
+      },
+    },
+  },
   mounted() {
-    this.fetchGsprData();
+    this.fetchProjects();
+    /*  this.fetchGsprData(); */
     this.init();
   },
   methods: {
+    // 处理删除按钮点击
+    handleDeleteItems() {
+      if (!this.currentProjectId) {
+        this.$message.warning("请先选择一个项目");
+        return;
+      }
+
+      const selectedProject = this.projectOptions.find(
+        (p) => p.id === this.currentProjectId
+      );
+
+      this.$confirm(
+        `您确定要删除项目 "${selectedProject.name}" 的所有输入项目吗?此操作不可恢复。`,
+        "警告",
+        {
+          confirmButtonText: "继续删除",
+          cancelButtonText: "取消",
+          type: "warning",
+        }
+      )
+        .then(() => {
+          this.deleteForm.confirmText = "";
+          this.deleteDialogVisible = true;
+        })
+        .catch(() => {
+          this.$message({
+            type: "info",
+            message: "已取消删除",
+          });
+        });
+    },
+
+    // 确认删除
+    confirmDelete() {
+      this.$refs.deleteForm.validate(async (valid) => {
+        if (!valid) {
+          return false;
+        }
+
+        try {
+          const loading = this.$loading({
+            lock: true,
+            text: "正在删除...",
+            spinner: "el-icon-loading",
+            background: "rgba(0, 0, 0, 0.7)",
+          });
+
+          const response = await delete_items({
+            project_id: this.currentProjectId,
+          });
+
+          loading.close();
+
+          if (response.status === 200) {
+            this.$message.success("删除成功");
+            this.deleteDialogVisible = false;
+            // 重新加载数据
+            this.fetchGsprData();
+          } else {
+            this.$message.error(response.message || "删除失败");
+          }
+        } catch (error) {
+          this.$message.error("删除失败:" + (error.message || "未知错误"));
+        }
+      });
+    },
+    /* 初始化请求项目列表接口 */
+    async fetchProjects() {
+      try {
+        const response = await searchProject({ page: 1, pageSize: 999 });
+        if (response.status === 200) {
+          this.projectOptions = response.data.dataList;
+
+          // 如果有当前项目ID但没有选中项目,自动选中
+          if (this.currentProjectId && !this.selectedProjectId) {
+            this.selectedProjectId = this.currentProjectId;
+            this.handleProjectConfirm();
+          }
+        }
+      } catch (error) {
+        this.$message.error("获取项目列表失败");
+      }
+    },
+
+    // 修改 handleProjectConfirm 方法
+    handleProjectConfirm() {
+      if (!this.selectedProjectId) {
+        this.$message.warning("请先选择一个项目");
+        return;
+      }
+
+      const selectedProject = this.projectOptions.find(
+        (p) => p.id === this.selectedProjectId
+      );
+
+      if (!selectedProject) {
+        this.$message.error("未找到选中的项目");
+        return;
+      }
+
+      this.$store.dispatch("project/setCurrentProject", {
+        id: selectedProject.id,
+        name: selectedProject.name,
+      });
+
+      // 保存到 localStorage
+      localStorage.setItem(
+        "currentProject",
+        JSON.stringify({
+          id: selectedProject.id,
+          name: selectedProject.name,
+        })
+      );
+
+      this.gsprSearchForm.project_id = this.selectedProjectId;
+      this.fetchGsprData();
+    },
+
+    // 创建项目的方法
+    async handleAddGspr() {
+      if (!this.currentProjectId) {
+        this.$message.warning("请先选择一个项目");
+        return;
+      }
+      const selectedProject = this.projectOptions.find(
+        (p) => p.id === this.currentProjectId
+      );
+
+      const loading = this.$loading({
+        lock: true,
+        text: "正在创建项目...",
+        spinner: "el-icon-loading",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+
+      try {
+        const res = await create_items({
+          project_id: selectedProject.id,
+          project_name: selectedProject.name,
+        });
+
+        if (res.status !== 200) {
+          throw new Error("创建失败");
+        }
+
+        this.$message.success(
+          `成功创建 ${res.data.data.created_count} 个输入项目!`
+        );
+        await this.fetchGsprData();
+      } catch (error) {
+        this.$message.error("创建失败: " + (error.message || "未知错误"));
+      } finally {
+        loading.close();
+      }
+    },
+
+    // 新增更新项目的方法
+    async handleUpdateGspr() {
+      if (!this.currentProjectId) {
+        this.$message.warning("请先选择一个项目");
+        return;
+      }
+      const selectedProject = this.projectOptions.find(
+        (p) => p.id === this.currentProjectId
+      );
+
+      try {
+        await this.$confirm(
+          "此操作将更新当前项目的所有输入项目,是否继续?",
+          "提示",
+          {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning",
+          }
+        );
+
+        const loading = this.$loading({
+          lock: true,
+          text: "正在更新项目...",
+          spinner: "el-icon-loading",
+          background: "rgba(0, 0, 0, 0.7)",
+        });
+
+        try {
+          const res = await update_items({
+            // 假设有一个update_items的API
+            project_id: selectedProject.id,
+            project_name: selectedProject.name,
+          });
+
+          if (res.status !== 200) {
+            throw new Error("更新失败");
+          }
+
+          this.$message.success(
+            `成功更新 ${res.data.data.updated_count} 个输入项目!`
+          );
+          await this.fetchGsprData();
+        } finally {
+          loading.close();
+        }
+      } catch (error) {
+        if (error !== "cancel") {
+          this.$message.error("更新失败: " + (error.message || "未知错误"));
+        }
+      }
+    },
     /* 编辑内容 */
     handleEditContent(row) {
+      const selectedProject = this.projectOptions.find(
+        (p) => p.id === this.currentProjectId
+      );
       this.contentForm = {
+        project: selectedProject.id,
+        project_name: selectedProject.name,
         id: row.id,
+        tech_report_location: row.tech_report_location,
         content: row.content,
         name: row.name,
         department: row.department,
@@ -528,10 +891,10 @@ export default {
     // 新增:处理标签页切换
     handleTabClick(tab) {
       if (tab.name === "second" && !this.isSecondTabLoaded) {
-         this.fetchData();
+        this.fetchData();
         this.isSecondTabLoaded = false;
       } else {
-       this.fetchGsprData();
+        this.fetchGsprData();
         this.isSecondTabLoaded = true;
       }
     },
@@ -563,6 +926,10 @@ export default {
     },
     // 修改 fetchGsprData 方法,添加搜索参数
     async fetchGsprData() {
+      if (!this.currentProjectId) {
+        return; // 如果没有选择项目,直接返回
+      }
+
       const loading = this.$loading({
         lock: true,
         text: "加载中...",
@@ -574,6 +941,7 @@ export default {
         const params = {
           sort_field: this.sort_field,
           sort_order: this.sort_order,
+          project_id: this.currentProjectId,
           ...this.gsprPageForm,
           ...this.gsprSearchForm,
         };
@@ -581,6 +949,7 @@ export default {
         if (response.status === 200) {
           this.gsprTableData = response.data.list;
           this.gsprTotal = response.data.total;
+          this.hasExistingData = this.gsprTotal > 0;
         }
       } catch (error) {
         console.error("获取数据失败:", error);
@@ -602,7 +971,7 @@ export default {
     },
 
     // GSPR表单操作
-    handleAddGspr() {
+    /* handleAddGspr() {
       this.gsprDialogTitle = "新增文献项目";
       this.gsprForm = {
         name: "",
@@ -611,11 +980,12 @@ export default {
         status: 5,
       };
       this.gsprDialogVisible = true;
-    },
+    }, */
 
     handleEditGspr(row) {
       this.gsprDialogTitle = "编辑文献项目";
       this.gsprForm = { ...row };
+      console.log(this.gsprForm);
       this.gsprDialogVisible = true;
     },
 
@@ -669,6 +1039,12 @@ export default {
 </script>
   
   <style scoped>
+.project-selector {
+  margin-bottom: 20px;
+}
+/* .el-form-item {
+  margin-bottom: 0;
+} */
 .template-location-container {
   padding: 20px;
 }
@@ -679,4 +1055,17 @@ export default {
   display: flex;
   justify-content: end;
 }
+.delete-warning {
+  padding: 12px 16px;
+  background-color: #fdf6ec;
+  border-radius: 4px;
+  color: #e6a23c;
+  line-height: 1.4;
+  font-size: 14px;
+  display: flex;
+  align-items: center;
+}
+::v-deep .el-tabs__nav-wrap::after {
+  width: 13%;
+}
 </style>

部分文件因文件數量過多而無法顯示