Jelajahi Sumber

修改部分页面

yangg 8 bulan lalu
induk
melakukan
65ee5895fe

File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.html


File diff ditekan karena terlalu besar
+ 0 - 0
dist/static/css/chunk-688ed2e7.7a93a04c.css


File diff ditekan karena terlalu besar
+ 0 - 0
dist/static/js/app.bcecd9bf.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/static/js/chunk-0767fa6e.5d91a2a4.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/static/js/chunk-688ed2e7.dc6c4b0d.js


+ 63 - 2
src/api/knowledge.js

@@ -474,6 +474,7 @@ export function analysisPro(data) {
   })
 } 
 
+
 /* 文献点位列表 */
 
 export function rawSearch(data) {
@@ -508,8 +509,68 @@ export function rawImport(data) {
 
 export function rawList(data) {
   return request({
-    url: '/project-raw-data/list',
+    url: '/project-raw-data/search',
+    method: 'post',
+    data
+  })
+}
+
+/* 文献项目输入列表 project-input/list */
+
+export function projectList(data) {
+  return request({
+    url: 'project-input/search',
     method: 'post',
     data
   })
-}
+}
+
+/* 新增文献项目 project-input/add*/
+
+export function projectAdd(data) {
+  return request({
+    url: 'project-input/add',
+    method: 'post',
+    data
+  })
+}
+
+/* 获取部门 project-input/departments */
+
+export function departments(data) {
+  return request({
+    url: 'project-input/departments',
+    method: 'get',
+    data
+  })
+}
+
+/* 修改 */
+
+export function projectUpdate(data) {
+  return request({
+    url: 'project-input/update',
+    method: 'post',
+    data
+  })
+}
+
+/* 删除  */
+
+export function projectDelete(data) {
+  return request({
+    url: 'project-input/delete',
+    method: 'post',
+    data
+  })
+}
+
+/* 动作类型   */
+
+export function get_action_types(data) {
+  return request({
+    url: 'project-raw-data/get_action_types',
+    method: 'post',
+    data
+  })
+}

+ 156 - 18
src/views/document/com/components/sourceEs/index.vue

@@ -11,25 +11,31 @@
       >
         <div class="match-content">
           <span>原始值: {{ item }}</span>
-          <span>替换后: {{ item + "1" }}</span>
+          <!-- <span>替换后: {{ item  }}</span> -->
         </div>
         <div class="actions">
           <el-button size="small" @click="replaceItem(item)">替换</el-button>
         </div>
       </div>
-      <el-button type="primary" @click="replaceAll">批量替换</el-button>
+      <div style="display: flex; justify-content: flex-end; margin-top: 20px">
+        <el-button type="primary" @click="replaceAll">批量替换</el-button>
+      </div>
     </div>
   </div>
 </template>
     
     <script>
-import { searchSourceData, deleteSourceData } from "@/api/sourceData";
+import {
+  searchSourceData,
+  deleteSourceData,
+  batch_content,
+} from "@/api/sourceData";
 /* import { search } from "core-js/fn/symbol"; */
 import LuckyExcel from "luckyexcel"; //引入LuckyExcel
 import axios from "axios";
 export default {
   name: "SourceEs",
-  emits: ["onPicked"],
+  emits: ["onPicked", "close"],
   props: {
     TemList: {
       type: Array,
@@ -73,30 +79,85 @@ export default {
           allMatches = [...allMatches, ...matches];
         }
       });
-
       // 去重
       this.matchResults = [...new Set(allMatches)];
-      console.log("匹配到的结果:", this.matchResults);
+    },
+    // 格式化请求参数
+    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(() => ""),
+      };
     },
 
     // 单个替换
     replaceItem(item) {
-      this.$confirm(`确认将 ${item} 替换为 ${item}1?`, "提示", {
+      // 去掉方括号
+      const cleanItem = item.replace(/[\[\]]/g, "");
+      this.$confirm(`确认替换 ${item}?`, "提示", {
         confirmButtonText: "确定",
         cancelButtonText: "取消",
         type: "warning",
       })
-        .then(() => {
-          // 这里添加替换逻辑
-          this.$message.success("替换成功");
+        .then(async () => {
+          try {
+            // 修改这里,确保传入数组形式的参数
+            const params = this.formatRequestParams(cleanItem); /* item */
+            const response = await axios.post(
+              `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+              params,
+              {
+                headers: {
+                  "Content-Type": "application/json",
+                },
+              }
+            );
+
+            if (response.status === 200 && response.data) {
+              // 修改获取替换值的逻辑
+              const replacementValue =
+                response.data.data.input_item_contents[0].content;
+
+              if (replacementValue) {
+                this.TemList.forEach((el, index) => {
+                  this.$set(
+                    this.TemList[index],
+                    "content",
+                    el.content.replace(
+                      new RegExp(this.escapeRegExp(item), "g"),
+                      replacementValue
+                    )
+                  );
+                });
+
+                this.matchResults = this.matchResults.filter(
+                  (match) => match !== item
+                );
+                this.$message.success("替换成功");
+                this.$emit("close"); // 成功后触发关闭事件
+              } else {
+                this.$message.warning("未获取到替换内容");
+              }
+            } else {
+              this.$message.error("获取替换内容失败");
+            }
+          } catch (error) {
+            console.error("替换失败:", error);
+            this.$message.error(error.response?.data?.message || "替换失败");
+          }
         })
         .catch(() => {
           // 取消操作
         });
     },
-
-    // 批量替换
+    /*批量替换 */
     replaceAll() {
+      this.loadingAll = true;
+
       this.$confirm(
         `确认批量替换 ${this.matchResults.length} 项内容?`,
         "提示",
@@ -106,14 +167,91 @@ export default {
           type: "warning",
         }
       )
-        .then(() => {
-          // 这里添加批量替换逻辑
-          this.$message.success("批量替换成功");
+        .then(async () => {
+          try {
+            // 清理所有项的方括号
+            const cleanItems = this.matchResults.map((item) =>
+              item.replace(/[\[\]]/g, "")
+            );
+            const params = this.formatRequestParams(cleanItems);
+            const response = await axios.post(
+              `${process.env.VUE_APP_BASE_API}/project-raw-data/batch-content`,
+              params,
+              {
+                headers: {
+                  "Content-Type": "application/json",
+                },
+              }
+            );
+
+            if (response.status === 200 && response.data) {
+              // 修改这里,使用与单个替换相同的数据结构
+              const replacementValues =
+                response.data.data.input_item_contents.map(
+                  (item) => item.content
+                );
+              // 添加验证:检查是否所有值都为 null
+              if (replacementValues.every((value) => value === null)) {
+                this.$message.warning("所有替换内容均无效,请检查数据");
+                return;
+              }
+
+              // 添加验证:检查是否存在 null 值
+              const nullCount = replacementValues.filter(
+                (value) => value === null
+              ).length;
+              if (nullCount > 0) {
+                this.$message.warning(
+                  `${nullCount} 项内容无法替换,请检查数据`
+                );
+                return;
+              }
+              if (replacementValues.length > 0) {
+                this.TemList.forEach((el, index) => {
+                  let updatedContent = el.content;
+                  this.matchResults.forEach((item, idx) => {
+                    const replacementValue = replacementValues[idx];
+                    if (replacementValue) {
+                      updatedContent = updatedContent.replace(
+                        new RegExp(this.escapeRegExp(item), "g"),
+                        replacementValue
+                      );
+                    }
+                  });
+                  this.$set(this.TemList[index], "content", updatedContent);
+                });
+
+                this.matchResults = [];
+                this.$message.success("批量替换成功");
+                this.$emit("close"); // 成功后触发关闭事件
+              } else {
+                this.$message.warning("未获取到替换内容");
+              }
+            } else {
+              this.$message.error("获取替换内容失败");
+            }
+          } catch (error) {
+            console.error("批量替换失败:", error);
+            this.$message.error(
+              error.response?.data?.message || "批量替换失败"
+            );
+          }
         })
         .catch(() => {
           // 取消操作
+        })
+        .finally(() => {
+          this.loadingAll = false;
         });
     },
+    // 辅助方法:转义正则表达式特殊字符
+    // 修改 escapeRegExp 方法
+    escapeRegExp(string) {
+      // 先去掉首尾的方括号,然后转义特殊字符
+      const content = string.replace(/^\[|\]$/g, "");
+      const escaped = content.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
+      return "\\[" + escaped + "\\]";
+    },
     /* 检索当前模版的所有内容 */
     /*  searchEx() {
       console.log("TemList", this.TemList);
@@ -148,20 +286,20 @@ export default {
 <style lang="scss" scoped>
 .match-results {
   margin-top: 20px;
-  
+
   .match-item {
     padding: 10px;
     border-bottom: 1px solid #eee;
     display: flex;
     justify-content: space-between;
     align-items: center;
-    
+
     .match-content {
       flex: 1;
       display: flex;
       gap: 20px;
     }
-    
+
     .actions {
       margin-left: 10px;
     }

+ 464 - 71
src/views/templateLoca/index.vue

@@ -1,66 +1,209 @@
 <template>
   <div class="template-location-container">
-    <!-- 顶部操作栏 -->
-    <div class="operation-bar">
-      <el-button type="primary" @click="handleImport">导入模版位置表</el-button>
-      <el-button type="primary" @click="handleExport">导出模版位置表</el-button>
-    </div>
-
-    <!-- 数据列表 -->
-    <el-table :data="tableData" style="width: 100%">
-      <el-table-column prop="id" label="ID" width="80" />
-<!--       <el-table-column prop="project_id" label="项目ID" width="100" /> -->
-      <el-table-column prop="group_name" label="项目组" />
-      <el-table-column prop="project_name" label="项目名称" />
-      <el-table-column prop="action_type" label="动作类型" width="100" />
-      <el-table-column prop="template_location" label="模板位置" />
-      <el-table-column prop="middle_layer_location" label="中间层位置" />
-      <el-table-column prop="tech_report_location" label="技术报告位置" />
-      <el-table-column prop="other_location" label="其他位置" />
-      <el-table-column prop="create_time" label="创建时间" width="160" />
-      <!-- <el-table-column prop="update_time" label="更新时间" width="160" />
-      <el-table-column prop="status" label="状态" width="100">
-        <template slot-scope="scope">
-          <el-tag :type="getStatusType(scope.row.status)">
-            {{ getStatusText(scope.row.status) }}
-          </el-tag>
-        </template>
-      </el-table-column> -->
-    </el-table>
-
-    <!-- 新增/编辑弹窗 -->
-    <!--  <el-dialog :title="dialogTitle" :visible.sync="dialogVisible" width="500px">
-      <el-form :model="form" ref="form" :rules="rules" label-width="100px">
-        <el-form-item label="项目ID" prop="project_id">
-          <el-input v-model="form.project_id" />
-        </el-form-item>
-        <el-form-item label="组名" prop="group_name">
-          <el-input v-model="form.group_name" />
-        </el-form-item>
-        <el-form-item label="项目名称" prop="project_name">
-          <el-input v-model="form.project_name" />
-        </el-form-item>
-        <el-form-item label="内容" prop="content">
-          <el-input type="textarea" v-model="form.content" />
-        </el-form-item>
-        <el-form-item label="模板位置" prop="template_location">
-          <el-input v-model="form.template_location" />
-        </el-form-item>
-        <el-form-item label="状态" prop="status">
-          <el-input v-model="form.status" />
-        </el-form-item>
-      </el-form>
-      <div slot="footer">
-        <el-button @click="dialogVisible = false">取消</el-button>
-        <el-button type="primary" @click="handleSubmit">确定</el-button>
-      </div>
-    </el-dialog> -->
+    <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+      <!-- 第一个标签页 - 原有的模板位置表 -->
+      <el-tab-pane label="模板位置表" name="first">
+        <!-- 顶部操作栏 -->
+        <div class="operation-bar">
+          <el-form
+            :inline="true"
+            :model="searchForm"
+            class="search-form"
+            label-width="100px"
+          >
+            <el-form-item label="动作类型">
+              <!-- <el-input
+                v-model="searchForm.action_type"
+                placeholder="请输入动作类型"
+                clearable
+              /> -->
+              <el-select
+                v-model="searchForm.action_type"
+                placeholder="请选择动作类型"
+                clearable
+              >
+                <el-option v-for="(item,index) in typeList" :key="index" :label="item.label" :value="item.value" />
+                <!-- <el-option label="WE" value="WE" /> -->
+              </el-select>
+            </el-form-item>
+            <el-form-item label="模板位置">
+              <el-input
+                v-model="searchForm.template_location"
+                placeholder="请输入模板位置"
+                clearable
+              />
+            </el-form-item>
+            <el-form-item label="技术报告位置">
+              <el-input
+                v-model="searchForm.tech_report_location"
+                placeholder="请输入技术报告位置"
+                clearable
+              />
+            </el-form-item>
+            <el-form-item label="中间层位置">
+              <el-input
+                v-model="searchForm.middle_layer_location"
+                placeholder="请输入中间层位置"
+                clearable
+              />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" @click="handleSearch">搜索</el-button>
+              <el-button @click="handleReset">重置</el-button>
+            </el-form-item>
+          </el-form>
+          <el-button type="primary" @click="handleImport"
+            >导入模版位置表</el-button
+          >
+          <el-button type="primary" @click="handleExport"
+            >导出模版位置表</el-button
+          >
+        </div>
+
+        <!-- 数据列表 -->
+        <el-table :data="tableData" style="width: 100%">
+          <el-table-column prop="id" label="ID" width="80" />
+          <el-table-column prop="action_type" label="动作类型" width="100" />
+          <el-table-column prop="template_location" label="模板位置" />
+          <el-table-column prop="middle_layer_location" label="中间层位置" />
+          <el-table-column prop="tech_report_location" label="技术报告位置" />
+          <el-table-column prop="other_location" label="其他位置" />
+          <el-table-column prop="create_time" label="创建时间" width="160" />
+        </el-table>
+        <div class="pagination-container">
+          <el-pagination
+            @size-change="handleSizeChange"
+            @current-change="handleCurrentChange"
+            :current-page="pageForm.page"
+            :page-sizes="[10, 20, 30, 50]"
+            :page-size="pageForm.page_size"
+            layout="total, sizes, prev, pager, next, jumper"
+            :total="total"
+          />
+        </div>
+      </el-tab-pane>
+
+      <!-- 新增的第二个标签页 -->
+      <el-tab-pane label="文献项目输入表" name="second">
+        <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>
+          <el-button type="primary" @click="handleAddGspr">新增</el-button>
+        </div>
+
+        <el-table :data="gsprTableData" style="width: 100%">
+          <el-table-column prop="name" label="项目名称" />
+          <el-table-column prop="tech_report_location" label="技术报告位置" />
+          <el-table-column prop="department" label="部门" />
+          <el-table-column prop="content" label="内容" />
+          <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>
+
+        <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>
+
+        <!-- GSPR表单弹窗 -->
+        <el-dialog
+          :title="gsprDialogTitle"
+          :visible.sync="gsprDialogVisible"
+          width="700px"
+        >
+          <el-form
+            :model="gsprForm"
+            ref="gsprForm"
+            :rules="gsprRules"
+            label-width="120px"
+          >
+            <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="content">
+              <el-input v-model="gsprForm.content" />
+            </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>
+          <div slot="footer">
+            <el-button @click="gsprDialogVisible = false">取消</el-button>
+            <el-button type="primary" @click="handleGsprSubmit">确定</el-button>
+          </div>
+        </el-dialog>
+      </el-tab-pane>
+    </el-tabs>
   </div>
 </template>
   
   <script>
-import { rawSearch, export_template, rawImport,rawList } from "@/api/knowledge";
-
+import {
+  rawSearch,
+  export_template,
+  rawImport,
+  rawList,
+  projectList,
+  projectAdd,
+  departments,
+  projectUpdate,
+  projectDelete,
+  get_action_types
+} from "@/api/knowledge";
+import axios from "axios";
 export default {
   name: "TemplateLocation",
   data() {
@@ -78,8 +221,9 @@ export default {
       },
       pageForm: {
         page: 1,
-        page_size: 30,
+        page_size: 30, // 修改默认每页显示数量
       },
+      total: 0, // 添加总数据量
       rules: {
         project_id: [
           { required: true, message: "请输入项目ID", trigger: "blur" },
@@ -91,19 +235,82 @@ export default {
           { required: true, message: "请输入项目名称", trigger: "blur" },
         ],
       },
+
+      // 新增的数据
+      activeTab: "first",
+      isSecondTabLoaded: false, // 新增:标记第二个标签页是否已加载
+      gsprTableData: [],
+      gsprDialogVisible: false,
+      gsprDialogTitle: "",
+      gsprForm: {
+        id: "",
+        name: "",
+        tech_report_location: "",
+        department: "",
+        content: "",
+        status: 5,
+      },
+      gsprPageForm: {
+        page: 1,
+        page_size: 30,
+      },
+      gsprTotal: 0,
+      gsprRules: {
+        name: [{ required: true, message: "请输入名称", trigger: "blur" }],
+        tech_report_location: [
+          { required: true, message: "请输入技术报告位置", trigger: "blur" },
+        ],
+        department: [
+          { required: true, message: "请输入部门", trigger: "blur" },
+        ],
+        status: [{ required: true, message: "请选择状态", trigger: "change" }],
+      },
+      departList: [] /* 部门数据 */,
+      searchForm: {
+        action_type: "",
+        template_location: "",
+        tech_report_location: "", // 添加技术报告位置字段
+        middle_layer_location:''
+      },
+      gsprSearchForm: {
+        keyword: "",
+        department: "",
+      },
+      /* 动作类型列表 */
+      typeList:[],
     };
   },
-  created() {
+  mounted() {
     this.fetchData();
+    this.init();
   },
   methods: {
-    // 获取列表数据
+    // 第一个表格的搜索方法
+    async handleSearch() {
+      this.pageForm.page = 1;
+      await this.fetchData();
+    },
+
+    handleReset() {
+      this.searchForm = {
+        action_type: "",
+        template_location: "",
+        tech_report_location: "", // 添加技术报告位置字段
+        middle_layer_location:''
+      };
+      this.handleSearch();
+    },
+    // 修改 fetchData 方法,添加搜索参数
     async fetchData() {
       try {
-        const response = await rawList(this.pageForm);
+        const params = {
+          ...this.pageForm,
+          ...this.searchForm,
+        };
+        const response = await rawList(params);
         if (response.status === 200) {
-          console.log(response);
           this.tableData = response.data.list;
+          this.total = response.data.total;
         }
       } catch (error) {
         console.error("获取数据失败:", error);
@@ -111,6 +318,17 @@ export default {
       }
     },
 
+    // 添加分页方法
+    handleSizeChange(val) {
+      this.pageForm.page_size = val;
+      this.fetchData();
+    },
+
+    handleCurrentChange(val) {
+      this.pageForm.page = val;
+      this.fetchData();
+    },
+
     // 打开新增弹窗
     handleAdd() {
       this.dialogTitle = "新增";
@@ -127,31 +345,75 @@ export default {
 
     async handleImport() {
       try {
-        // 创建一个隐藏的文件输入框
         const input = document.createElement("input");
         input.type = "file";
         input.accept = ".xlsx,.xls";
 
         input.onchange = async (e) => {
           const file = e.target.files[0];
-          if (!file) return;
+          if (!file) {
+            this.$message.warning("请选择文件");
+            return;
+          }
+
+          // 验证文件类型
+          const validTypes = [
+            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+            "application/vnd.ms-excel",
+          ];
+          if (!validTypes.includes(file.type)) {
+            this.$message.error("请上传Excel文件(.xlsx或.xls)");
+            return;
+          }
+
+          // 验证文件大小(例如:10MB限制)
+          const maxSize = 10 * 1024 * 1024;
+          if (file.size > maxSize) {
+            this.$message.error("文件大小不能超过10MB");
+            return;
+          }
 
           const formData = new FormData();
           formData.append("file", file);
 
-          const response = await rawImport(formData);
-          if (response.status === 200) {
-            this.$message.success("导入成功");
-            this.fetchData(); // 刷新数据
-          } else {
-            this.$message.error("导入失败");
+          // 添加loading
+          const loading = this.$loading({
+            lock: true,
+            text: "正在导入...",
+            spinner: "el-icon-loading",
+            background: "rgba(0, 0, 0, 0.7)",
+          });
+
+          try {
+            // 使用 axios 直接发送请求
+            const response = await axios.post(
+              `${process.env.VUE_APP_BASE_API}/project-raw-data/import`,
+              formData,
+              {
+                headers: {
+                  "Content-Type": "multipart/form-data",
+                },
+              }
+            );
+
+            loading.close();
+
+            if (response.status === 200) {
+              this.$message.success("导入成功");
+              this.fetchData();
+            } else {
+              this.$message.error(response.data.message || "导入失败");
+            }
+          } catch (error) {
+            loading.close();
+            this.$message.error(error.response?.data?.message || "导入失败");
           }
         };
 
         input.click();
       } catch (error) {
         console.error("导入失败:", error);
-        this.$message.error("导入失败");
+        this.$message.error(error.response?.data?.message || "导入失败");
       }
     },
 
@@ -179,6 +441,133 @@ export default {
         this.$message.error("导出失败");
       }
     },
+
+    /* 新表 */
+    // 新增:处理标签页切换
+    handleTabClick(tab) {
+      if (tab.name === "second" && !this.isSecondTabLoaded) {
+        this.fetchGsprData();
+        this.isSecondTabLoaded = true;
+      } else {
+        this.fetchData();
+        this.isSecondTabLoaded = false;
+      }
+    },
+    // 第二个表格的搜索方法
+    async handleGsprSearch() {
+      this.gsprPageForm.page = 1;
+      await this.fetchGsprData();
+    },
+
+    handleGsprReset() {
+      this.gsprSearchForm = {
+        keyword: "",
+        department: "",
+      };
+      this.handleGsprSearch();
+    },
+
+    // 修改 fetchGsprData 方法,添加搜索参数
+    async fetchGsprData() {
+      const loading = this.$loading({
+        lock: true,
+        text: "加载中...",
+        spinner: "el-icon-loading",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+
+      try {
+        const params = {
+          ...this.gsprPageForm,
+          ...this.gsprSearchForm,
+        };
+        const response = await projectList(params);
+        if (response.status === 200) {
+          this.gsprTableData = response.data.list;
+          this.gsprTotal = response.data.total;
+        }
+      } catch (error) {
+        console.error("获取数据失败:", error);
+        this.$message.error("获取数据失败");
+      } finally {
+        loading.close();
+      }
+    },
+
+    // GSPR分页处理
+    handleGsprSizeChange(val) {
+      this.gsprPageForm.page_size = val;
+      this.fetchGsprData();
+    },
+
+    handleGsprCurrentChange(val) {
+      this.gsprPageForm.page = val;
+      this.fetchGsprData();
+    },
+
+    // GSPR表单操作
+    handleAddGspr() {
+      this.gsprDialogTitle = "新增文献项目";
+      this.gsprForm = {
+        name: "",
+        tech_report_location: "",
+        department: "",
+        status: 5,
+      };
+      this.gsprDialogVisible = true;
+    },
+
+    handleEditGspr(row) {
+      this.gsprDialogTitle = "编辑文献项目";
+      this.gsprForm = { ...row };
+      this.gsprDialogVisible = true;
+    },
+
+    async handleDeleteGspr(row) {
+      try {
+        await this.$confirm("确认删除该记录?", "提示", {
+          type: "warning",
+        });
+        // 替换为实际的删除API调用
+        await projectDelete({ id: row.id });
+        this.$message.success("删除成功");
+        this.fetchGsprData();
+      } catch (error) {
+        if (error !== "cancel") {
+          this.$message.error("删除失败");
+        }
+      }
+    },
+
+    async handleGsprSubmit() {
+      try {
+        await this.$refs.gsprForm.validate();
+        // 替换为实际的保存API调用
+        if (this.gsprForm.id) {
+          await projectUpdate(this.gsprForm);
+        } else {
+          await projectAdd(this.gsprForm);
+        }
+        this.$message.success(this.gsprForm.id ? "更新成功" : "创建成功");
+        this.gsprDialogVisible = false;
+        this.fetchGsprData();
+      } catch (error) {
+        if (error !== false) {
+          this.$message.error("保存失败");
+        }
+      }
+    },
+    /* 加载初始化数据 */
+    init() {
+      departments().then((res) => {
+        if (res.status !== 200) return;
+        this.departList = res.data.departments;
+      });
+      get_action_types().then(res=>{
+        if(res.status!==200) return
+       this.typeList=res.data.action_types
+      })
+    },
   },
 };
 </script>
@@ -190,4 +579,8 @@ export default {
 .operation-bar {
   margin-bottom: 20px;
 }
+.pagination-container {
+  display: flex;
+  justify-content: end;
+}
 </style>

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini