Просмотр исходного кода

合同内项目信息路由跳转问题

lamphua 3 месяцев назад
Родитель
Сommit
2987409869

+ 2
- 2
oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java Просмотреть файл

89
             List<Long> userPostList = postService.selectPostListByUserId(sysUser.getUserId());
89
             List<Long> userPostList = postService.selectPostListByUserId(sysUser.getUserId());
90
             if (userPostList.size() > 0) {
90
             if (userPostList.size() > 0) {
91
                 for (Long post : userPostList)
91
                 for (Long post : userPostList)
92
-                    postName.append(postService.selectPostById(post).getPostName()).append("");
92
+                    postName.append(postService.selectPostById(post).getPostName()).append("/");
93
                 sysUser.setPostNames(postName.substring(0, postName.length() - 1));
93
                 sysUser.setPostNames(postName.substring(0, postName.length() - 1));
94
             }
94
             }
95
         }
95
         }
108
             StringBuilder postName = new StringBuilder();
108
             StringBuilder postName = new StringBuilder();
109
             List<Long> userPostList = postService.selectPostListByUserId(sysUser.getUserId());
109
             List<Long> userPostList = postService.selectPostListByUserId(sysUser.getUserId());
110
             for (Long post : userPostList)
110
             for (Long post : userPostList)
111
-                postName.append(postService.selectPostById(post).getPostName()).append("");
111
+                postName.append(postService.selectPostById(post).getPostName()).append("/");
112
             if (!postName.toString().equals(""))
112
             if (!postName.toString().equals(""))
113
                 sysUser.setPostNames(postName.substring(0, postName.length() - 1));
113
                 sysUser.setPostNames(postName.substring(0, postName.length() - 1));
114
             sysUser.setUserId(sysUser.getUserId() - 1);
114
             sysUser.setUserId(sysUser.getUserId() - 1);

+ 6
- 0
oa-back/ruoyi-agent/pom.xml Просмотреть файл

83
             <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
83
             <artifactId>langchain4j-document-parser-apache-pdfbox</artifactId>
84
             <version>0.35.0</version>
84
             <version>0.35.0</version>
85
         </dependency>
85
         </dependency>
86
+        <!-- MySQL 驱动依赖 -->
87
+        <dependency>
88
+            <groupId>mysql</groupId>
89
+            <artifactId>mysql-connector-java</artifactId>
90
+            <version>8.0.33</version>
91
+        </dependency>
86
     </dependencies>
92
     </dependencies>
87
 
93
 
88
     <dependencyManagement>
94
     <dependencyManagement>

+ 42
- 32
oa-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/impl/McpServiceImpl.java Просмотреть файл

1
 package com.ruoyi.agent.service.impl;
1
 package com.ruoyi.agent.service.impl;
2
 
2
 
3
+import com.alibaba.fastjson2.JSONArray;
3
 import com.alibaba.fastjson2.JSONObject;
4
 import com.alibaba.fastjson2.JSONObject;
4
 import com.ruoyi.agent.service.IMcpService;
5
 import com.ruoyi.agent.service.IMcpService;
5
 import dev.langchain4j.data.document.Document;
6
 import dev.langchain4j.data.document.Document;
26
 import org.apache.poi.extractor.ExtractorFactory;
27
 import org.apache.poi.extractor.ExtractorFactory;
27
 import org.apache.poi.xwpf.usermodel.*;
28
 import org.apache.poi.xwpf.usermodel.*;
28
 import org.apache.xmlbeans.XmlCursor;
29
 import org.apache.xmlbeans.XmlCursor;
29
-import org.noear.solon.Solon;
30
 import org.noear.solon.ai.annotation.ToolMapping;
30
 import org.noear.solon.ai.annotation.ToolMapping;
31
 import org.noear.solon.ai.chat.ChatModel;
31
 import org.noear.solon.ai.chat.ChatModel;
32
 import org.noear.solon.ai.chat.ChatResponse;
32
 import org.noear.solon.ai.chat.ChatResponse;
40
 import org.springframework.beans.factory.annotation.Value;
40
 import org.springframework.beans.factory.annotation.Value;
41
 import org.springframework.stereotype.Service;
41
 import org.springframework.stereotype.Service;
42
 
42
 
43
+import javax.annotation.PostConstruct;
43
 import java.io.*;
44
 import java.io.*;
44
 import java.sql.*;
45
 import java.sql.*;
45
 import java.util.*;
46
 import java.util.*;
50
 
51
 
51
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
52
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
52
 
53
 
53
-    @Value("${llmService.url}")
54
-    private static String llmServiceUrl;
54
+    @Value("${cmc.llmService.url}")
55
+    private String llmServiceUrl;
55
 
56
 
56
-    @Value("${lmilvusService.url}")
57
-    private static String milvusServiceUrl;
57
+    @Value("${cmc.milvusService.url}")
58
+    private String milvusServiceUrl;
58
 
59
 
59
-    @Value("${mysqlService.jdbcUrl}")
60
-    private static String url ;
60
+    @Value("${cmc.mysqlService.jdbcUrl}")
61
+    private String url ;
61
 
62
 
62
-    @Value("${mysqlService.username}")
63
-    private static String user;
63
+    @Value("${cmc.mysqlService.username}")
64
+    private String user;
64
 
65
 
65
-    @Value("${mysqlService.password}")
66
-    private static String password;
66
+    @Value("${cmc.mysqlService.password}")
67
+    private String password;
67
 
68
 
68
     @Value("${cmc.profile}")
69
     @Value("${cmc.profile}")
69
-    private static String profile;
70
+    private String profile;
70
 
71
 
72
+    private MilvusClientV2 milvusClient;
73
+    
74
+    /**
75
+     * 初始化 Milvus 客户端
76
+     */
77
+    @PostConstruct
78
+    public void initMilvusClient() {
79
+        if (milvusServiceUrl == null || milvusServiceUrl.trim().isEmpty()) {
80
+            throw new IllegalStateException("Milvus service URL 未配置");
81
+        }
82
+//        this.milvusClient = new MilvusClientV2(
83
+//                ConnectConfig.builder()
84
+//                        .uri(milvusServiceUrl)
85
+//                        .build());
86
+    }
71
     /**
87
     /**
72
      * 调用LLM+RAG(外部文件+知识库)生成回答
88
      * 调用LLM+RAG(外部文件+知识库)生成回答
73
      */
89
      */
92
     /**
108
     /**
93
      * 查询OA数据生成回答
109
      * 查询OA数据生成回答
94
      */
110
      */
95
-    @ToolMapping(description = "数据查询")
96
-    public AssistantMessage SQLQuery(@Param(description = "sql语句") String sqlString) throws Exception
111
+    @ToolMapping(description = "执行SQL查询")
112
+    public JSONArray SQLQuery(@Param(description = "sql语句") String sqlString)
97
     {
113
     {
98
-            try {
99
-                List<Map<String, Object>> data = executeQuery(sqlString, 100.0);
100
-                return ChatMessage.ofAssistant(generateAnswer(sqlString));
101
-            } catch (IOException e) {
102
-                throw new RuntimeException(e);
103
-            }
114
+            sqlString = sqlString.replace("[","").replace("]","");
115
+            return executeQuery(sqlString);
104
     }
116
     }
105
 
117
 
106
-    public static List<Map<String, Object>> executeQuery(String sql, Object... params) {
107
-        List<Map<String, Object>> result = new ArrayList<>();
118
+    public JSONArray executeQuery(String sql) {
119
+        JSONArray result = new JSONArray();
120
+
121
+        try {
122
+            // 显式加载 MySQL 驱动
123
+            Class.forName("com.mysql.cj.jdbc.Driver");
124
+        } catch (ClassNotFoundException e) {
125
+            throw new RuntimeException("MySQL 驱动未找到", e);
126
+        }
108
 
127
 
109
         try (Connection conn = DriverManager.getConnection(url, user, password);
128
         try (Connection conn = DriverManager.getConnection(url, user, password);
110
              PreparedStatement stmt = conn.prepareStatement(sql)) {
129
              PreparedStatement stmt = conn.prepareStatement(sql)) {
111
 
130
 
112
-            // 设置参数
113
-            for (int i = 0; i < params.length; i++) {
114
-                stmt.setObject(i + 1, params[i]);
115
-            }
116
-
117
             ResultSet rs = stmt.executeQuery();
131
             ResultSet rs = stmt.executeQuery();
118
             ResultSetMetaData metaData = rs.getMetaData();
132
             ResultSetMetaData metaData = rs.getMetaData();
119
             int columnCount = metaData.getColumnCount();
133
             int columnCount = metaData.getColumnCount();
120
 
134
 
121
             while (rs.next()) {
135
             while (rs.next()) {
122
-                Map<String, Object> row = new HashMap<>();
136
+                JSONObject row = new JSONObject();
123
                 for (int i = 1; i <= columnCount; i++) {
137
                 for (int i = 1; i <= columnCount; i++) {
124
                     String columnName = metaData.getColumnLabel(i);
138
                     String columnName = metaData.getColumnLabel(i);
125
                     Object value = rs.getObject(i);
139
                     Object value = rs.getObject(i);
362
      * @return
376
      * @return
363
      */
377
      */
364
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
378
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
365
-        MilvusClientV2 milvusClient = new MilvusClientV2(
366
-                ConnectConfig.builder()
367
-                        .uri(milvusServiceUrl)
368
-                        .build());
369
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
379
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
370
 
380
 
371
         //  加载集合
381
         //  加载集合

+ 13
- 0
oa-back/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java Просмотреть файл

192
     })
192
     })
193
     private SysDept dept;
193
     private SysDept dept;
194
 
194
 
195
+    @Excel(name = "备注")
196
+    private String remark;
197
+
195
     private CmcPostSalary salary;
198
     private CmcPostSalary salary;
196
 
199
 
197
     /** 角色对象 */
200
     /** 角色对象 */
692
     {
695
     {
693
         return telephone;
696
         return telephone;
694
     }
697
     }
698
+    public String getRemark()
699
+    {
700
+        return remark;
701
+    }
702
+
703
+    public void setRemark(String remark)
704
+    {
705
+        this.remark = remark;
706
+    }
707
+
695
 
708
 
696
     @Override
709
     @Override
697
     public String toString() {
710
     public String toString() {

+ 1
- 4
oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/RagController.java Просмотреть файл

27
     @Autowired
27
     @Autowired
28
     private ILangChainMilvusService langChainMilvusService;
28
     private ILangChainMilvusService langChainMilvusService;
29
 
29
 
30
-    @Value("${llmService.url}")
31
-    private String llmServiceUrl;
32
-
33
     /**
30
     /**
34
      * 调用LLM+RAG(知识库)生成回答
31
      * 调用LLM+RAG(知识库)生成回答
35
      */
32
      */
36
     @GetMapping("/answer")
33
     @GetMapping("/answer")
37
     public Flux<AssistantMessage> answerWithCollection(String collectionName, String topicId, String question) throws IOException {
34
     public Flux<AssistantMessage> answerWithCollection(String collectionName, String topicId, String question) throws IOException {
38
         List<JSONObject> contexts = langChainMilvusService.retrieveFromMilvus(collectionName, question, 10);
35
         List<JSONObject> contexts = langChainMilvusService.retrieveFromMilvus(collectionName, question, 10);
39
-        return langChainMilvusService.generateAnswerWithCollection(topicId, question, contexts, llmServiceUrl);
36
+        return langChainMilvusService.generateAnswerWithCollection(topicId, question, contexts);
40
     }
37
     }
41
 
38
 
42
     /**
39
     /**

+ 86
- 5
oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/SessionController.java Просмотреть файл

1
 package com.ruoyi.web.llm.controller;
1
 package com.ruoyi.web.llm.controller;
2
 
2
 
3
+import com.alibaba.fastjson2.JSONObject;
4
+import com.ruoyi.common.config.RuoYiConfig;
3
 import com.ruoyi.common.core.controller.BaseController;
5
 import com.ruoyi.common.core.controller.BaseController;
6
+import com.ruoyi.llm.domain.CmcChat;
7
+import com.ruoyi.llm.service.ICmcChatService;
4
 import com.ruoyi.web.llm.service.ILangChainMilvusService;
8
 import com.ruoyi.web.llm.service.ILangChainMilvusService;
9
+import org.noear.solon.ai.chat.ChatModel;
10
+import org.noear.solon.ai.chat.ChatResponse;
11
+import org.noear.solon.ai.chat.ChatSession;
5
 import org.noear.solon.ai.chat.message.AssistantMessage;
12
 import org.noear.solon.ai.chat.message.AssistantMessage;
13
+import org.noear.solon.ai.chat.message.ChatMessage;
14
+import org.noear.solon.ai.chat.session.InMemoryChatSession;
15
+import org.noear.solon.ai.mcp.McpChannel;
16
+import org.noear.solon.ai.mcp.client.McpClientProvider;
17
+import org.reactivestreams.Publisher;
6
 import org.springframework.beans.factory.annotation.Autowired;
18
 import org.springframework.beans.factory.annotation.Autowired;
7
 import org.springframework.beans.factory.annotation.Value;
19
 import org.springframework.beans.factory.annotation.Value;
8
 import org.springframework.web.bind.annotation.GetMapping;
20
 import org.springframework.web.bind.annotation.GetMapping;
10
 import org.springframework.web.bind.annotation.RestController;
22
 import org.springframework.web.bind.annotation.RestController;
11
 import reactor.core.publisher.Flux;
23
 import reactor.core.publisher.Flux;
12
 
24
 
13
-import java.io.IOException;
25
+import java.io.*;
26
+import java.util.ArrayList;
27
+import java.util.List;
14
 
28
 
15
 /**
29
 /**
16
  * session对话Controller
30
  * session对话Controller
17
- * 
31
+ *
18
  * @author cmc
32
  * @author cmc
19
  * @date 2025-04-08
33
  * @date 2025-04-08
20
  */
34
  */
22
 @RequestMapping("/llm/session")
36
 @RequestMapping("/llm/session")
23
 public class SessionController extends BaseController
37
 public class SessionController extends BaseController
24
 {
38
 {
39
+    @Autowired
40
+    private ICmcChatService cmcChatService;
41
+
25
     @Autowired
42
     @Autowired
26
     private ILangChainMilvusService langChainMilvusService;
43
     private ILangChainMilvusService langChainMilvusService;
27
 
44
 
32
      * 生成回答
49
      * 生成回答
33
      */
50
      */
34
     @GetMapping("/answer")
51
     @GetMapping("/answer")
35
-    public Flux<AssistantMessage> answer(String topicId, String question) {
36
-        return langChainMilvusService.generateAnswer(topicId, question, llmServiceUrl);
52
+    public Flux<AssistantMessage> answer(String topicId, String question) throws IOException {
53
+        McpClientProvider clientProvider = McpClientProvider.builder()
54
+                .channel(McpChannel.SSE)
55
+                .url("http://localhost:8080/mcp/sse")
56
+                .build();
57
+        ChatModel chatModel = ChatModel.of(llmServiceUrl)
58
+                .model("Qwen2.5-7B-Instruct")
59
+                .defaultToolsAdd(clientProvider)
60
+                .build();
61
+
62
+        List<ChatMessage> messages = new ArrayList<>();
63
+        CmcChat cmcChat = new CmcChat();
64
+        cmcChat.setTopicId(topicId);
65
+        List<CmcChat> cmcChatList = cmcChatService.selectCmcChatList(cmcChat);
66
+        for (CmcChat chat : cmcChatList) {
67
+            messages.add(ChatMessage.ofUser(chat.getInput()));
68
+            messages.add(ChatMessage.ofAssistant(chat.getOutput()));
69
+        }
70
+        StringBuilder sqlContent = new StringBuilder();
71
+        File sqlStructure = new File(RuoYiConfig.getProfile() + "/cmc_oa.sql");
72
+        try (BufferedReader br = new BufferedReader(new FileReader(sqlStructure))) {
73
+            String line;
74
+
75
+            while ((line = br.readLine()) != null) {
76
+                sqlContent.append(line).append("\n");
77
+            }
78
+        } catch (IOException e) {
79
+            System.err.println("读取文件时出错: " + e.getMessage());
80
+        }
81
+
82
+        String prompt = "你是一个MySQL专家。根据以下OA系统表结构信息:  \n" +
83
+                sqlContent + " \n" +
84
+                "用户查询:  \n"+
85
+                question  + " \n"+
86
+                "你可以使用SQLQuery工具来查询OA系统数据。  \n" +
87
+                "SQLQuery工具功能:执行SQL查询语句,获取OA系统数据  \n" +
88
+                "工具参数:sqlString(需要执行的SQL语句,格式为[SQL语句])  \n" +
89
+                "要求:  \n" +
90
+                "1. 根据用户查询需求,决定是否需要查询数据  \n" +
91
+                "2. 如果需要查询数据,调用SQLQuery工具并传入正确的SQL语句  \n" +
92
+                "3. 生成标准MYSQL查询语句,根据语义和字段类型使用COUNT/SUM/AVG等聚合函数  \n" +
93
+                "4. 如果单表字段不满足查询需求,根据OA系统表结构信息进行多张表连接查询  \n" +
94
+                "5. 给生成的字段取一个简短的中文名称  \n" +
95
+                "6. 输出格式:使用[]包含sql文本,例如:[select 1 from dual]\n";
96
+        messages.add(ChatMessage.ofUser(prompt));
97
+        ChatSession chatSession =  InMemoryChatSession.builder().messages(messages).build();
98
+        ChatResponse response = chatModel.prompt(chatSession).call();
99
+        String resultContent = response.lastChoice().getMessage().getResultContent();
100
+
101
+        if (resultContent.contains("<tool_call>")) {
102
+            resultContent = resultContent.split("<tool_call>\n")[1];
103
+            String content = resultContent.replace("\n</tool_call>", "");
104
+            JSONObject jsonObject = JSONObject.parseObject(content);
105
+            String name = jsonObject.getString("name");
106
+            JSONObject arguments = jsonObject.getJSONObject("arguments");
107
+            resultContent = clientProvider.callToolAsText(name, arguments).getContent();
108
+            resultContent = "根据查询结果:\n" +
109
+                    resultContent + "回答问题:\n" +
110
+                    question + " \n";
111
+            return langChainMilvusService.generateAnswer(topicId, resultContent);
112
+        } else {
113
+            // 不需要调用工具,直接返回原始响应,避免重复调用大模型
114
+            // 创建一个包含原始响应内容的 AssistantMessage 并返回 Flux
115
+            AssistantMessage assistantMessage = ChatMessage.ofAssistant(resultContent);
116
+            return Flux.just(assistantMessage);
117
+        }
37
     }
118
     }
38
 
119
 
39
     /**
120
     /**
42
     @GetMapping("/answerWithDocument")
123
     @GetMapping("/answerWithDocument")
43
     public Flux<AssistantMessage> answerWithDocument(String topicId, String chatId, String question) throws Exception
124
     public Flux<AssistantMessage> answerWithDocument(String topicId, String chatId, String question) throws Exception
44
     {
125
     {
45
-        return langChainMilvusService.generateAnswerWithDocument(topicId, chatId, question, llmServiceUrl);
126
+        return langChainMilvusService.generateAnswerWithDocument(topicId, chatId, question);
46
     }
127
     }
47
 
128
 
48
 }
129
 }

+ 4
- 5
oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/ILangChainMilvusService.java Просмотреть файл

5
 import org.springframework.web.multipart.MultipartFile;
5
 import org.springframework.web.multipart.MultipartFile;
6
 import reactor.core.publisher.Flux;
6
 import reactor.core.publisher.Flux;
7
 
7
 
8
-import java.io.FileNotFoundException;
9
 import java.io.IOException;
8
 import java.io.IOException;
10
 import java.util.List;
9
 import java.util.List;
11
 
10
 
40
      * 调用LLM生成回答
39
      * 调用LLM生成回答
41
      * @return
40
      * @return
42
      */
41
      */
43
-    public Flux<AssistantMessage> generateAnswer(String topicId, String question, String llmServiceUrl);
42
+    public Flux<AssistantMessage> generateAnswer(String topicId, String question);
44
 
43
 
45
     /**
44
     /**
46
      * 调用LLM+RAG(知识库)生成回答
45
      * 调用LLM+RAG(知识库)生成回答
47
      * @return
46
      * @return
48
      */
47
      */
49
-    public Flux<AssistantMessage> generateAnswerWithCollection(String topicId, String question, List<JSONObject> contexts, String llmServiceUrl);
48
+    public Flux<AssistantMessage> generateAnswerWithCollection(String topicId, String question, List<JSONObject> contexts);
50
 
49
 
51
     /**
50
     /**
52
      * 调用LLM+RAG(外部文件)生成回答
51
      * 调用LLM+RAG(外部文件)生成回答
53
      * @return
52
      * @return
54
      */
53
      */
55
-    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws Exception;
54
+    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question) throws Exception;
56
 
55
 
57
     /**
56
     /**
58
      * 调用LLM+RAG(外部文件+知识库)生成回答
57
      * 调用LLM+RAG(外部文件+知识库)生成回答
59
      * @return
58
      * @return
60
      */
59
      */
61
-    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question,  List<JSONObject> requests, String llmServiceUrl) throws Exception;
60
+    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question,  List<JSONObject> requests) throws Exception;
62
 
61
 
63
     /**
62
     /**
64
      * 获取二级标题下三级标题列表
63
      * 获取二级标题下三级标题列表

+ 27
- 17
oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/LangChainMilvusServiceImpl.java Просмотреть файл

49
 import org.springframework.web.multipart.MultipartFile;
49
 import org.springframework.web.multipart.MultipartFile;
50
 import reactor.core.publisher.Flux;
50
 import reactor.core.publisher.Flux;
51
 
51
 
52
+import javax.annotation.PostConstruct;
52
 import java.io.*;
53
 import java.io.*;
53
 import java.util.*;
54
 import java.util.*;
54
 
55
 
71
     @Value("${milvusService.url}")
72
     @Value("${milvusService.url}")
72
     private String milvusServiceUrl;
73
     private String milvusServiceUrl;
73
 
74
 
75
+    private MilvusClientV2 milvusClient;
76
+
77
+    @PostConstruct
78
+    public void initMilvusClient() {
79
+        if (milvusServiceUrl == null || milvusServiceUrl.isEmpty()) {
80
+            throw new IllegalArgumentException("milvusServiceUrl 配置不能为空");
81
+        }
82
+//        milvusClient = new MilvusClientV2(
83
+//                ConnectConfig.builder()
84
+//                        .uri(milvusServiceUrl)
85
+//                        .build());
86
+    }
87
+
74
     /**
88
     /**
75
      * 上传多文件
89
      * 上传多文件
76
      *
90
      *
87
     @Override
101
     @Override
88
     public int insertLangchainEmbeddingDocument(MultipartFile[] fileList, String collectionName)
102
     public int insertLangchainEmbeddingDocument(MultipartFile[] fileList, String collectionName)
89
     {
103
     {
90
-        MilvusClientV2 milvusClient = new MilvusClientV2(
91
-                ConnectConfig.builder()
92
-                        .uri(llmServiceUrl)
93
-                        .build());
94
         processValue = "";
104
         processValue = "";
95
         int successfullyInsertedFiles = 0;
105
         int successfullyInsertedFiles = 0;
96
 
106
 
97
         for (int i = 0; i < fileList.length; i++) {
107
         for (int i = 0; i < fileList.length; i++) {
98
             MultipartFile file = fileList[i];
108
             MultipartFile file = fileList[i];
99
             try {
109
             try {
100
-                File profilePath = new File( RuoYiConfig.getProfile() + "/upload/rag/knowledge/" + collectionName);
110
+                // 构建上传目录路径
111
+                String uploadDir = RuoYiConfig.getProfile() + "/upload/rag/knowledge/" + collectionName;
112
+                File profilePath = new File(uploadDir);
113
+                
114
+                // 确保目录存在,创建目录并设置权限
101
                 if (!profilePath.exists())
115
                 if (!profilePath.exists())
102
                     profilePath.mkdirs();
116
                     profilePath.mkdirs();
103
-                File transferFile = new File( profilePath + "/" + file.getOriginalFilename());
117
+                File transferFile = new File(profilePath, file.getOriginalFilename());
104
                 if (!transferFile.exists())
118
                 if (!transferFile.exists())
105
                     file.transferTo(transferFile);
119
                     file.transferTo(transferFile);
106
                 List<TextSegment> segments = splitDocument(transferFile);
120
                 List<TextSegment> segments = splitDocument(transferFile);
213
      * @return
227
      * @return
214
      */
228
      */
215
     @Override
229
     @Override
216
-    public Flux<AssistantMessage> generateAnswer(String topicId, String prompt, String llmServiceUrl) {
230
+    public Flux<AssistantMessage> generateAnswer(String topicId, String prompt) {
217
         ChatModel chatModel = ChatModel.of(llmServiceUrl)
231
         ChatModel chatModel = ChatModel.of(llmServiceUrl)
218
 
232
 
219
                 .model("Qwen2.5-7B-Instruct")
233
                 .model("Qwen2.5-7B-Instruct")
241
      * @return
255
      * @return
242
      */
256
      */
243
     @Override
257
     @Override
244
-    public Flux<AssistantMessage> generateAnswerWithCollection(String topicId, String question, List<JSONObject> contexts, String llmServiceUrl) {
258
+    public Flux<AssistantMessage> generateAnswerWithCollection(String topicId, String question, List<JSONObject> contexts) {
245
         StringBuilder sb = new StringBuilder();
259
         StringBuilder sb = new StringBuilder();
246
         sb.append("问题: ").append(question).append("\n\n");
260
         sb.append("问题: ").append(question).append("\n\n");
247
         sb.append("根据以下上下文回答问题:\n\n");
261
         sb.append("根据以下上下文回答问题:\n\n");
251
                     .append("上下文").append(": ")
265
                     .append("上下文").append(": ")
252
                     .append(context.getString("content")).append("\n\n");
266
                     .append(context.getString("content")).append("\n\n");
253
         }
267
         }
254
-        return generateAnswer(topicId, sb.toString(), llmServiceUrl);
268
+        return generateAnswer(topicId, sb.toString());
255
     }
269
     }
256
 
270
 
257
     /**
271
     /**
258
      * 调用LLM生成回答
272
      * 调用LLM生成回答
259
      */
273
      */
260
     @Override
274
     @Override
261
-    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws Exception {
275
+    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question) throws Exception {
262
         CmcDocument cmcDocument = new CmcDocument();
276
         CmcDocument cmcDocument = new CmcDocument();
263
         cmcDocument.setChatId(chatId);
277
         cmcDocument.setChatId(chatId);
264
         List<CmcDocument> documentList = cmcDocumentService.selectCmcDocumentList(cmcDocument);
278
         List<CmcDocument> documentList = cmcDocumentService.selectCmcDocumentList(cmcDocument);
284
                         .append(contexts).append("\n\n");
298
                         .append(contexts).append("\n\n");
285
             }
299
             }
286
         }
300
         }
287
-        return generateAnswer(topicId, sb.toString(), llmServiceUrl);
301
+        return generateAnswer(topicId, sb.toString());
288
     }
302
     }
289
 
303
 
290
     /**
304
     /**
291
      * 调用LLM生成回答
305
      * 调用LLM生成回答
292
      */
306
      */
293
     @Override
307
     @Override
294
-    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question, List<JSONObject> contexts, String llmServiceUrl) throws Exception {
308
+    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question, List<JSONObject> contexts) throws Exception {
295
         StringBuilder sb = new StringBuilder("招标文件内容:\n\n");
309
         StringBuilder sb = new StringBuilder("招标文件内容:\n\n");
296
         CmcChat cmcChat = new CmcChat();
310
         CmcChat cmcChat = new CmcChat();
297
         cmcChat.setTopicId(topicId);
311
         cmcChat.setTopicId(topicId);
328
 //                    .append("段落格式").append(": ")
342
 //                    .append("段落格式").append(": ")
329
 //                    .append(context.getString("content")).append("\n\n");
343
 //                    .append(context.getString("content")).append("\n\n");
330
 //        }
344
 //        }
331
-        return generateAnswer(topicId, sb.toString(), llmServiceUrl);
345
+        return generateAnswer(topicId, sb.toString());
332
     }
346
     }
333
 
347
 
334
     /**
348
     /**
374
      * @return
388
      * @return
375
      */
389
      */
376
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
390
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
377
-        MilvusClientV2 milvusClient = new MilvusClientV2(
378
-                ConnectConfig.builder()
379
-                        .uri(milvusServiceUrl)
380
-                        .build());
381
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
391
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
382
 
392
 
383
         //  加载集合
393
         //  加载集合

+ 14
- 32
oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/MilvusServiceImpl.java Просмотреть файл

16
 import org.springframework.beans.factory.annotation.Value;
16
 import org.springframework.beans.factory.annotation.Value;
17
 import org.springframework.stereotype.Service;
17
 import org.springframework.stereotype.Service;
18
 
18
 
19
+import javax.annotation.PostConstruct;
19
 import java.text.SimpleDateFormat;
20
 import java.text.SimpleDateFormat;
20
 import java.util.*;
21
 import java.util.*;
21
 import java.util.stream.Collectors;
22
 import java.util.stream.Collectors;
26
     @Value("${milvusService.url}")
27
     @Value("${milvusService.url}")
27
     private String milvusServiceUrl;
28
     private String milvusServiceUrl;
28
 
29
 
30
+    private MilvusClientV2 milvusClient;
31
+
32
+    @PostConstruct
33
+    public void initMilvusClient() {
34
+        if (milvusServiceUrl == null || milvusServiceUrl.isEmpty()) {
35
+            throw new IllegalArgumentException("milvusServiceUrl 配置不能为空");
36
+        }
37
+//        milvusClient = new MilvusClientV2(
38
+//                ConnectConfig.builder()
39
+//                        .uri(milvusServiceUrl)
40
+//                        .build());
41
+    }
42
+
29
     /**
43
     /**
30
      * 新建知识库Collection(含Schema、Field、Index)
44
      * 新建知识库Collection(含Schema、Field、Index)
31
      */
45
      */
32
     @Override
46
     @Override
33
     public void createCollection(String collectionName, String description, int dimension) {
47
     public void createCollection(String collectionName, String description, int dimension) {
34
-        MilvusClientV2 milvusClient = new MilvusClientV2(
35
-                ConnectConfig.builder()
36
-                        .uri(milvusServiceUrl)
37
-                        .build());
38
         CreateCollectionReq.CollectionSchema schema = MilvusClientV2.CreateSchema();
48
         CreateCollectionReq.CollectionSchema schema = MilvusClientV2.CreateSchema();
39
 
49
 
40
         schema.addField(AddFieldReq.builder()
50
         schema.addField(AddFieldReq.builder()
93
      */
103
      */
94
     @Override
104
     @Override
95
     public JSONArray getCollectionNames() {
105
     public JSONArray getCollectionNames() {
96
-        MilvusClientV2 milvusClient = new MilvusClientV2(
97
-                ConnectConfig.builder()
98
-                        .uri(milvusServiceUrl)
99
-                        .build());
100
         JSONArray jsonArray = new JSONArray();
106
         JSONArray jsonArray = new JSONArray();
101
         ListCollectionsResp listResponse = milvusClient.listCollections();
107
         ListCollectionsResp listResponse = milvusClient.listCollections();
102
         if (listResponse != null) {
108
         if (listResponse != null) {
126
      */
132
      */
127
     @Override
133
     @Override
128
     public JSONArray listKnowLedgeByCollectionName(String collectionName) {
134
     public JSONArray listKnowLedgeByCollectionName(String collectionName) {
129
-        MilvusClientV2 milvusClient = new MilvusClientV2(
130
-                ConnectConfig.builder()
131
-                        .uri(milvusServiceUrl)
132
-                        .build());
133
         JSONArray jsonArray = new JSONArray();
135
         JSONArray jsonArray = new JSONArray();
134
         ListCollectionsResp listResponse = milvusClient.listCollections();
136
         ListCollectionsResp listResponse = milvusClient.listCollections();
135
 
137
 
161
      */
163
      */
162
     @Override
164
     @Override
163
     public void collectionRename(String collectionName, String newCollectionName) {
165
     public void collectionRename(String collectionName, String newCollectionName) {
164
-        MilvusClientV2 milvusClient = new MilvusClientV2(
165
-                ConnectConfig.builder()
166
-                        .uri(milvusServiceUrl)
167
-                        .build());
168
         RenameCollectionReq renameCollectionReq = RenameCollectionReq.builder()
166
         RenameCollectionReq renameCollectionReq = RenameCollectionReq.builder()
169
                 .collectionName(collectionName)
167
                 .collectionName(collectionName)
170
                 .newCollectionName(newCollectionName)
168
                 .newCollectionName(newCollectionName)
178
      */
176
      */
179
     @Override
177
     @Override
180
     public void deleteCollectionName(String collectionName) {
178
     public void deleteCollectionName(String collectionName) {
181
-        MilvusClientV2 milvusClient = new MilvusClientV2(
182
-                ConnectConfig.builder()
183
-                        .uri(milvusServiceUrl)
184
-                        .build());
185
         DropCollectionReq dropCollectionReq = DropCollectionReq.builder()
179
         DropCollectionReq dropCollectionReq = DropCollectionReq.builder()
186
                 .collectionName(collectionName)
180
                 .collectionName(collectionName)
187
                 .build();
181
                 .build();
193
      */
187
      */
194
     @Override
188
     @Override
195
     public List<String> listDocument(String collectionName, String fileType) {
189
     public List<String> listDocument(String collectionName, String fileType) {
196
-        MilvusClientV2 milvusClient = new MilvusClientV2(
197
-                ConnectConfig.builder()
198
-                        .uri(milvusServiceUrl)
199
-                        .build());
200
         List<String> documentList = new ArrayList<>();
190
         List<String> documentList = new ArrayList<>();
201
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
191
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
202
                 .collectionName(collectionName)
192
                 .collectionName(collectionName)
233
      */
223
      */
234
     @Override
224
     @Override
235
     public void removeDocument(String collectionName, String fileName) {
225
     public void removeDocument(String collectionName, String fileName) {
236
-        MilvusClientV2 milvusClient = new MilvusClientV2(
237
-                ConnectConfig.builder()
238
-                        .uri(milvusServiceUrl)
239
-                        .build());
240
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
226
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
241
                 .collectionName(collectionName)
227
                 .collectionName(collectionName)
242
                 .build();
228
                 .build();
253
      */
239
      */
254
     @Override
240
     @Override
255
     public void removeAllDocument(String collectionName) {
241
     public void removeAllDocument(String collectionName) {
256
-        MilvusClientV2 milvusClient = new MilvusClientV2(
257
-                ConnectConfig.builder()
258
-                        .uri(milvusServiceUrl)
259
-                        .build());
260
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
242
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
261
                 .collectionName(collectionName)
243
                 .collectionName(collectionName)
262
                 .build();
244
                 .build();

+ 0
- 1
oa-back/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java Просмотреть файл

1
 package com.ruoyi.quartz.task;
1
 package com.ruoyi.quartz.task;
2
 
2
 
3
-import com.ruoyi.common.utils.spring.SpringUtils;
4
 import com.ruoyi.system.service.ISysLogininforService;
3
 import com.ruoyi.system.service.ISysLogininforService;
5
 import com.ruoyi.system.service.ISysOperLogService;
4
 import com.ruoyi.system.service.ISysOperLogService;
6
 import org.springframework.beans.factory.annotation.Autowired;
5
 import org.springframework.beans.factory.annotation.Autowired;

+ 19
- 3
oa-ui/src/views/contractStatistic/components/projectStatistic.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-12-17 10:32:27
3
  * @Date: 2024-12-17 10:32:27
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-12-19 16:25:46
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2026-01-08 14:56:17
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div>
8
   <div>
85
     rowClickFn(row) {
85
     rowClickFn(row) {
86
       this.$router.replace({ query: { ...this.$route.query, projectId: row.projectId } });
86
       this.$router.replace({ query: { ...this.$route.query, projectId: row.projectId } });
87
       this.drawerOpen = true;
87
       this.drawerOpen = true;
88
+      // 找到当前tab并修改当前tab显示的标题
89
+      let currentView = this.$store.state.tagsView.visitedViews.find(item => item.path === this.$route.path);
90
+      if (currentView != null) {
91
+        currentView.title = row.projectName;
92
+      }
88
     },
93
     },
89
     closeDrawerFn(){
94
     closeDrawerFn(){
90
-      this.$router.replace({ path: '/statistics/contractStatistic' }); 
95
+      this.drawerOpen = false;
96
+      // 只需要删除 query 中的 projectId参数,保留其他参数
97
+      const { projectId, ...otherQuery } = this.$route.query;
98
+      this.$router.replace({ 
99
+        path: this.$route.path, 
100
+        query: otherQuery 
101
+      });
102
+      // 找到当前tab并修改当前tab显示的标题为"合同统计"
103
+      let currentView = this.$store.state.tagsView.visitedViews.find(item => item.path === this.$route.path);
104
+      if (currentView != null) {
105
+        currentView.title = '合同统计';
106
+      }
91
     }
107
     }
92
   },
108
   },
93
 }
109
 }

+ 22
- 3
oa-ui/src/views/flowable/form/business/contractForm.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-05-10 15:31:57
3
  * @Date: 2024-05-10 15:31:57
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-08-15 09:38:15
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2026-01-08 14:57:18
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
392
     <el-dialog :visible.sync="subOpen" title="选择分包合同" :size="'70%'" append-to-body>
392
     <el-dialog :visible.sync="subOpen" title="选择分包合同" :size="'70%'" append-to-body>
393
       <choose-subcontract @choose="confirmSubContract"></choose-subcontract>
393
       <choose-subcontract @choose="confirmSubContract"></choose-subcontract>
394
     </el-dialog>
394
     </el-dialog>
395
-    <el-drawer :visible.sync="drawerOpen" title="" :size="'70%'" append-to-body>
395
+    <el-drawer :visible.sync="drawerOpen" title="" :size="'70%'" append-to-body @close="closeDrawerFn">
396
       <projectInfo :needReturn="false"></projectInfo>
396
       <projectInfo :needReturn="false"></projectInfo>
397
     </el-drawer>
397
     </el-drawer>
398
     <el-drawer :visible.sync="subInfoOpen" title="" :size="'55%'" append-to-body>
398
     <el-drawer :visible.sync="subInfoOpen" title="" :size="'55%'" append-to-body>
1217
     clickProjectFn(row) {
1217
     clickProjectFn(row) {
1218
       this.$router.replace({ query: { ...this.$route.query, projectId: row.projectId } });
1218
       this.$router.replace({ query: { ...this.$route.query, projectId: row.projectId } });
1219
       this.drawerOpen = true;
1219
       this.drawerOpen = true;
1220
+      // 找到当前tab并修改当前tab显示的标题
1221
+      let currentView = this.$store.state.tagsView.visitedViews.find(item => item.path === this.$route.path);
1222
+      if (currentView != null) {
1223
+        currentView.title = row.projectName;
1224
+      }
1225
+    },
1226
+    closeDrawerFn() {
1227
+      this.drawerOpen = false;
1228
+      // 只需要删除 query 中的 projectId参数,保留其他参数
1229
+      const { projectId, ...otherQuery } = this.$route.query;
1230
+      this.$router.replace({ 
1231
+        path: this.$route.path, 
1232
+        query: otherQuery 
1233
+      });
1234
+      // 找到当前tab并修改当前tab显示的标题为"承接合同"
1235
+      let currentView = this.$store.state.tagsView.visitedViews.find(item => item.path === this.$route.path);
1236
+      if (currentView != null) {
1237
+        currentView.title = '承接合同';
1238
+      }
1220
     },
1239
     },
1221
     clickSubFn(row) {
1240
     clickSubFn(row) {
1222
       this.subContractId.formId = row.subContractId
1241
       this.subContractId.formId = row.subContractId

+ 8
- 3
oa-ui/src/views/llm/agent/AgentDetail.vue Просмотреть файл

531
 
531
 
532
     // 滚动到底部
532
     // 滚动到底部
533
     scrollToBottom() {
533
     scrollToBottom() {
534
-      if (this.messagesContainer) {
535
-        this.messagesContainer.scrollTop = this.messagesContainer.scrollHeight
536
-      }
534
+      // 确保在 DOM 更新后执行滚动操作
535
+      this.$nextTick(() => {
536
+        // 直接从 $refs 中获取滚动容器,确保每次都能获取到最新的 DOM 元素
537
+        const container = this.$refs.messagesContainer;
538
+        if (container) {
539
+          container.scrollTop = container.scrollHeight;
540
+        }
541
+      });
537
     },
542
     },
538
 
543
 
539
     // 聊天内文件上传相关方法
544
     // 聊天内文件上传相关方法

+ 4
- 1
oa-ui/src/views/llm/chat/index.vue Просмотреть файл

675
     scrollToBottom() {
675
     scrollToBottom() {
676
       if (this.$refs.messageScrollbar) {
676
       if (this.$refs.messageScrollbar) {
677
         const scrollbar = this.$refs.messageScrollbar;
677
         const scrollbar = this.$refs.messageScrollbar;
678
-        scrollbar.scrollTop = scrollbar.scrollHeight;
678
+        // Element UI的el-scrollbar组件内部的滚动容器是wrap DOM元素
679
+        if (scrollbar && scrollbar.wrap) {
680
+          scrollbar.wrap.scrollTop = scrollbar.wrap.scrollHeight;
681
+        }
679
       }
682
       }
680
     },
683
     },
681
 
684
 

+ 7
- 4
oa-ui/src/views/llm/knowledge/index.vue Просмотреть файл

716
 
716
 
717
     /** 滚动到底部 */
717
     /** 滚动到底部 */
718
     scrollToBottom() {
718
     scrollToBottom() {
719
-      const container = this.$refs.chatMessagesRef;
720
-      if (container) {
721
-        container.scrollTop = container.scrollHeight;
722
-      }
719
+      // 确保在 DOM 更新后执行滚动操作
720
+      this.$nextTick(() => {
721
+        const container = this.$refs.chatMessagesRef;
722
+        if (container) {
723
+          container.scrollTop = container.scrollHeight;
724
+        }
725
+      });
723
     },
726
     },
724
 
727
 
725
     /** 处理Enter键 */
728
     /** 处理Enter键 */

+ 43
- 8
oa-ui/src/views/oa/project/info.vue Просмотреть файл

288
                 <el-input disabled type="textarea" v-model="projectComment.jyComment"></el-input>
288
                 <el-input disabled type="textarea" v-model="projectComment.jyComment"></el-input>
289
                 <div class="sign mt10">
289
                 <div class="sign mt10">
290
                   <div class="mr20">签名:<span class="auditor">{{ projectComment.jyUser ? projectComment.jyUser.nickName :
290
                   <div class="mr20">签名:<span class="auditor">{{ projectComment.jyUser ? projectComment.jyUser.nickName :
291
-        ''
292
-                      }}</span>
291
+                    ''
292
+                  }}</span>
293
                   </div>
293
                   </div>
294
                   <div class="ml20"><span>审核时间:{{ projectComment.jyApprovalTime }}</span></div>
294
                   <div class="ml20"><span>审核时间:{{ projectComment.jyApprovalTime }}</span></div>
295
                 </div>
295
                 </div>
304
                 <el-input disabled type="textarea" v-model="projectComment.manageComment"></el-input>
304
                 <el-input disabled type="textarea" v-model="projectComment.manageComment"></el-input>
305
                 <div class="sign mt10">
305
                 <div class="sign mt10">
306
                   <div class="mr20">签名:<span class="auditor">{{ projectComment.managerUser ?
306
                   <div class="mr20">签名:<span class="auditor">{{ projectComment.managerUser ?
307
-        projectComment.managerUser.nickName : '' }}</span>
307
+                    projectComment.managerUser.nickName : '' }}</span>
308
                   </div>
308
                   </div>
309
                   <div class="ml20"><span>审核时间:{{ projectComment.manageApprovalTime }}</span></div>
309
                   <div class="ml20"><span>审核时间:{{ projectComment.manageApprovalTime }}</span></div>
310
                 </div>
310
                 </div>
345
               </template>
345
               </template>
346
               <el-select v-model="devices" multiple disabled style="width:100%">
346
               <el-select v-model="devices" multiple disabled style="width:100%">
347
                 <el-option v-for="item in deviceList" :key="item.deviceId" :label="item.name + '【' + (item.brand != null ? item.brand : '') + (item.series != null ? '-' + item.series + '】' : '')
347
                 <el-option v-for="item in deviceList" :key="item.deviceId" :label="item.name + '【' + (item.brand != null ? item.brand : '') + (item.series != null ? '-' + item.series + '】' : '')
348
-        + (item.code != null ? '(设备编号:' + item.code + ')' : '')" :value="item.deviceId">
348
+                  + (item.code != null ? '(设备编号:' + item.code + ')' : '')" :value="item.deviceId">
349
                 </el-option>
349
                 </el-option>
350
               </el-select>
350
               </el-select>
351
             </el-descriptions-item>
351
             </el-descriptions-item>
355
                 使用车辆
355
                 使用车辆
356
               </template>
356
               </template>
357
               <el-select v-model="cars" multiple disabled style="width:100%">
357
               <el-select v-model="cars" multiple disabled style="width:100%">
358
-                <el-option v-for="item in carList" :label="item.licensePlate + (item.brand ? item.brand : '') + (item.series ? item.series : '')" :value="item.carId"
359
-                  :key="item.carId">
358
+                <el-option v-for="item in carList"
359
+                  :label="item.licensePlate + (item.brand ? item.brand : '') + (item.series ? item.series : '')"
360
+                  :value="item.carId" :key="item.carId">
360
                 </el-option>
361
                 </el-option>
361
               </el-select>
362
               </el-select>
362
             </el-descriptions-item>
363
             </el-descriptions-item>
572
     }
573
     }
573
   },
574
   },
574
   beforeCreate() {
575
   beforeCreate() {
575
-    // 可有可无,在面包屑中展示
576
-    this.$route.meta.title = this.$route.query.projectName
577
     // 找到当前tab并修改当前tab显示的标题
576
     // 找到当前tab并修改当前tab显示的标题
578
     let currentView = this.$store.getters.visitedViews[this.$store.getters.visitedViews.findIndex(
577
     let currentView = this.$store.getters.visitedViews[this.$store.getters.visitedViews.findIndex(
579
       (item) => item.path === this.$route.path
578
       (item) => item.path === this.$route.path
599
       this.goBack();
598
       this.goBack();
600
     }
599
     }
601
   },
600
   },
601
+  watch: {
602
+    '$route.query.projectId'(newProjectId, oldProjectId) {
603
+      if (newProjectId && newProjectId !== oldProjectId) {
604
+        // 重置数据
605
+        this.project = {};
606
+        this.deptLeaderList = [];
607
+        this.projectComment = {};
608
+        this.projectChangeList = [];
609
+        this.workList = [];
610
+        this.progressList = [];
611
+        this.actualList = [];
612
+        
613
+        // 更新任务表单ID
614
+        this.taskForm.formId = newProjectId;
615
+        
616
+        // 重新加载数据
617
+        this.getProjectInfo(newProjectId);
618
+        this.getProjectWorkList(newProjectId);
619
+        this.getProjectCommentList(newProjectId);
620
+        this.getProjectProgressList(newProjectId);
621
+        this.getActualList(newProjectId);
622
+        this.getProjectChangeList(newProjectId);
623
+      }
624
+    }
625
+  },
602
   data() {
626
   data() {
603
     return {
627
     return {
604
       baseUrl: process.env.VUE_APP_BASE_API,
628
       baseUrl: process.env.VUE_APP_BASE_API,
657
           if (this.project.projectLeader == this.$store.state.user.id) {
681
           if (this.project.projectLeader == this.$store.state.user.id) {
658
             this.isProjectLeader = true;
682
             this.isProjectLeader = true;
659
           }
683
           }
684
+          // 更新标签页标题
685
+          if (this.project.projectNumber && this.project.projectName) {
686
+            const newTitle = `【${this.project.projectNumber}】${this.project.projectName}`;
687
+            this.$store.dispatch('tagsView/updateVisitedView', {
688
+              ...this.$route,
689
+              meta: {
690
+                ...this.$route.meta,
691
+                title: newTitle
692
+              }
693
+            });
694
+          }
660
           let deptArr = [];
695
           let deptArr = [];
661
           if (this.project.undertakingDept && this.project.undertakingDept.trim() !== '') {
696
           if (this.project.undertakingDept && this.project.undertakingDept.trim() !== '') {
662
             deptArr = (this.project.undertakingDept.split(',')).map(Number)
697
             deptArr = (this.project.undertakingDept.split(',')).map(Number)

Загрузка…
Отмена
Сохранить