lamphua 1 месяц назад
Родитель
Сommit
992ae8ae47
40 измененных файлов: 789 добавлений и 269 удалений
  1. 6
    8
      oa-back/pom.xml
  2. 47
    0
      oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcBudgetController.java
  3. 80
    1
      oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcCheckController.java
  4. 19
    0
      oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/oa/CmcProjectController.java
  5. 7
    0
      oa-back/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
  6. 16
    8
      oa-back/ruoyi-admin/src/main/resources/application.yml
  7. 72
    9
      oa-back/ruoyi-agent/src/main/java/com/ruoyi/agent/service/impl/McpServiceImpl.java
  8. 9
    1
      oa-back/ruoyi-agent/src/main/resources/application.yml
  9. 2
    2
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/CmcAgentController.java
  10. 7
    20
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/McpController.java
  11. 7
    3
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/RagController.java
  12. 7
    3
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/controller/SessionController.java
  13. 3
    2
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/ILangChainMilvusService.java
  14. 18
    9
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/LangChainMilvusServiceImpl.java
  15. 51
    28
      oa-back/ruoyi-llm/src/main/java/com/ruoyi/web/llm/service/impl/MilvusServiceImpl.java
  16. 9
    5
      oa-back/ruoyi-system/src/main/java/com/ruoyi/llm/service/impl/CmcAgentServiceImpl.java
  17. 23
    0
      oa-back/ruoyi-system/src/main/java/com/ruoyi/oa/domain/CmcCheck.java
  18. 0
    1
      oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcArchiveMapper.xml
  19. 0
    2
      oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcBorrowMapper.xml
  20. 8
    3
      oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcCheckMapper.xml
  21. 0
    1
      oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcPerformanceStaffMapper.xml
  22. 0
    2
      oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcSettleMapper.xml
  23. 1
    0
      oa-ui/package.json
  24. 15
    0
      oa-ui/src/api/oa/budget/check.js
  25. 51
    45
      oa-ui/src/views/flowable/form/budget/addBudget.vue
  26. 2
    2
      oa-ui/src/views/flowable/form/budget/adjust/adjustIndex.vue
  27. 6
    3
      oa-ui/src/views/flowable/form/budget/adjust/budgetAdjust.vue
  28. 2
    2
      oa-ui/src/views/flowable/form/budget/adjust/newBudgetInfo.vue
  29. 3
    3
      oa-ui/src/views/flowable/form/budget/budgetInfo.vue
  30. 49
    18
      oa-ui/src/views/flowable/form/business/subContract.vue
  31. 135
    4
      oa-ui/src/views/llm/chat/index.vue
  32. 1
    0
      oa-ui/src/views/oa/budget/index.vue
  33. 7
    3
      oa-ui/src/views/oa/car/index.vue
  34. 3
    3
      oa-ui/src/views/oa/study/components/studyHead.vue
  35. 4
    4
      oa-ui/src/views/oa/study/record.vue
  36. 4
    4
      oa-ui/src/views/statistics/components/borrowStatistics.vue
  37. 16
    2
      oa-ui/src/views/statistics/components/projectStatistics.vue
  38. 89
    59
      oa-ui/src/views/statistics/components/settleStatistics.vue
  39. 10
    3
      oa-ui/src/views/statistics/index.vue
  40. 0
    6
      package-lock.json

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

178
                 <version>${cmc.version}</version>
178
                 <version>${cmc.version}</version>
179
             </dependency>
179
             </dependency>
180
 
180
 
181
-            <!-- 智能体-->
182
-            <dependency>
183
-                <groupId>com.ruoyi</groupId>
184
-                <artifactId>ruoyi-agent</artifactId>
185
-                <version>${cmc.version}</version>
186
-            </dependency>
187
-
188
             <dependency>
181
             <dependency>
189
                 <groupId>com.google.protobuf</groupId>
182
                 <groupId>com.google.protobuf</groupId>
190
                 <artifactId>protobuf-java</artifactId>
183
                 <artifactId>protobuf-java</artifactId>
191
                 <version>3.25.5</version>
184
                 <version>3.25.5</version>
192
             </dependency>
185
             </dependency>
193
 
186
 
187
+            <dependency>
188
+                <groupId>com.squareup.okhttp3</groupId>
189
+                <artifactId>okhttp</artifactId>
190
+                <version>4.12.0</version>
191
+            </dependency>
192
+
194
             <dependency>
193
             <dependency>
195
                 <groupId>com.ruoyi</groupId>
194
                 <groupId>com.ruoyi</groupId>
196
                 <artifactId>ruoyi-flowable</artifactId>
195
                 <artifactId>ruoyi-flowable</artifactId>
219
     <modules>
218
     <modules>
220
         <module>ruoyi-admin</module>
219
         <module>ruoyi-admin</module>
221
         <module>ruoyi-llm</module>
220
         <module>ruoyi-llm</module>
222
-        <module>ruoyi-agent</module>
223
         <module>ruoyi-framework</module>
221
         <module>ruoyi-framework</module>
224
         <module>ruoyi-system</module>
222
         <module>ruoyi-system</module>
225
         <module>ruoyi-quartz</module>
223
         <module>ruoyi-quartz</module>

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

1
 package com.ruoyi.web.controller.oa;
1
 package com.ruoyi.web.controller.oa;
2
 
2
 
3
+import java.math.BigDecimal;
4
+import java.text.ParseException;
5
+import java.text.SimpleDateFormat;
6
+import java.util.Calendar;
3
 import java.util.Date;
7
 import java.util.Date;
4
 import java.util.List;
8
 import java.util.List;
5
 import javax.servlet.http.HttpServletResponse;
9
 import javax.servlet.http.HttpServletResponse;
6
 
10
 
7
 
11
 
12
+import com.alibaba.fastjson2.JSONArray;
13
+import com.alibaba.fastjson2.JSONObject;
14
+import com.ruoyi.oa.domain.CmcSettle;
8
 import org.springframework.beans.factory.annotation.Autowired;
15
 import org.springframework.beans.factory.annotation.Autowired;
9
 import org.springframework.web.bind.annotation.*;
16
 import org.springframework.web.bind.annotation.*;
10
 import com.ruoyi.common.annotation.Log;
17
 import com.ruoyi.common.annotation.Log;
61
         return success(cmcBudgetService.selectCmcBudgetByBudgetId(budgetId));
68
         return success(cmcBudgetService.selectCmcBudgetByBudgetId(budgetId));
62
     }
69
     }
63
 
70
 
71
+    /**
72
+     * 获取cmc结算审批详细信息
73
+     */
74
+    @GetMapping("/statistic")
75
+    public AjaxResult getBudgetStatistic(CmcBudget cmcBudget) throws ParseException {
76
+        JSONObject jsonObject = new JSONObject();
77
+        JSONArray yearArray = new JSONArray();
78
+        JSONObject yearObject = new JSONObject();
79
+        JSONArray amountArray = new JSONArray();
80
+        JSONObject amountObject = new JSONObject();
81
+        //每年借款金额
82
+        if (cmcBudget.getZjlTime() == null) {
83
+            for (int i = 2019; i <= Calendar.getInstance().get(Calendar.YEAR); i++) {
84
+                cmcBudget.setZjlTime(new SimpleDateFormat("yyyy").parse(String.valueOf(i)));
85
+                yearObject.put(String.valueOf(i), cmcBudgetService.selectCmcBudgetList(cmcBudget).size());
86
+                BigDecimal amount = new BigDecimal(0);
87
+                for (CmcBudget budget : cmcBudgetService.selectCmcBudgetList(cmcBudget)) {
88
+                    if (budget.getTotalBudget() != null)
89
+                        amount = amount.add(budget.getTotalBudget());
90
+                }
91
+                amountObject.put(String.valueOf(i), amount);
92
+            }
93
+            cmcBudget.setZjlTime(null);
94
+        }
95
+        else {
96
+            yearObject.put(new SimpleDateFormat("yyyy").format(cmcBudget.getZjlTime()), cmcBudgetService.selectCmcBudgetList(cmcBudget).size());
97
+            BigDecimal amount = new BigDecimal(0);
98
+            for (CmcBudget budget : cmcBudgetService.selectCmcBudgetList(cmcBudget)) {
99
+                if (budget.getTotalBudget() != null)
100
+                    amount = amount.add(budget.getTotalBudget());
101
+            }
102
+            amountObject.put(new SimpleDateFormat("yyyy").format(cmcBudget.getZjlTime()), amount);
103
+        }
104
+        yearArray.add(yearObject);
105
+        amountArray.add(amountObject);
106
+        jsonObject.put("year", yearArray);
107
+        jsonObject.put("amount", amountArray);
108
+        return success(jsonObject);
109
+    }
110
+
64
     /**
111
     /**
65
      * 新增cmc预算管理
112
      * 新增cmc预算管理
66
      */
113
      */

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

1
 package com.ruoyi.web.controller.oa;
1
 package com.ruoyi.web.controller.oa;
2
 
2
 
3
+import java.math.BigDecimal;
4
+import java.text.ParseException;
5
+import java.text.SimpleDateFormat;
6
+import java.util.Calendar;
3
 import java.util.List;
7
 import java.util.List;
4
 import javax.servlet.http.HttpServletResponse;
8
 import javax.servlet.http.HttpServletResponse;
9
+
10
+import com.alibaba.fastjson2.JSONArray;
11
+import com.alibaba.fastjson2.JSONObject;
12
+import com.ruoyi.oa.domain.CmcBudget;
13
+import com.ruoyi.oa.domain.CmcCheck;
14
+import com.ruoyi.oa.domain.CmcSettle;
15
+import com.ruoyi.oa.service.ICmcBudgetService;
5
 import org.springframework.beans.factory.annotation.Autowired;
16
 import org.springframework.beans.factory.annotation.Autowired;
6
 import org.springframework.web.bind.annotation.GetMapping;
17
 import org.springframework.web.bind.annotation.GetMapping;
7
 import org.springframework.web.bind.annotation.PostMapping;
18
 import org.springframework.web.bind.annotation.PostMapping;
15
 import com.ruoyi.common.core.controller.BaseController;
26
 import com.ruoyi.common.core.controller.BaseController;
16
 import com.ruoyi.common.core.domain.AjaxResult;
27
 import com.ruoyi.common.core.domain.AjaxResult;
17
 import com.ruoyi.common.enums.BusinessType;
28
 import com.ruoyi.common.enums.BusinessType;
18
-import com.ruoyi.oa.domain.CmcCheck;
19
 import com.ruoyi.oa.service.ICmcCheckService;
29
 import com.ruoyi.oa.service.ICmcCheckService;
20
 import com.ruoyi.common.utils.poi.ExcelUtil;
30
 import com.ruoyi.common.utils.poi.ExcelUtil;
21
 import com.ruoyi.common.core.page.TableDataInfo;
31
 import com.ruoyi.common.core.page.TableDataInfo;
33
     @Autowired
43
     @Autowired
34
     private ICmcCheckService cmcCheckService;
44
     private ICmcCheckService cmcCheckService;
35
 
45
 
46
+    @Autowired
47
+    private ICmcBudgetService cmcBudgetService;
48
+
36
     /**
49
     /**
37
      * 查询cmc项目核算列表
50
      * 查询cmc项目核算列表
38
      */
51
      */
65
         return success(cmcCheckService.selectCmcCheckByCheckId(checkId));
78
         return success(cmcCheckService.selectCmcCheckByCheckId(checkId));
66
     }
79
     }
67
 
80
 
81
+    /**
82
+     * 获取cmc核算审批详细信息
83
+     */
84
+    @GetMapping("/statistic")
85
+    public AjaxResult getCheckStatistic(CmcCheck cmcCheck) throws ParseException {
86
+        JSONObject jsonObject = new JSONObject();
87
+        JSONArray yearArray = new JSONArray();
88
+        JSONObject yearObject = new JSONObject();
89
+        JSONArray amountArray = new JSONArray();
90
+        JSONObject amountObject = new JSONObject();
91
+        JSONArray yearProjectCountArray = new JSONArray();
92
+        JSONObject yearProjectCountObject = new JSONObject();
93
+        JSONArray yearProjectAmountArray = new JSONArray();
94
+        JSONObject yearProjectAmountObject = new JSONObject();
95
+        //每年核算金额
96
+        if (cmcCheck.getCheckTime() == null) {
97
+            for (int i = 2019; i <= Calendar.getInstance().get(Calendar.YEAR); i++) {
98
+                cmcCheck.setCheckTime(new SimpleDateFormat("yyyy").parse(String.valueOf(i)));
99
+                yearObject.put(String.valueOf(i), cmcCheckService.selectCmcCheckList(cmcCheck).size());
100
+                BigDecimal amount = new BigDecimal(0);
101
+                for (CmcCheck check : cmcCheckService.selectCmcCheckList(cmcCheck)) {
102
+                    if (check.getTotalAdjust() != null)
103
+                        amount = amount.add(check.getTotalAdjust());
104
+                }
105
+                amountObject.put(String.valueOf(i), amount);
106
+            }
107
+            cmcCheck.setCheckTime(null);
108
+        }
109
+        else {
110
+            yearObject.put(new SimpleDateFormat("yyyy").format(cmcCheck.getCheckTime()), cmcCheckService.selectCmcCheckList(cmcCheck).size());
111
+            BigDecimal amount = new BigDecimal(0);
112
+            for (CmcCheck check : cmcCheckService.selectCmcCheckList(cmcCheck)) {
113
+                if (check.getTotalAdjust() != null)
114
+                    amount = amount.add(check.getTotalAdjust());
115
+            }
116
+            amountObject.put(new SimpleDateFormat("yyyy").format(cmcCheck.getCheckTime()), amount);
117
+        }
118
+        getCheckProjectStatistic(cmcCheck, yearProjectCountObject, yearProjectAmountObject);
119
+        yearArray.add(yearObject);
120
+        amountArray.add(amountObject);
121
+        yearProjectCountArray.add(yearProjectCountObject);
122
+        yearProjectAmountArray.add(yearProjectAmountObject);
123
+        jsonObject.put("year", yearArray);
124
+        jsonObject.put("amount", amountArray);
125
+        jsonObject.put("yearProjectCount", yearProjectCountArray);
126
+        jsonObject.put("yearProjectAmount", yearProjectAmountArray);
127
+        return success(jsonObject);
128
+    }
129
+
68
     /**
130
     /**
69
      * 新增cmc项目核算
131
      * 新增cmc项目核算
70
      */
132
      */
94
     {
156
     {
95
         return success(cmcCheckService.deleteCmcCheckByCheckIds(checkIds));
157
         return success(cmcCheckService.deleteCmcCheckByCheckIds(checkIds));
96
     }
158
     }
159
+
160
+    public void getCheckProjectStatistic(CmcCheck cmcCheck, JSONObject yearProjectCountObject, JSONObject yearProjectAmountObject) throws ParseException {
161
+        if (cmcCheck.getCheckTime() == null)
162
+            cmcCheck.setCheckTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
163
+        for (int i = 2019; i <= Calendar.getInstance().get(Calendar.YEAR); i++) {
164
+            BigDecimal pyAmount = new BigDecimal(0);
165
+            int count = 0;
166
+            for (CmcCheck check : cmcCheckService.selectCmcCheckList(cmcCheck)) {
167
+                if (check.getTotalAdjust() != null && check.getProjectNumber() != null && check.getProjectNumber().contains(String.valueOf(i))) {
168
+                    pyAmount = pyAmount.add(check.getTotalAdjust());
169
+                    count ++;
170
+                }
171
+            }
172
+            yearProjectCountObject.put(i + "项目", count);
173
+            yearProjectAmountObject.put(i + "项目", pyAmount);
174
+        }
175
+    }
97
 }
176
 }

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

67
     @Autowired
67
     @Autowired
68
     private ICmcSettleService cmcSettleService;
68
     private ICmcSettleService cmcSettleService;
69
 
69
 
70
+    @Autowired
71
+    private ICmcCheckService cmcCheckService;
72
+
70
     @Autowired
73
     @Autowired
71
     private IFilesAchievementService filesAchievementService;
74
     private IFilesAchievementService filesAchievementService;
72
 
75
 
212
         JSONObject archiveObject = new JSONObject();
215
         JSONObject archiveObject = new JSONObject();
213
         JSONArray settleArray = new JSONArray();
216
         JSONArray settleArray = new JSONArray();
214
         JSONObject settleObject = new JSONObject();
217
         JSONObject settleObject = new JSONObject();
218
+        JSONArray checkArray = new JSONArray();
219
+        JSONObject checkObject = new JSONObject();
215
         //整体
220
         //整体
216
         if (cmcProject.getProjectNumber() == null) {
221
         if (cmcProject.getProjectNumber() == null) {
217
             //每年项目数量
222
             //每年项目数量
247
                 cmcSettle.setGmTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
252
                 cmcSettle.setGmTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
248
                 List<CmcSettle> settleList = cmcSettleService.selectCmcSettleList(cmcSettle);
253
                 List<CmcSettle> settleList = cmcSettleService.selectCmcSettleList(cmcSettle);
249
                 settleObject.put(String.valueOf(i), settleList.size());
254
                 settleObject.put(String.valueOf(i), settleList.size());
255
+                //已核算
256
+                CmcCheck cmcCheck = new CmcCheck();
257
+                cmcCheck.setProjectNumber(String.valueOf(i));
258
+                cmcCheck.setCheckTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
259
+                List<CmcCheck> checkList = cmcCheckService.selectCmcCheckList(cmcCheck);
260
+                checkObject.put(String.valueOf(i), checkList.size());
250
             }
261
             }
251
             cmcProject.setProjectNumber(null);
262
             cmcProject.setProjectNumber(null);
252
 
263
 
284
             cmcSettle.setGmTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
295
             cmcSettle.setGmTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
285
             List<CmcSettle> settleList = cmcSettleService.selectCmcSettleList(cmcSettle);
296
             List<CmcSettle> settleList = cmcSettleService.selectCmcSettleList(cmcSettle);
286
             settleObject.put(cmcProject.getProjectNumber(), settleList.size());
297
             settleObject.put(cmcProject.getProjectNumber(), settleList.size());
298
+            //已核算
299
+            CmcCheck cmcCheck = new CmcCheck();
300
+            cmcCheck.setProjectNumber(cmcProject.getProjectNumber());
301
+            cmcCheck.setCheckTime(new SimpleDateFormat("yyyy").parse("2000-01-01"));
302
+            List<CmcCheck> checkList = cmcCheckService.selectCmcCheckList(cmcCheck);
303
+            checkObject.put(cmcProject.getProjectNumber(), checkList.size());
287
 
304
 
288
         }
305
         }
289
         getProjectSourceStatistic(cmcProject, sourceObject);
306
         getProjectSourceStatistic(cmcProject, sourceObject);
296
         completeArray.add(completeObject);
313
         completeArray.add(completeObject);
297
         archiveArray.add(archiveObject);
314
         archiveArray.add(archiveObject);
298
         settleArray.add(settleObject);
315
         settleArray.add(settleObject);
316
+        checkArray.add(checkObject);
299
         jsonObject.put("year", yearArray);
317
         jsonObject.put("year", yearArray);
300
         jsonObject.put("source", sourceArray);
318
         jsonObject.put("source", sourceArray);
301
         jsonObject.put("dept", deptArray);
319
         jsonObject.put("dept", deptArray);
303
         jsonObject.put("complete", completeArray);
321
         jsonObject.put("complete", completeArray);
304
         jsonObject.put("archive", archiveArray);
322
         jsonObject.put("archive", archiveArray);
305
         jsonObject.put("settle", settleArray);
323
         jsonObject.put("settle", settleArray);
324
+        jsonObject.put("check", checkArray);
306
         return success(jsonObject);
325
         return success(jsonObject);
307
     }
326
     }
308
 
327
 

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

7
 import com.ruoyi.common.core.domain.entity.SysUser;
7
 import com.ruoyi.common.core.domain.entity.SysUser;
8
 import com.ruoyi.oa.domain.CmcManageDept;
8
 import com.ruoyi.oa.domain.CmcManageDept;
9
 import com.ruoyi.oa.service.ICmcManageDeptService;
9
 import com.ruoyi.oa.service.ICmcManageDeptService;
10
+import com.ruoyi.system.service.ISysDeptService;
10
 import com.ruoyi.system.service.ISysUserService;
11
 import com.ruoyi.system.service.ISysUserService;
11
 import org.springframework.beans.factory.annotation.Autowired;
12
 import org.springframework.beans.factory.annotation.Autowired;
12
 import org.springframework.security.access.prepost.PreAuthorize;
13
 import org.springframework.security.access.prepost.PreAuthorize;
43
     @Autowired
44
     @Autowired
44
     private  ISysUserService userService;
45
     private  ISysUserService userService;
45
 
46
 
47
+    @Autowired
48
+    private ISysDeptService deptService;
49
+
46
     @Autowired
50
     @Autowired
47
     private  ICmcManageDeptService cmcManageDeptService;
51
     private  ICmcManageDeptService cmcManageDeptService;
48
 
52
 
275
 
279
 
276
     public  List<SysUser> getManageId(String deptId, String partyAId) {
280
     public  List<SysUser> getManageId(String deptId, String partyAId) {
277
         List<SysUser> userList = new ArrayList<>();
281
         List<SysUser> userList = new ArrayList<>();
282
+        Long parentId = deptService.selectDeptById(Long.valueOf(deptId)).getParentId();
283
+        if (parentId > 100)
284
+            deptId = parentId.toString();
278
         CmcManageDept cmcManageDept = new CmcManageDept();
285
         CmcManageDept cmcManageDept = new CmcManageDept();
279
         cmcManageDept.setDeptId(deptId);
286
         cmcManageDept.setDeptId(deptId);
280
         cmcManageDept.setPartyAId(partyAId);
287
         cmcManageDept.setPartyAId(partyAId);

+ 16
- 8
oa-back/ruoyi-admin/src/main/resources/application.yml Просмотреть файл

7
   # 版权年份
7
   # 版权年份
8
   copyrightYear: 2023
8
   copyrightYear: 2023
9
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
9
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
10
-#  profile: /home/cmc/Java-server/综合办公/
11
-  profile: D:/ruoyi/uploadPath
10
+#  profile: /home/cmc/Java-server/综合办公
11
+  profile: /home/cmc/projects/cmc-oa
12
+#  profile: D:/ruoyi/uploadPath
12
   # 获取ip地址开关
13
   # 获取ip地址开关
13
   addressEnabled: false
14
   addressEnabled: false
14
   # 验证码类型 math 数字计算 char 字符验证
15
   # 验证码类型 math 数字计算 char 字符验证
17
 # 开发环境配置
18
 # 开发环境配置
18
 server:
19
 server:
19
   # 服务器的HTTP端口,默认为8080
20
   # 服务器的HTTP端口,默认为8080
20
-  port: 8080
21
-#  port: 8086
21
+#  port: 8087
22
+  port: 8086
22
   servlet:
23
   servlet:
23
     # 应用的访问路径
24
     # 应用的访问路径
24
     context-path: /
25
     context-path: /
61
       # 单个文件大小
62
       # 单个文件大小
62
       max-file-size: 1024MB
63
       max-file-size: 1024MB
63
       # 设置总上传的文件大小
64
       # 设置总上传的文件大小
64
-      max-request-size: 10240MB
65
+      max-request-size: 1024MB
65
   # 服务模块
66
   # 服务模块
66
   devtools:
67
   devtools:
67
     restart:
68
     restart:
71
   redis:
72
   redis:
72
     # 地址
73
     # 地址
73
     host: localhost
74
     host: localhost
75
+#    host: cmc-redis
74
     # 端口,默认为6379
76
     # 端口,默认为6379
75
     port: 6379
77
     port: 6379
76
     # 数据库索引
78
     # 数据库索引
97
   # 令牌密钥
99
   # 令牌密钥
98
   secret: abcdefghijklmnopqrstuvwxyz
100
   secret: abcdefghijklmnopqrstuvwxyz
99
   # 令牌有效期(默认30分钟)
101
   # 令牌有效期(默认30分钟)
100
-  expireTime: 240
102
+  expireTime: 480
101
 
103
 
102
 # MyBatis配置
104
 # MyBatis配置
103
 mybatis:
105
 mybatis:
133
 # flowable相关表
135
 # flowable相关表
134
 flowable:
136
 flowable:
135
   # true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用)
137
   # true 会对数据库中所有表进行更新操作。如果表不存在,则自动创建(建议开发时使用)
136
-  database-schema-update: false
138
+#  database-schema-update: false
139
+  database-schema-update: true
137
   # 关闭定时任务JOB
140
   # 关闭定时任务JOB
138
-  async-executor-activate: false
141
+  async-executor-activate: false
142
+
143
+llmService:
144
+  url: http://192.168.28.196:8000/v1/chat/completions
145
+milvusService:
146
+  url: http://192.168.28.196:19530

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

37
 import org.noear.solon.ai.mcp.McpChannel;
37
 import org.noear.solon.ai.mcp.McpChannel;
38
 import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint;
38
 import org.noear.solon.ai.mcp.server.annotation.McpServerEndpoint;
39
 import org.noear.solon.annotation.Param;
39
 import org.noear.solon.annotation.Param;
40
+import org.springframework.beans.factory.annotation.Value;
40
 import org.springframework.stereotype.Service;
41
 import org.springframework.stereotype.Service;
41
 
42
 
42
 import java.io.*;
43
 import java.io.*;
44
+import java.sql.*;
43
 import java.util.*;
45
 import java.util.*;
44
 
46
 
45
 @Service
47
 @Service
48
 
50
 
49
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
51
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
50
 
52
 
51
-    private static final String llmServiceUrl = "http://192.168.28.196:8000/v1/chat/completions";
53
+    @Value("${llmService.url}")
54
+    private static String llmServiceUrl;
52
 
55
 
53
-    private static final MilvusClientV2 milvusClient = new MilvusClientV2(
54
-            ConnectConfig.builder()
55
-                    .uri("http://192.168.28.196:19530")
56
-                    .build());
56
+    @Value("${lmilvusService.url}")
57
+    private static String milvusServiceUrl;
58
+
59
+    @Value("${mysqlService.jdbcUrl}")
60
+    private static String url ;
61
+
62
+    @Value("${mysqlService.username}")
63
+    private static String user;
64
+
65
+    @Value("${mysqlService.password}")
66
+    private static String password;
67
+
68
+    @Value("${cmc.profile}")
69
+    private static String profile;
57
 
70
 
58
     /**
71
     /**
59
      * 调用LLM+RAG(外部文件+知识库)生成回答
72
      * 调用LLM+RAG(外部文件+知识库)生成回答
66
     {
79
     {
67
             try {
80
             try {
68
                 if (templatePath.startsWith("/dev-api"))
81
                 if (templatePath.startsWith("/dev-api"))
69
-                    templatePath = templatePath.replace("/dev-api/profile", Solon.cfg().getProperty("cmc.profile"));
70
-                templatePath = Solon.cfg().getProperty("cmc.profile") + templatePath;
82
+                    templatePath = templatePath.replace("/dev-api/profile", profile);
83
+                templatePath =profile + templatePath;
71
                 List<String> subTitles = extractSubTitles(templatePath, title);
84
                 List<String> subTitles = extractSubTitles(templatePath, title);
72
                 List<JSONObject> contexts = retrieveFromMilvus(collectionName, title, 10);
85
                 List<JSONObject> contexts = retrieveFromMilvus(collectionName, title, 10);
73
                 return generateAnswerWithDocumentAndCollection(agentName, templatePath, subTitles, contexts);
86
                 return generateAnswerWithDocumentAndCollection(agentName, templatePath, subTitles, contexts);
76
             }
89
             }
77
     }
90
     }
78
 
91
 
92
+    /**
93
+     * 查询OA数据生成回答
94
+     */
95
+    @ToolMapping(description = "数据查询")
96
+    public AssistantMessage SQLQuery(@Param(description = "sql语句") String sqlString) throws Exception
97
+    {
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
+            }
104
+    }
105
+
106
+    public static List<Map<String, Object>> executeQuery(String sql, Object... params) {
107
+        List<Map<String, Object>> result = new ArrayList<>();
108
+
109
+        try (Connection conn = DriverManager.getConnection(url, user, password);
110
+             PreparedStatement stmt = conn.prepareStatement(sql)) {
111
+
112
+            // 设置参数
113
+            for (int i = 0; i < params.length; i++) {
114
+                stmt.setObject(i + 1, params[i]);
115
+            }
116
+
117
+            ResultSet rs = stmt.executeQuery();
118
+            ResultSetMetaData metaData = rs.getMetaData();
119
+            int columnCount = metaData.getColumnCount();
120
+
121
+            while (rs.next()) {
122
+                Map<String, Object> row = new HashMap<>();
123
+                for (int i = 1; i <= columnCount; i++) {
124
+                    String columnName = metaData.getColumnLabel(i);
125
+                    Object value = rs.getObject(i);
126
+                    row.put(columnName, value);
127
+                }
128
+                result.add(row);
129
+            }
130
+
131
+        } catch (SQLException e) {
132
+            throw new RuntimeException("执行 SQL 失败: " + sql, e);
133
+        }
134
+
135
+        return result;
136
+    }
137
+
79
     /**
138
     /**
80
      * 从Milvus检索相关文档
139
      * 从Milvus检索相关文档
81
      * @return
140
      * @return
124
             sb.append("针对本项目招标文件内容,补全以下章节部分:\n\n").append(title);
183
             sb.append("针对本项目招标文件内容,补全以下章节部分:\n\n").append(title);
125
             content.append(generateAnswer(sb.toString()));
184
             content.append(generateAnswer(sb.toString()));
126
         }
185
         }
127
-        String absolutePath = templatePath.replace("/dev-api/profile", Solon.cfg().getProperty("cmc.profile"));
186
+        String absolutePath = templatePath.replace("/dev-api/profile", profile);
128
         writeContent(content.toString(), titles, absolutePath);
187
         writeContent(content.toString(), titles, absolutePath);
129
         for (JSONObject context : contexts) {
188
         for (JSONObject context : contexts) {
130
             sb.append("文件").append(": ")
189
             sb.append("文件").append(": ")
133
                     .append(context.getString("content")).append("\n\n");
192
                     .append(context.getString("content")).append("\n\n");
134
         }
193
         }
135
         content.append( "招标文件分析完成,章节内容已写入【<a href='")
194
         content.append( "招标文件分析完成,章节内容已写入【<a href='")
136
-                .append(templatePath.replace(Solon.cfg().getProperty("cmc.profile"), "/dev-api/profile"))
195
+                .append(templatePath.replace(profile, "/dev-api/profile"))
137
                 .append("'> 技术文件" + "</a>】,请查阅\n\n")
196
                 .append("'> 技术文件" + "</a>】,请查阅\n\n")
138
                 .append("如需修改,请输入技术文件已有内容的章节标题\n\n")
197
                 .append("如需修改,请输入技术文件已有内容的章节标题\n\n")
139
                 .append(extractTitles(templatePath));
198
                 .append(extractTitles(templatePath));
303
      * @return
362
      * @return
304
      */
363
      */
305
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
364
     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());
306
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
369
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
307
 
370
 
308
         //  加载集合
371
         //  加载集合

+ 9
- 1
oa-back/ruoyi-agent/src/main/resources/application.yml Просмотреть файл

2
 cmc:
2
 cmc:
3
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
3
   # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
4
   #  profile: /home/cmc/projects/cmc-llm
4
   #  profile: /home/cmc/projects/cmc-llm
5
-  profile: E:/home/cmc/projects/cmc-llm
5
+  profile: /home/cmc/projects/cmc-oa
6
+  llmService:
7
+    url: http://192.168.28.196:8000/v1/chat/completions
8
+  milvusService:
9
+    url: http://192.168.28.196:19530
10
+  mysqlService:
11
+    jdbcUrl: jdbc:mysql://localhost:3306/cmc_oa?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
12
+    username: root
13
+    password: cmcroot

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

5
 import java.util.List;
5
 import java.util.List;
6
 import javax.servlet.http.HttpServletResponse;
6
 import javax.servlet.http.HttpServletResponse;
7
 
7
 
8
-import org.noear.solon.ai.chat.message.AssistantMessage;
8
+import org.noear.solon.ai.chat.message.ChatMessage;
9
 import org.springframework.beans.factory.annotation.Autowired;
9
 import org.springframework.beans.factory.annotation.Autowired;
10
 import org.springframework.web.bind.annotation.GetMapping;
10
 import org.springframework.web.bind.annotation.GetMapping;
11
 import org.springframework.web.bind.annotation.PostMapping;
11
 import org.springframework.web.bind.annotation.PostMapping;
76
      */
76
      */
77
     @GetMapping("/opening")
77
     @GetMapping("/opening")
78
     public AjaxResult opening(String agentName) {
78
     public AjaxResult opening(String agentName) {
79
-        return success(new AssistantMessage(cmcAgentService.getOpening(agentName)));
79
+        return success(ChatMessage.ofAssistant(cmcAgentService.getOpening(agentName)));
80
     }
80
     }
81
 
81
 
82
     /**
82
     /**

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

1
 package com.ruoyi.web.llm.controller;
1
 package com.ruoyi.web.llm.controller;
2
 
2
 
3
 import com.alibaba.fastjson2.JSONObject;
3
 import com.alibaba.fastjson2.JSONObject;
4
-import com.ruoyi.common.config.RuoYiConfig;
5
 import com.ruoyi.common.core.controller.BaseController;
4
 import com.ruoyi.common.core.controller.BaseController;
6
 import com.ruoyi.llm.domain.CmcChat;
5
 import com.ruoyi.llm.domain.CmcChat;
7
 import com.ruoyi.llm.service.ICmcAgentService;
6
 import com.ruoyi.llm.service.ICmcAgentService;
8
 import com.ruoyi.llm.service.ICmcChatService;
7
 import com.ruoyi.llm.service.ICmcChatService;
9
 import com.ruoyi.llm.service.ICmcTopicService;
8
 import com.ruoyi.llm.service.ICmcTopicService;
10
-import com.ruoyi.web.llm.service.ILangChainMilvusService;
11
-import dev.langchain4j.model.embedding.EmbeddingModel;
12
-import dev.langchain4j.model.embedding.onnx.bgesmallzhv15.BgeSmallZhV15EmbeddingModel;
13
-import io.milvus.client.MilvusServiceClient;
14
-import io.milvus.param.ConnectParam;
15
-import org.noear.solon.Solon;
16
 import org.noear.solon.ai.chat.ChatModel;
9
 import org.noear.solon.ai.chat.ChatModel;
17
 import org.noear.solon.ai.chat.ChatResponse;
10
 import org.noear.solon.ai.chat.ChatResponse;
18
 import org.noear.solon.ai.chat.ChatSession;
11
 import org.noear.solon.ai.chat.ChatSession;
22
 import org.noear.solon.ai.mcp.McpChannel;
15
 import org.noear.solon.ai.mcp.McpChannel;
23
 import org.noear.solon.ai.mcp.client.McpClientProvider;
16
 import org.noear.solon.ai.mcp.client.McpClientProvider;
24
 import org.springframework.beans.factory.annotation.Autowired;
17
 import org.springframework.beans.factory.annotation.Autowired;
18
+import org.springframework.beans.factory.annotation.Value;
25
 import org.springframework.web.bind.annotation.GetMapping;
19
 import org.springframework.web.bind.annotation.GetMapping;
26
 import org.springframework.web.bind.annotation.RequestMapping;
20
 import org.springframework.web.bind.annotation.RequestMapping;
27
 import org.springframework.web.bind.annotation.RestController;
21
 import org.springframework.web.bind.annotation.RestController;
40
 @RequestMapping("/llm/mcp")
34
 @RequestMapping("/llm/mcp")
41
 public class McpController extends BaseController
35
 public class McpController extends BaseController
42
 {
36
 {
43
-    @Autowired
44
-    private ILangChainMilvusService langChainMilvusService;
45
-
46
     @Autowired
37
     @Autowired
47
     private ICmcChatService cmcChatService;
38
     private ICmcChatService cmcChatService;
48
 
39
 
52
     @Autowired
43
     @Autowired
53
     private ICmcAgentService cmcAgentService;
44
     private ICmcAgentService cmcAgentService;
54
 
45
 
55
-    private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
56
-
57
-    private static final String llmServiceUrl = "http://192.168.28.196:8000/v1/chat/completions";
46
+    @Value("${llmService.url}")
47
+    private String llmServiceUrl;
58
 
48
 
59
-    private static final MilvusServiceClient milvusClient = new MilvusServiceClient(
60
-            ConnectParam.newBuilder()
61
-                    .withHost("192.168.28.196")
62
-                    .withPort(19530)
63
-                    .build());
49
+    @Value("${milvusService.url}")
50
+    private String milvusServiceUrl;
64
 
51
 
65
     /**
52
     /**
66
      * 自动调用mcp工具问答
53
      * 自动调用mcp工具问答
70
     public AssistantMessage answer(String topicId, String question) throws IOException {
57
     public AssistantMessage answer(String topicId, String question) throws IOException {
71
         McpClientProvider clientProvider = McpClientProvider.builder()
58
         McpClientProvider clientProvider = McpClientProvider.builder()
72
                 .channel(McpChannel.SSE)
59
                 .channel(McpChannel.SSE)
73
-                .apiUrl("http://localhost:8080/mcp/sse")
60
+                .url("http://localhost:8080/mcp/sse")
74
                 .build();
61
                 .build();
75
         ChatModel chatModel = ChatModel.of(llmServiceUrl)
62
         ChatModel chatModel = ChatModel.of(llmServiceUrl)
76
                 .model("Qwen2.5-7B-Instruct")
63
                 .model("Qwen2.5-7B-Instruct")
102
                 arguments.put("title", question);
89
                 arguments.put("title", question);
103
             }
90
             }
104
             resultContent = clientProvider.callToolAsText(name, arguments).getContent();
91
             resultContent = clientProvider.callToolAsText(name, arguments).getContent();
105
-            assistantMessage = new AssistantMessage(resultContent);
92
+            assistantMessage = ChatMessage.ofAssistant(resultContent);
106
         }
93
         }
107
         else
94
         else
108
             throw new IOException("模型上下文工具未准备就绪,请重试");
95
             throw new IOException("模型上下文工具未准备就绪,请重试");

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

5
 import com.ruoyi.common.core.controller.BaseController;
5
 import com.ruoyi.common.core.controller.BaseController;
6
 import org.noear.solon.ai.chat.message.AssistantMessage;
6
 import org.noear.solon.ai.chat.message.AssistantMessage;
7
 import org.springframework.beans.factory.annotation.Autowired;
7
 import org.springframework.beans.factory.annotation.Autowired;
8
+import org.springframework.beans.factory.annotation.Value;
8
 import org.springframework.web.bind.annotation.GetMapping;
9
 import org.springframework.web.bind.annotation.GetMapping;
9
 import org.springframework.web.bind.annotation.RequestMapping;
10
 import org.springframework.web.bind.annotation.RequestMapping;
10
 import org.springframework.web.bind.annotation.RestController;
11
 import org.springframework.web.bind.annotation.RestController;
11
 import reactor.core.publisher.Flux;
12
 import reactor.core.publisher.Flux;
12
 
13
 
14
+import java.io.IOException;
13
 import java.util.List;
15
 import java.util.List;
14
 
16
 
15
 /**
17
 /**
25
     @Autowired
27
     @Autowired
26
     private ILangChainMilvusService langChainMilvusService;
28
     private ILangChainMilvusService langChainMilvusService;
27
 
29
 
30
+    @Value("${llmService.url}")
31
+    private String llmServiceUrl;
32
+
28
     /**
33
     /**
29
      * 调用LLM+RAG(知识库)生成回答
34
      * 调用LLM+RAG(知识库)生成回答
30
      */
35
      */
31
     @GetMapping("/answer")
36
     @GetMapping("/answer")
32
-    public Flux<AssistantMessage> answerWithCollection(String collectionName, String topicId, String question)
33
-    {
37
+    public Flux<AssistantMessage> answerWithCollection(String collectionName, String topicId, String question) throws IOException {
34
         List<JSONObject> contexts = langChainMilvusService.retrieveFromMilvus(collectionName, question, 10);
38
         List<JSONObject> contexts = langChainMilvusService.retrieveFromMilvus(collectionName, question, 10);
35
-        return langChainMilvusService.generateAnswerWithCollection(topicId, question, contexts, "http://192.168.28.196:8000/v1/chat/completions");
39
+        return langChainMilvusService.generateAnswerWithCollection(topicId, question, contexts, llmServiceUrl);
36
     }
40
     }
37
 
41
 
38
     /**
42
     /**

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

4
 import com.ruoyi.web.llm.service.ILangChainMilvusService;
4
 import com.ruoyi.web.llm.service.ILangChainMilvusService;
5
 import org.noear.solon.ai.chat.message.AssistantMessage;
5
 import org.noear.solon.ai.chat.message.AssistantMessage;
6
 import org.springframework.beans.factory.annotation.Autowired;
6
 import org.springframework.beans.factory.annotation.Autowired;
7
+import org.springframework.beans.factory.annotation.Value;
7
 import org.springframework.web.bind.annotation.GetMapping;
8
 import org.springframework.web.bind.annotation.GetMapping;
8
 import org.springframework.web.bind.annotation.RequestMapping;
9
 import org.springframework.web.bind.annotation.RequestMapping;
9
 import org.springframework.web.bind.annotation.RestController;
10
 import org.springframework.web.bind.annotation.RestController;
24
     @Autowired
25
     @Autowired
25
     private ILangChainMilvusService langChainMilvusService;
26
     private ILangChainMilvusService langChainMilvusService;
26
 
27
 
28
+    @Value("${llmService.url}")
29
+    private String llmServiceUrl;
30
+
27
     /**
31
     /**
28
      * 生成回答
32
      * 生成回答
29
      */
33
      */
30
     @GetMapping("/answer")
34
     @GetMapping("/answer")
31
     public Flux<AssistantMessage> answer(String topicId, String question) {
35
     public Flux<AssistantMessage> answer(String topicId, String question) {
32
-        return langChainMilvusService.generateAnswer(topicId, question, "http://192.168.28.196:8000/v1/chat/completions");
36
+        return langChainMilvusService.generateAnswer(topicId, question, llmServiceUrl);
33
     }
37
     }
34
 
38
 
35
     /**
39
     /**
36
      * 调用LLM+RAG(外部文件)生成回答
40
      * 调用LLM+RAG(外部文件)生成回答
37
      */
41
      */
38
     @GetMapping("/answerWithDocument")
42
     @GetMapping("/answerWithDocument")
39
-    public Flux<AssistantMessage> answerWithDocument(String topicId, String chatId, String question) throws IOException
43
+    public Flux<AssistantMessage> answerWithDocument(String topicId, String chatId, String question) throws Exception
40
     {
44
     {
41
-        return langChainMilvusService.generateAnswerWithDocument(topicId, chatId, question, "http://192.168.28.196:8000/v1/chat/completions");
45
+        return langChainMilvusService.generateAnswerWithDocument(topicId, chatId, question, llmServiceUrl);
42
     }
46
     }
43
 
47
 
44
 }
48
 }

+ 3
- 2
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;
8
 import java.io.IOException;
9
 import java.io.IOException;
9
 import java.util.List;
10
 import java.util.List;
10
 
11
 
51
      * 调用LLM+RAG(外部文件)生成回答
52
      * 调用LLM+RAG(外部文件)生成回答
52
      * @return
53
      * @return
53
      */
54
      */
54
-    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws IOException;
55
+    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws Exception;
55
 
56
 
56
     /**
57
     /**
57
      * 调用LLM+RAG(外部文件+知识库)生成回答
58
      * 调用LLM+RAG(外部文件+知识库)生成回答
58
      * @return
59
      * @return
59
      */
60
      */
60
-    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question,  List<JSONObject> requests, String llmServiceUrl) throws IOException;
61
+    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question,  List<JSONObject> requests, String llmServiceUrl) throws Exception;
61
 
62
 
62
     /**
63
     /**
63
      * 获取二级标题下三级标题列表
64
      * 获取二级标题下三级标题列表

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

42
 import org.noear.solon.ai.chat.message.AssistantMessage;
42
 import org.noear.solon.ai.chat.message.AssistantMessage;
43
 import org.noear.solon.ai.chat.message.ChatMessage;
43
 import org.noear.solon.ai.chat.message.ChatMessage;
44
 import org.noear.solon.ai.chat.session.InMemoryChatSession;
44
 import org.noear.solon.ai.chat.session.InMemoryChatSession;
45
-import org.noear.solon.web.sse.SseEvent;
46
 import org.reactivestreams.Publisher;
45
 import org.reactivestreams.Publisher;
47
 import org.springframework.beans.factory.annotation.Autowired;
46
 import org.springframework.beans.factory.annotation.Autowired;
47
+import org.springframework.beans.factory.annotation.Value;
48
 import org.springframework.stereotype.Service;
48
 import org.springframework.stereotype.Service;
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;
61
     @Autowired
61
     @Autowired
62
     private ICmcDocumentService cmcDocumentService;
62
     private ICmcDocumentService cmcDocumentService;
63
 
63
 
64
-    private static final MilvusClientV2 milvusClient = new MilvusClientV2(
65
-            ConnectConfig.builder()
66
-                    .uri("http://192.168.28.196:19530")
67
-                    .build());
68
-
69
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
64
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
70
 
65
 
71
     private String processValue = "";
66
     private String processValue = "";
72
 
67
 
68
+    @Value("${llmService.url}")
69
+    private String llmServiceUrl;
70
+
71
+    @Value("${milvusService.url}")
72
+    private String milvusServiceUrl;
73
+
73
     /**
74
     /**
74
      * 上传多文件
75
      * 上传多文件
75
      *
76
      *
86
     @Override
87
     @Override
87
     public int insertLangchainEmbeddingDocument(MultipartFile[] fileList, String collectionName)
88
     public int insertLangchainEmbeddingDocument(MultipartFile[] fileList, String collectionName)
88
     {
89
     {
90
+        MilvusClientV2 milvusClient = new MilvusClientV2(
91
+                ConnectConfig.builder()
92
+                        .uri(llmServiceUrl)
93
+                        .build());
89
         processValue = "";
94
         processValue = "";
90
         int successfullyInsertedFiles = 0;
95
         int successfullyInsertedFiles = 0;
91
 
96
 
253
      * 调用LLM生成回答
258
      * 调用LLM生成回答
254
      */
259
      */
255
     @Override
260
     @Override
256
-    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws IOException {
261
+    public Flux<AssistantMessage> generateAnswerWithDocument(String topicId, String chatId, String question, String llmServiceUrl) throws Exception {
257
         CmcDocument cmcDocument = new CmcDocument();
262
         CmcDocument cmcDocument = new CmcDocument();
258
         cmcDocument.setChatId(chatId);
263
         cmcDocument.setChatId(chatId);
259
         List<CmcDocument> documentList = cmcDocumentService.selectCmcDocumentList(cmcDocument);
264
         List<CmcDocument> documentList = cmcDocumentService.selectCmcDocumentList(cmcDocument);
286
      * 调用LLM生成回答
291
      * 调用LLM生成回答
287
      */
292
      */
288
     @Override
293
     @Override
289
-    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question, List<JSONObject> contexts, String llmServiceUrl) throws IOException {
294
+    public Flux<AssistantMessage> generateAnswerWithDocumentAndCollection(String topicId, String question, List<JSONObject> contexts, String llmServiceUrl) throws Exception {
290
         StringBuilder sb = new StringBuilder("招标文件内容:\n\n");
295
         StringBuilder sb = new StringBuilder("招标文件内容:\n\n");
291
         CmcChat cmcChat = new CmcChat();
296
         CmcChat cmcChat = new CmcChat();
292
         cmcChat.setTopicId(topicId);
297
         cmcChat.setTopicId(topicId);
369
      * @return
374
      * @return
370
      */
375
      */
371
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
376
     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());
372
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
381
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
373
 
382
 
374
         //  加载集合
383
         //  加载集合
405
     /**
414
     /**
406
      * 检索知识库
415
      * 检索知识库
407
      */
416
      */
408
-    private List<TextSegment> splitDocument(File transferFile) throws FileNotFoundException {
417
+    private List<TextSegment> splitDocument(File transferFile) throws Exception {
409
         // 加载文档
418
         // 加载文档
410
         Document document;
419
         Document document;
411
         InputStream fileInputStream = new FileInputStream(transferFile);
420
         InputStream fileInputStream = new FileInputStream(transferFile);

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

13
 import io.milvus.v2.service.vector.request.DeleteReq;
13
 import io.milvus.v2.service.vector.request.DeleteReq;
14
 import io.milvus.v2.service.vector.request.QueryReq;
14
 import io.milvus.v2.service.vector.request.QueryReq;
15
 import io.milvus.v2.service.vector.response.QueryResp;
15
 import io.milvus.v2.service.vector.response.QueryResp;
16
+import org.springframework.beans.factory.annotation.Value;
16
 import org.springframework.stereotype.Service;
17
 import org.springframework.stereotype.Service;
17
 
18
 
18
 import java.text.SimpleDateFormat;
19
 import java.text.SimpleDateFormat;
22
 @Service
23
 @Service
23
 public class MilvusServiceImpl implements IMilvusService {
24
 public class MilvusServiceImpl implements IMilvusService {
24
 
25
 
25
-    private static final MilvusClientV2 milvusClient = new MilvusClientV2(
26
-            ConnectConfig.builder()
27
-                    .uri("http://192.168.28.196:19530")
28
-                    .build());
26
+    @Value("${milvusService.url}")
27
+    private String milvusServiceUrl;
29
 
28
 
30
     /**
29
     /**
31
      * 新建知识库Collection(含Schema、Field、Index)
30
      * 新建知识库Collection(含Schema、Field、Index)
32
      */
31
      */
33
     @Override
32
     @Override
34
     public void createCollection(String collectionName, String description, int dimension) {
33
     public void createCollection(String collectionName, String description, int dimension) {
34
+        MilvusClientV2 milvusClient = new MilvusClientV2(
35
+                ConnectConfig.builder()
36
+                        .uri(milvusServiceUrl)
37
+                        .build());
35
         CreateCollectionReq.CollectionSchema schema = MilvusClientV2.CreateSchema();
38
         CreateCollectionReq.CollectionSchema schema = MilvusClientV2.CreateSchema();
36
 
39
 
37
         schema.addField(AddFieldReq.builder()
40
         schema.addField(AddFieldReq.builder()
90
      */
93
      */
91
     @Override
94
     @Override
92
     public JSONArray getCollectionNames() {
95
     public JSONArray getCollectionNames() {
96
+        MilvusClientV2 milvusClient = new MilvusClientV2(
97
+                ConnectConfig.builder()
98
+                        .uri(milvusServiceUrl)
99
+                        .build());
93
         JSONArray jsonArray = new JSONArray();
100
         JSONArray jsonArray = new JSONArray();
94
         ListCollectionsResp listResponse = milvusClient.listCollections();
101
         ListCollectionsResp listResponse = milvusClient.listCollections();
95
         if (listResponse != null) {
102
         if (listResponse != null) {
119
      */
126
      */
120
     @Override
127
     @Override
121
     public JSONArray listKnowLedgeByCollectionName(String collectionName) {
128
     public JSONArray listKnowLedgeByCollectionName(String collectionName) {
129
+        MilvusClientV2 milvusClient = new MilvusClientV2(
130
+                ConnectConfig.builder()
131
+                        .uri(milvusServiceUrl)
132
+                        .build());
122
         JSONArray jsonArray = new JSONArray();
133
         JSONArray jsonArray = new JSONArray();
123
         ListCollectionsResp listResponse = milvusClient.listCollections();
134
         ListCollectionsResp listResponse = milvusClient.listCollections();
124
-        
135
+
125
         if (listResponse != null) {
136
         if (listResponse != null) {
126
             List<String> allCollectionNames = listResponse.getCollectionNames();
137
             List<String> allCollectionNames = listResponse.getCollectionNames();
127
             for (String name : allCollectionNames) {
138
             for (String name : allCollectionNames) {
150
      */
161
      */
151
     @Override
162
     @Override
152
     public void collectionRename(String collectionName, String newCollectionName) {
163
     public void collectionRename(String collectionName, String newCollectionName) {
164
+        MilvusClientV2 milvusClient = new MilvusClientV2(
165
+                ConnectConfig.builder()
166
+                        .uri(milvusServiceUrl)
167
+                        .build());
153
         RenameCollectionReq renameCollectionReq = RenameCollectionReq.builder()
168
         RenameCollectionReq renameCollectionReq = RenameCollectionReq.builder()
154
                 .collectionName(collectionName)
169
                 .collectionName(collectionName)
155
                 .newCollectionName(newCollectionName)
170
                 .newCollectionName(newCollectionName)
163
      */
178
      */
164
     @Override
179
     @Override
165
     public void deleteCollectionName(String collectionName) {
180
     public void deleteCollectionName(String collectionName) {
181
+        MilvusClientV2 milvusClient = new MilvusClientV2(
182
+                ConnectConfig.builder()
183
+                        .uri(milvusServiceUrl)
184
+                        .build());
166
         DropCollectionReq dropCollectionReq = DropCollectionReq.builder()
185
         DropCollectionReq dropCollectionReq = DropCollectionReq.builder()
167
                 .collectionName(collectionName)
186
                 .collectionName(collectionName)
168
                 .build();
187
                 .build();
174
      */
193
      */
175
     @Override
194
     @Override
176
     public List<String> listDocument(String collectionName, String fileType) {
195
     public List<String> listDocument(String collectionName, String fileType) {
196
+        MilvusClientV2 milvusClient = new MilvusClientV2(
197
+                ConnectConfig.builder()
198
+                        .uri(milvusServiceUrl)
199
+                        .build());
177
         List<String> documentList = new ArrayList<>();
200
         List<String> documentList = new ArrayList<>();
178
-        loadCollectionName(collectionName);
201
+        LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
202
+                .collectionName(collectionName)
203
+                .build();
204
+        milvusClient.loadCollection(loadCollectionReq);
179
         QueryReq queryParam = QueryReq.builder()
205
         QueryReq queryParam = QueryReq.builder()
180
                 .collectionName(collectionName)
206
                 .collectionName(collectionName)
181
                 .filter("id > 0")
207
                 .filter("id > 0")
195
                 documentList.add(rowRecord.getEntity().get("file_name").toString());
221
                 documentList.add(rowRecord.getEntity().get("file_name").toString());
196
             }
222
             }
197
         }
223
         }
198
-        releaseCollectionName(collectionName);
224
+        ReleaseCollectionReq releaseCollectionReq = ReleaseCollectionReq.builder()
225
+                .collectionName(collectionName)
226
+                .build();
227
+        milvusClient.releaseCollection(releaseCollectionReq);
199
         return documentList.stream().distinct().collect(Collectors.toList());
228
         return documentList.stream().distinct().collect(Collectors.toList());
200
     }
229
     }
201
 
230
 
204
      */
233
      */
205
     @Override
234
     @Override
206
     public void removeDocument(String collectionName, String fileName) {
235
     public void removeDocument(String collectionName, String fileName) {
207
-        loadCollectionName(collectionName);
236
+        MilvusClientV2 milvusClient = new MilvusClientV2(
237
+                ConnectConfig.builder()
238
+                        .uri(milvusServiceUrl)
239
+                        .build());
240
+        LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
241
+                .collectionName(collectionName)
242
+                .build();
243
+        milvusClient.loadCollection(loadCollectionReq);
208
         DeleteReq deleteReq = DeleteReq.builder()
244
         DeleteReq deleteReq = DeleteReq.builder()
209
                 .collectionName(collectionName)
245
                 .collectionName(collectionName)
210
                 .filter(String.format("file_name == \"%s\"", fileName))
246
                 .filter(String.format("file_name == \"%s\"", fileName))
217
      */
253
      */
218
     @Override
254
     @Override
219
     public void removeAllDocument(String collectionName) {
255
     public void removeAllDocument(String collectionName) {
220
-        loadCollectionName(collectionName);
221
-        DeleteReq deleteReq = DeleteReq.builder()
222
-                .collectionName(collectionName)
223
-                .filter("id > 0")
224
-                .build();
225
-        milvusClient.delete(deleteReq);
226
-    }
227
-
228
-    /**
229
-     * 加载知识库Collection
230
-     */
231
-    public void loadCollectionName(String collectionName) {
256
+        MilvusClientV2 milvusClient = new MilvusClientV2(
257
+                ConnectConfig.builder()
258
+                        .uri(milvusServiceUrl)
259
+                        .build());
232
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
260
         LoadCollectionReq loadCollectionReq = LoadCollectionReq.builder()
233
                 .collectionName(collectionName)
261
                 .collectionName(collectionName)
234
                 .build();
262
                 .build();
235
         milvusClient.loadCollection(loadCollectionReq);
263
         milvusClient.loadCollection(loadCollectionReq);
236
-    }
237
-
238
-    /**
239
-     * 释放知识库Collection
240
-     */
241
-    public void releaseCollectionName(String collectionName) {
242
-        ReleaseCollectionReq releaseCollectionReq = ReleaseCollectionReq.builder()
264
+        DeleteReq deleteReq = DeleteReq.builder()
243
                 .collectionName(collectionName)
265
                 .collectionName(collectionName)
266
+                .filter("id > 0")
244
                 .build();
267
                 .build();
245
-        milvusClient.releaseCollection(releaseCollectionReq);
268
+        milvusClient.delete(deleteReq);
246
     }
269
     }
247
 
270
 
248
 }
271
 }

+ 9
- 5
oa-back/ruoyi-system/src/main/java/com/ruoyi/llm/service/impl/CmcAgentServiceImpl.java Просмотреть файл

42
 import org.noear.solon.ai.chat.message.ChatMessage;
42
 import org.noear.solon.ai.chat.message.ChatMessage;
43
 import org.noear.solon.ai.chat.session.InMemoryChatSession;
43
 import org.noear.solon.ai.chat.session.InMemoryChatSession;
44
 import org.springframework.beans.factory.annotation.Autowired;
44
 import org.springframework.beans.factory.annotation.Autowired;
45
+import org.springframework.beans.factory.annotation.Value;
45
 import org.springframework.stereotype.Service;
46
 import org.springframework.stereotype.Service;
46
 import org.springframework.web.multipart.MultipartFile;
47
 import org.springframework.web.multipart.MultipartFile;
47
 
48
 
74
 
75
 
75
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
76
     private static final EmbeddingModel embeddingModel = new BgeSmallZhV15EmbeddingModel();
76
 
77
 
77
-    private static final String llmServiceUrl = "http://192.168.28.196:8000/v1/chat/completions";
78
+    @Value("${llmService.url}")
79
+    private String llmServiceUrl;
78
 
80
 
79
-    private static final MilvusClientV2 milvusClient = new MilvusClientV2(
80
-            ConnectConfig.builder()
81
-                    .uri("http://192.168.28.196:19530")
82
-                    .build());
81
+    @Value("${milvusService.url}")
82
+    private String milvusServiceUrl;
83
 
83
 
84
     /**
84
     /**
85
      * 查询智能体
85
      * 查询智能体
650
      * 检索知识库
650
      * 检索知识库
651
      */
651
      */
652
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
652
     private List<List<SearchResp.SearchResult>> retrieve(String collectionName, String query, int topK) {
653
+        MilvusClientV2 milvusClient = new MilvusClientV2(
654
+                ConnectConfig.builder()
655
+                        .uri(milvusServiceUrl)
656
+                        .build());
653
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
657
         List<BaseVector> queryVector = Collections.singletonList(new FloatVec(embeddingModel.embed(query).content().vector()));
654
 
658
 
655
         //  加载集合
659
         //  加载集合

+ 23
- 0
oa-back/ruoyi-system/src/main/java/com/ruoyi/oa/domain/CmcCheck.java Просмотреть файл

1
 package com.ruoyi.oa.domain;
1
 package com.ruoyi.oa.domain;
2
 
2
 
3
+import java.math.BigDecimal;
3
 import java.util.Date;
4
 import java.util.Date;
4
 import com.fasterxml.jackson.annotation.JsonFormat;
5
 import com.fasterxml.jackson.annotation.JsonFormat;
5
 import com.ruoyi.common.core.domain.entity.SysUser;
6
 import com.ruoyi.common.core.domain.entity.SysUser;
45
     @Excel(name = "核算说明")
46
     @Excel(name = "核算说明")
46
     private String checkComment;
47
     private String checkComment;
47
 
48
 
49
+    /** 核算总额 */
50
+    @Excel(name = "核算总额")
51
+    private BigDecimal totalAdjust;
52
+
48
     /** 财务审核人 */
53
     /** 财务审核人 */
49
     @Excel(name = "财务审核人")
54
     @Excel(name = "财务审核人")
50
     private String cwUserName;
55
     private String cwUserName;
151
     {
156
     {
152
         return checkComment;
157
         return checkComment;
153
     }
158
     }
159
+    public void setTotalAdjust(BigDecimal totalAdjust)
160
+    {
161
+        this.totalAdjust = totalAdjust;
162
+    }
163
+
164
+    public BigDecimal getTotalAdjust()
165
+    {
166
+        return totalAdjust;
167
+    }
154
     public void setCwUserId(Long cwUserId) 
168
     public void setCwUserId(Long cwUserId) 
155
     {
169
     {
156
         this.cwUserId = cwUserId;
170
         this.cwUserId = cwUserId;
283
     {
297
     {
284
         return project;
298
         return project;
285
     }
299
     }
300
+    public void setProjectNumber(String projectNumber)
301
+    {
302
+        this.projectNumber = projectNumber;
303
+    }
304
+
305
+    public String getProjectNumber()
306
+    {
307
+        return projectNumber;
308
+    }
286
 
309
 
287
     @Override
310
     @Override
288
     public String toString() {
311
     public String toString() {

+ 0
- 1
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcArchiveMapper.xml Просмотреть файл

7
     <resultMap type="CmcArchive" id="CmcArchiveResult">
7
     <resultMap type="CmcArchive" id="CmcArchiveResult">
8
         <result property="archiveId"    column="archive_id"    />
8
         <result property="archiveId"    column="archive_id"    />
9
         <result property="projectId"    column="project_id"    />
9
         <result property="projectId"    column="project_id"    />
10
-        <result property="projectNumber"    column="project_number"    />
11
         <result property="projectLeader"    column="project_leader"    />
10
         <result property="projectLeader"    column="project_leader"    />
12
         <result property="submitTime"    column="submit_time"    />
11
         <result property="submitTime"    column="submit_time"    />
13
         <result property="submitSituation"    column="submit_situation"    />
12
         <result property="submitSituation"    column="submit_situation"    />

+ 0
- 2
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcBorrowMapper.xml Просмотреть файл

7
     <resultMap type="CmcBorrow" id="CmcBorrowResult">
7
     <resultMap type="CmcBorrow" id="CmcBorrowResult">
8
         <result property="borrowId"    column="borrow_id"    />
8
         <result property="borrowId"    column="borrow_id"    />
9
         <result property="projectId"    column="project_id"    />
9
         <result property="projectId"    column="project_id"    />
10
-        <result property="projectNumber"    column="project_number"    />
11
-        <result property="undertakingDept"    column="undertaking_dept"    />
12
         <result property="applyReason"    column="apply_reason"    />
10
         <result property="applyReason"    column="apply_reason"    />
13
         <result property="borrowUsage"    column="borrow_usage"    />
11
         <result property="borrowUsage"    column="borrow_usage"    />
14
         <result property="applier"    column="applier"    />
12
         <result property="applier"    column="applier"    />

+ 8
- 3
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcCheckMapper.xml Просмотреть файл

11
         <result property="checker"    column="checker"    />
11
         <result property="checker"    column="checker"    />
12
         <result property="checkTime"    column="check_time"    />
12
         <result property="checkTime"    column="check_time"    />
13
         <result property="checkComment"    column="check_comment"    />
13
         <result property="checkComment"    column="check_comment"    />
14
+        <result property="totalAdjust"    column="total_adjust"    />
14
         <result property="cwUserId"    column="cw_user_id"    />
15
         <result property="cwUserId"    column="cw_user_id"    />
15
         <result property="cwTime"    column="cw_time"    />
16
         <result property="cwTime"    column="cw_time"    />
16
         <result property="cwComment"    column="cw_comment"    />
17
         <result property="cwComment"    column="cw_comment"    />
54
     </resultMap>
55
     </resultMap>
55
 
56
 
56
     <sql id="selectCmcCheckVo">
57
     <sql id="selectCmcCheckVo">
57
-        select c.check_id, c.budget_id, c.project_id, p.project_number, p.project_name, c.checker, u.nick_name as check_nick_name, c.check_time, c.check_comment, c.cw_user_id, u1.nick_name as cw_nick_name, c.cw_time,
58
+        select c.check_id, c.budget_id, c.project_id, p.project_number, p.project_name, c.checker, u.nick_name as check_nick_name, c.check_time, c.check_comment, c.total_adjust, c.cw_user_id, u1.nick_name as cw_nick_name, c.cw_time,
58
                c.cw_comment, c.manager_user_id, u2.nick_name as manager_nick_name, c.manager_time, c.manager_comment, c.zjl_user_id, u3.nick_name as zjl_nick_name, c.zjl_time, c.zjl_comment from cmc_check as c
59
                c.cw_comment, c.manager_user_id, u2.nick_name as manager_nick_name, c.manager_time, c.manager_comment, c.zjl_user_id, u3.nick_name as zjl_nick_name, c.zjl_time, c.zjl_comment from cmc_check as c
59
         left join sys_user as u on u.user_id = c.checker
60
         left join sys_user as u on u.user_id = c.checker
60
         left join sys_user as u1 on u1.user_id = c.cw_user_id
61
         left join sys_user as u1 on u1.user_id = c.cw_user_id
68
         <where>  
69
         <where>  
69
             <if test="budgetId != null  and budgetId != ''"> and c.budget_id = #{budgetId}</if>
70
             <if test="budgetId != null  and budgetId != ''"> and c.budget_id = #{budgetId}</if>
70
             <if test="projectId != null  and projectId != ''"> and c.project_id = #{projectId}</if>
71
             <if test="projectId != null  and projectId != ''"> and c.project_id = #{projectId}</if>
72
+            <if test="projectNumber != null  and projectNumber != ''"> and p.project_number like concat('%', #{projectNumber}, '%')</if>
71
             <if test="checker != null "> and c.checker = #{checker}</if>
73
             <if test="checker != null "> and c.checker = #{checker}</if>
72
-            <if test="checkTime != null "> and c.check_time = #{checkTime}</if>
73
             <if test="checkComment != null  and checkComment != ''"> and c.check_comment = #{checkComment}</if>
74
             <if test="checkComment != null  and checkComment != ''"> and c.check_comment = #{checkComment}</if>
74
             <if test="cwUserId != null "> and c.cw_user_id = #{cwUserId}</if>
75
             <if test="cwUserId != null "> and c.cw_user_id = #{cwUserId}</if>
75
             <if test="cwTime != null "> and c.cw_time = #{cwTime}</if>
76
             <if test="cwTime != null "> and c.cw_time = #{cwTime}</if>
78
             <if test="managerTime != null "> and c.manager_time = #{managerTime}</if>
79
             <if test="managerTime != null "> and c.manager_time = #{managerTime}</if>
79
             <if test="managerComment != null  and managerComment != ''"> and c.manager_comment = #{managerComment}</if>
80
             <if test="managerComment != null  and managerComment != ''"> and c.manager_comment = #{managerComment}</if>
80
             <if test="zjlUserId != null "> and c.zjl_user_id = #{zjlUserId}</if>
81
             <if test="zjlUserId != null "> and c.zjl_user_id = #{zjlUserId}</if>
81
-            <if test="zjlTime != null "> and c.zjl_time = #{zjlTime}</if>
82
+            <if test="checkTime != null and @com.ruoyi.common.utils.DateUtils@parseDateToStr('yyyy', checkTime) == '2000' "> and c.check_time is not null</if>
83
+            <if test="checkTime != null and @com.ruoyi.common.utils.DateUtils@parseDateToStr('yyyy', checkTime) != '2000' "> and YEAR(c.check_time) = YEAR(#{checkTime})</if>
82
             <if test="zjlComment != null  and zjlComment != ''"> and c.zjl_comment = #{zjlComment}</if>
84
             <if test="zjlComment != null  and zjlComment != ''"> and c.zjl_comment = #{zjlComment}</if>
83
         </where>
85
         </where>
84
     </select>
86
     </select>
97
             <if test="checker != null">checker,</if>
99
             <if test="checker != null">checker,</if>
98
             <if test="checkTime != null">check_time,</if>
100
             <if test="checkTime != null">check_time,</if>
99
             <if test="checkComment != null">check_comment,</if>
101
             <if test="checkComment != null">check_comment,</if>
102
+            <if test="totalAdjust != null">total_adjust,</if>
100
             <if test="cwUserId != null">cw_user_id,</if>
103
             <if test="cwUserId != null">cw_user_id,</if>
101
             <if test="cwTime != null">cw_time,</if>
104
             <if test="cwTime != null">cw_time,</if>
102
             <if test="cwComment != null">cw_comment,</if>
105
             <if test="cwComment != null">cw_comment,</if>
114
             <if test="checker != null">#{checker},</if>
117
             <if test="checker != null">#{checker},</if>
115
             <if test="checkTime != null">#{checkTime},</if>
118
             <if test="checkTime != null">#{checkTime},</if>
116
             <if test="checkComment != null">#{checkComment},</if>
119
             <if test="checkComment != null">#{checkComment},</if>
120
+            <if test="totalAdjust != null">#{totalAdjust},</if>
117
             <if test="cwUserId != null">#{cwUserId},</if>
121
             <if test="cwUserId != null">#{cwUserId},</if>
118
             <if test="cwTime != null">#{cwTime},</if>
122
             <if test="cwTime != null">#{cwTime},</if>
119
             <if test="cwComment != null">#{cwComment},</if>
123
             <if test="cwComment != null">#{cwComment},</if>
134
             <if test="checker != null">checker = #{checker},</if>
138
             <if test="checker != null">checker = #{checker},</if>
135
             <if test="checkTime != null">check_time = #{checkTime},</if>
139
             <if test="checkTime != null">check_time = #{checkTime},</if>
136
             <if test="checkComment != null">check_comment = #{checkComment},</if>
140
             <if test="checkComment != null">check_comment = #{checkComment},</if>
141
+            <if test="totalAdjust != null">total_adjust = #{totalAdjust},</if>
137
             <if test="cwUserId != null">cw_user_id = #{cwUserId},</if>
142
             <if test="cwUserId != null">cw_user_id = #{cwUserId},</if>
138
             <if test="cwTime != null">cw_time = #{cwTime},</if>
143
             <if test="cwTime != null">cw_time = #{cwTime},</if>
139
             <if test="cwComment != null">cw_comment = #{cwComment},</if>
144
             <if test="cwComment != null">cw_comment = #{cwComment},</if>

+ 0
- 1
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcPerformanceStaffMapper.xml Просмотреть файл

8
         <result property="performanceStaffId"    column="performance_staff_id"    />
8
         <result property="performanceStaffId"    column="performance_staff_id"    />
9
         <result property="performanceId"    column="performance_id"    />
9
         <result property="performanceId"    column="performance_id"    />
10
         <result property="projectId"    column="project_id"    />
10
         <result property="projectId"    column="project_id"    />
11
-        <result property="projectNumber"    column="project_number"    />
12
         <result property="userId"    column="user_id"    />
11
         <result property="userId"    column="user_id"    />
13
         <result property="nickName"    column="nick_name"    />
12
         <result property="nickName"    column="nick_name"    />
14
         <result property="workType"    column="work_type"    />
13
         <result property="workType"    column="work_type"    />

+ 0
- 2
oa-back/ruoyi-system/src/main/resources/mapper/oa/CmcSettleMapper.xml Просмотреть файл

7
     <resultMap type="CmcSettle" id="CmcSettleResult">
7
     <resultMap type="CmcSettle" id="CmcSettleResult">
8
         <result property="settleId"    column="settle_id"    />
8
         <result property="settleId"    column="settle_id"    />
9
         <result property="projectId"    column="project_id"    />
9
         <result property="projectId"    column="project_id"    />
10
-        <result property="projectNumber"    column="project_number"    />
11
-        <result property="undertakingDept"    column="undertaking_dept"    />
12
         <result property="reportDept"    column="report_dept"    />
10
         <result property="reportDept"    column="report_dept"    />
13
         <result property="xmName"    column="xm_name"    />
11
         <result property="xmName"    column="xm_name"    />
14
         <result property="workloadReport"    column="workload_report"    />
12
         <result property="workloadReport"    column="workload_report"    />

+ 1
- 0
oa-ui/package.json Просмотреть файл

59
     "js-beautify": "1.13.0",
59
     "js-beautify": "1.13.0",
60
     "js-cookie": "3.0.1",
60
     "js-cookie": "3.0.1",
61
     "jsencrypt": "3.0.0-rc.1",
61
     "jsencrypt": "3.0.0-rc.1",
62
+    "marked": "^4.0.14",
62
     "nprogress": "0.2.0",
63
     "nprogress": "0.2.0",
63
     "ol": "^7.1.0",
64
     "ol": "^7.1.0",
64
     "pdfjs-dist": "^2.0.943",
65
     "pdfjs-dist": "^2.0.943",

+ 15
- 0
oa-ui/src/api/oa/budget/check.js Просмотреть файл

1
+/*
2
+ * @Author: wrh
3
+ * @Date: 2025-05-15 09:14:39
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-25 17:08:07
6
+ */
1
 import request from '@/utils/request'
7
 import request from '@/utils/request'
2
 
8
 
3
 // 查询cmc项目核算列表
9
 // 查询cmc项目核算列表
42
     method: 'delete'
48
     method: 'delete'
43
   })
49
   })
44
 }
50
 }
51
+
52
+// 核算统计
53
+export function getCheckStatistic(query) {
54
+  return request({
55
+    url: '/oa/check/statistic',
56
+    method: 'get',
57
+    params: query
58
+  })
59
+}

+ 51
- 45
oa-ui/src/views/flowable/form/budget/addBudget.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-06-21 18:51:51
3
  * @Date: 2024-06-21 18:51:51
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-07-08 10:23:25
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-31 16:41:48
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
9
     <h2 class="text-center">项目直接生产成本预算表</h2>
9
     <h2 class="text-center">项目直接生产成本预算表</h2>
10
-    <p style="text-align: center" v-if="taskName == '预算编制'">编制人:{{ $store.getters.name }}</p>
11
-    <p style="text-align: center" v-else>编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}</p>
10
+    <p style="text-align: center" v-if="taskName == '预算编制'">编制人:{{ $store.getters.name }} | 编制时间:{{ budgetForm.createTime }} </p>
11
+    <p style="text-align: center" v-else>编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }} | 编制时间:{{ budgetForm.createTime }} </p>
12
     <el-divider></el-divider>
12
     <el-divider></el-divider>
13
     <div class="mt20 mb20" v-if="showAlter">
13
     <div class="mt20 mb20" v-if="showAlter">
14
       <el-alert title="任务被退回,请修改后重新提交" type="error" :closable="false">
14
       <el-alert title="任务被退回,请修改后重新提交" type="error" :closable="false">
142
         @cancel="returnOpen = false"></return-btn>
142
         @cancel="returnOpen = false"></return-btn>
143
     </el-dialog>
143
     </el-dialog>
144
     <!-- 选择修改有多个预算的项目中的预算 -->
144
     <!-- 选择修改有多个预算的项目中的预算 -->
145
-    <el-dialog title="选择要修改的预算" :visible.sync="updateData" :close-on-click-modal="false"
146
-      :close-on-press-escape="false" :show-close="false"  width="30%" append-to-body>
147
-        <el-select v-model="selectedBudget" placeholder="请选择" style="width:100%">
148
-          <el-option
149
-            v-for="item in budgets"
150
-            :key="item.budgetId"
151
-            :label="item.project.projectName +'_'+ item.createTime"
152
-            :value="item.budgetId">
153
-          </el-option>
154
-        </el-select>
155
-        <div style="text-align: center">
156
-          <el-button type="success" style=" margin-top: 10px;"  @click="getBudgeNeesUpdate()">确定</el-button>
157
-        </div>
145
+    <el-dialog title="选择要修改的预算" :visible.sync="updateData" :close-on-click-modal="false" :close-on-press-escape="false"
146
+      :show-close="false" width="30%" append-to-body>
147
+      <el-select v-model="selectedBudget" placeholder="请选择" style="width:100%">
148
+        <el-option v-for="item in budgets" :key="item.budgetId" :label="item.project.projectName + '_' + item.createTime"
149
+          :value="item.budgetId">
150
+        </el-option>
151
+      </el-select>
152
+      <div style="text-align: center">
153
+        <el-button type="success" style=" margin-top: 10px;" @click="getBudgeNeesUpdate()">确定</el-button>
154
+      </div>
158
     </el-dialog>
155
     </el-dialog>
159
   </div>
156
   </div>
160
 </template>
157
 </template>
214
       viewOpen: false,
211
       viewOpen: false,
215
       innerSettleLimit: 0, // 内业预算绩效合计限制
212
       innerSettleLimit: 0, // 内业预算绩效合计限制
216
       outerUsers: [], // 存储外业人员
213
       outerUsers: [], // 存储外业人员
217
-      updateData:false,
218
-      selectedBudget:"",
219
-      budgets:{},
214
+      updateData: false,
215
+      selectedBudget: "",
216
+      budgets: {},
220
     };
217
     };
221
   },
218
   },
222
   props: {
219
   props: {
250
     async initBudgetForm() {
247
     async initBudgetForm() {
251
       const params = { pageNum: 1, pageSize: 20, projectId: this.taskForm.formId }
248
       const params = { pageNum: 1, pageSize: 20, projectId: this.taskForm.formId }
252
       let res = await listBudget(params)
249
       let res = await listBudget(params)
253
-      if (res.rows[0] && res.rows[0].budgetId){
254
-        // 如项目下已有预算,询问是新建预算还是修改原有预算
255
-        try{
256
-          await this.$confirm('该项目下已有预算,请选择修改已有预算还是创建新预算','系统提示',{
257
-                              distinguishCancelAndClose: true,confirmButtonText: '创建新预算',
258
-                              cancelButtonText: '修改已有预算',showClose: false, 
259
-                              closeOnClickModal: false, closeOnPressEscape: false});
260
-          this.flag = false;
261
-          this.budgetForm.projectId = this.taskForm.formId;
262
-          this.budgetForm.budgetId = new Snowflake(1n, 1n, 0n).nextId().toString();
263
-          this.budgetForm.procInstId = this.taskForm.procInsId;
264
-        }catch(action){
265
-          if (action === 'cancel') {
266
-            this.flag = true;
267
-            this.budgets = res.rows;
268
-            this.updateData = true;
269
-            // this.budgetForm = res.rows[0];
270
-            // this.budgetId = res.rows[0].budgetId;
250
+      if (res.rows[0] && res.rows[0].budgetId) {
251
+        if (this.taskName == '预算编制') {
252
+          // 如项目下已有预算,询问是新建预算还是修改原有预算
253
+          try {
254
+            await this.$confirm('该项目下已有预算,请选择修改已有预算还是创建新预算', '系统提示', {
255
+              distinguishCancelAndClose: true, confirmButtonText: '创建新预算',
256
+              cancelButtonText: '修改已有预算', showClose: false,
257
+              closeOnClickModal: false, closeOnPressEscape: false
258
+            });
259
+            this.flag = false;
260
+            this.budgetForm.projectId = this.taskForm.formId;
261
+            this.budgetForm.budgetId = new Snowflake(1n, 1n, 0n).nextId().toString();
262
+            this.budgetForm.procInstId = this.taskForm.procInsId;
263
+          } catch (action) {
264
+            if (action === 'cancel') {
265
+              this.flag = true;
266
+              this.budgets = res.rows;
267
+              this.updateData = true;
268
+              // this.budgetForm = res.rows[0];
269
+              // this.budgetId = res.rows[0].budgetId;
270
+            }
271
+          }
272
+        }
273
+        else {          
274
+          this.flag = true;
275
+          this.budgetForm = res.rows[0];
276
+          this.budgetId = res.rows[0].budgetId;
271
         }
277
         }
272
-      }}else {
273
-          this.flag = false;
274
-          this.budgetForm.projectId = this.taskForm.formId;
275
-          this.budgetForm.procInstId = this.taskForm.procInsId;
278
+      } else {
279
+        this.flag = false;
280
+        this.budgetForm.projectId = this.taskForm.formId;
281
+        this.budgetForm.procInstId = this.taskForm.procInsId;
276
       }
282
       }
277
       // listBudget({ pageNum: 1, pageSize: 20, projectId: this.taskForm.formId }).then(
283
       // listBudget({ pageNum: 1, pageSize: 20, projectId: this.taskForm.formId }).then(
278
       //   res => {
284
       //   res => {
483
         this.budgetForm.document = ""
489
         this.budgetForm.document = ""
484
       }
490
       }
485
     },
491
     },
486
-    getBudgeNeesUpdate(){
492
+    getBudgeNeesUpdate() {
487
       this.budgetForm = this.budgets.find(item => item.budgetId === this.selectedBudget);
493
       this.budgetForm = this.budgets.find(item => item.budgetId === this.selectedBudget);
488
       this.budgetId = this.selectedBudget;
494
       this.budgetId = this.selectedBudget;
489
-      this.updateData =false;
490
-   }
495
+      this.updateData = false;
496
+    }
491
   },
497
   },
492
 };
498
 };
493
 </script>
499
 </script>

+ 2
- 2
oa-ui/src/views/flowable/form/budget/adjust/adjustIndex.vue Просмотреть файл

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-05-14 16:09:56
3
  * @Date: 2025-05-14 16:09:56
4
  * @LastEditors: wrh
4
  * @LastEditors: wrh
5
- * @LastEditTime: 2025-09-30 16:39:33
5
+ * @LastEditTime: 2025-12-31 16:26:40
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
50
           </el-table-column>
50
           </el-table-column>
51
           <el-table-column label="项目编号" align="center" prop="project.projectNumber" />
51
           <el-table-column label="项目编号" align="center" prop="project.projectNumber" />
52
           <el-table-column label="项目名称" align="center" prop="project.projectName" />
52
           <el-table-column label="项目名称" align="center" prop="project.projectName" />
53
-          <el-table-column label="提交时间" align="center" prop="createTime" />
54
           <el-table-column label="预算总额" align="center" prop="totalBudget" />
53
           <el-table-column label="预算总额" align="center" prop="totalBudget" />
55
           <el-table-column label="编制人" align="center" prop="compiler">
54
           <el-table-column label="编制人" align="center" prop="compiler">
56
             <template slot-scope="scope">
55
             <template slot-scope="scope">
57
               {{ getUserName(scope.row.compiler) }}
56
               {{ getUserName(scope.row.compiler) }}
58
             </template>
57
             </template>
59
           </el-table-column>
58
           </el-table-column>
59
+          <el-table-column label="编制时间" align="center" prop="createTime" />
60
           <el-table-column label="预算当前流程节点" align="center" prop="taskName" />
60
           <el-table-column label="预算当前流程节点" align="center" prop="taskName" />
61
           <!-- <el-table-column label="审核人" align="center" prop="auditor">
61
           <!-- <el-table-column label="审核人" align="center" prop="auditor">
62
             <template slot-scope="scope">
62
             <template slot-scope="scope">

+ 6
- 3
oa-ui/src/views/flowable/form/budget/adjust/budgetAdjust.vue Просмотреть файл

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-05-07 11:01:39
3
  * @Date: 2025-05-07 11:01:39
4
  * @LastEditors: wrh
4
  * @LastEditors: wrh
5
- * @LastEditTime: 2025-09-30 16:13:13
5
+ * @LastEditTime: 2025-12-31 16:45:31
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="main">
8
   <div class="main">
33
       <el-descriptions-item label="项目备注" :span="3">
33
       <el-descriptions-item label="项目备注" :span="3">
34
         {{ project.remark }}
34
         {{ project.remark }}
35
       </el-descriptions-item>
35
       </el-descriptions-item>
36
-      <el-descriptions-item label="预算表单备注" :span="5">
36
+      <el-descriptions-item label="编制时间" :span="1">
37
+        {{ budgetForm.createTime }}
38
+      </el-descriptions-item>
39
+      <el-descriptions-item label="预算表单备注" :span="3">
37
         {{ budgetForm.remark }}
40
         {{ budgetForm.remark }}
38
       </el-descriptions-item>
41
       </el-descriptions-item>
39
       <el-descriptions-item label="预算附件" :span="3" v-if="budgetForm.document">
42
       <el-descriptions-item label="预算附件" :span="3" v-if="budgetForm.document">
820
 
823
 
821
         // 并发处理基础数据保存
824
         // 并发处理基础数据保存
822
         const savePromises = [];
825
         const savePromises = [];
823
-
826
+        this.checkForm.totalAdjust = this.totalBudgetAdjust
824
         if (!this.checkForm.checkId) {
827
         if (!this.checkForm.checkId) {
825
           savePromises.push(addCheck(obj));
828
           savePromises.push(addCheck(obj));
826
           this.$emit('preserve');
829
           this.$emit('preserve');

+ 2
- 2
oa-ui/src/views/flowable/form/budget/adjust/newBudgetInfo.vue Просмотреть файл

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-05-07 11:01:39
3
  * @Date: 2025-05-07 11:01:39
4
  * @LastEditors: wrh
4
  * @LastEditors: wrh
5
- * @LastEditTime: 2025-09-30 16:23:05
5
+ * @LastEditTime: 2025-12-31 16:22:00
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="main" v-loading="loading">
8
   <div class="main" v-loading="loading">
9
     <h2 class="text-center">项目直接生产成本预算表</h2>
9
     <h2 class="text-center">项目直接生产成本预算表</h2>
10
-    <p style="text-align: center">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}</p>
10
+    <p style="text-align: center">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }} | 编制时间:{{ budgetForm.createTime }} </p>
11
     <el-divider></el-divider>
11
     <el-divider></el-divider>
12
     <div class="mt20 mb20" v-if="showAlter && taskName">
12
     <div class="mt20 mb20" v-if="showAlter && taskName">
13
       <el-alert title="任务被退回,请修改后重新提交" type="error" :closable="false">
13
       <el-alert title="任务被退回,请修改后重新提交" type="error" :closable="false">

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

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-04-03 16:28:09
3
  * @Date: 2024-04-03 16:28:09
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-05-27 15:11:17
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-31 16:22:43
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="main">
8
   <div class="main">
9
     <div v-loading="loading">
9
     <div v-loading="loading">
10
       <h2 class="text-center">项目直接生产成本预算表(旧版)</h2>
10
       <h2 class="text-center">项目直接生产成本预算表(旧版)</h2>
11
-      <p style="text-align: center;">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }}</p>
11
+      <p style="text-align: center;">编制人:{{ budgetForm.compilerUser ? budgetForm.compilerUser.nickName : '' }} | 编制时间:{{ budgetForm.createTime }} </p>
12
       <el-descriptions :column="3" border class="descriptions">
12
       <el-descriptions :column="3" border class="descriptions">
13
         <el-descriptions-item label="项目编号">
13
         <el-descriptions-item label="项目编号">
14
           {{ projectForm.projectNumber }}
14
           {{ projectForm.projectNumber }}

+ 49
- 18
oa-ui/src/views/flowable/form/business/subContract.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:49:17
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-16 11:06:33
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
27
           <el-form-item label="承接单位" prop="partnerId">
27
           <el-form-item label="承接单位" prop="partnerId">
28
             <el-select allow-create v-model="form.partnerId" multiple filterable placeholder="请选择"
28
             <el-select allow-create v-model="form.partnerId" multiple filterable placeholder="请选择"
29
               :style="taskName == '合同拟稿' ? { width: '84%' } : { width: '100%' }" disabled clearable>
29
               :style="taskName == '合同拟稿' ? { width: '84%' } : { width: '100%' }" disabled clearable>
30
-              <el-option v-for="item in partnerList" :key="item.value" :label="item.partnerName"
31
-                :value="item.partnerId">
30
+              <el-option v-for="item in partnerList" :key="item.value" :label="item.partnerName" :value="item.partnerId">
32
               </el-option>
31
               </el-option>
33
             </el-select>
32
             </el-select>
34
             <el-button type="primary" @click="partnerOpen = true" size="mini" v-if="taskName == '合同拟稿'">选择单位</el-button>
33
             <el-button type="primary" @click="partnerOpen = true" size="mini" v-if="taskName == '合同拟稿'">选择单位</el-button>
303
           </el-row>
302
           </el-row>
304
           <el-divider></el-divider>
303
           <el-divider></el-divider>
305
           <el-form-item label="签订日期" prop="signDate">
304
           <el-form-item label="签订日期" prop="signDate">
306
-            <el-date-picker clearable v-model="form.signDate" type="date" value-format="yyyy-MM-dd"
307
-              placeholder="请选择签订日期" :disabled="taskName != '合同签订'">
305
+            <el-date-picker clearable v-model="form.signDate" type="date" value-format="yyyy-MM-dd" placeholder="请选择签订日期"
306
+              :disabled="taskName != '合同签订'">
308
             </el-date-picker>
307
             </el-date-picker>
309
           </el-form-item>
308
           </el-form-item>
310
           <el-form-item label="签订备注" prop="signRemark">
309
           <el-form-item label="签订备注" prop="signRemark">
350
     <el-dialog title="选择合作单位" :visible.sync="partnerOpen" width="70%" append-to-body>
349
     <el-dialog title="选择合作单位" :visible.sync="partnerOpen" width="70%" append-to-body>
351
       <choose-partner @confirm="confirmPartners"></choose-partner>
350
       <choose-partner @confirm="confirmPartners"></choose-partner>
352
     </el-dialog>
351
     </el-dialog>
352
+    <el-dialog title="选择承接合同" :visible.sync="contractOpen" width="70%" append-to-body>
353
+      <choose-contract @choose="confirmContract"></choose-contract>
354
+    </el-dialog>
353
     <el-drawer :visible.sync="drawerOpen" title="" :size="'70%'" append-to-body>
355
     <el-drawer :visible.sync="drawerOpen" title="" :size="'70%'" append-to-body>
354
       <projectInfo :needReturn="false"></projectInfo>
356
       <projectInfo :needReturn="false"></projectInfo>
355
     </el-drawer>
357
     </el-drawer>
390
 import paymentTable from './components/paymentTable.vue';
392
 import paymentTable from './components/paymentTable.vue';
391
 import projectChoose from '../components/chooseProject.vue';
393
 import projectChoose from '../components/chooseProject.vue';
392
 import ChoosePartner from '../components/choosePartner.vue';
394
 import ChoosePartner from '../components/choosePartner.vue';
395
+import ChooseContract from '@/views/flowable/form/components/chooseContract.vue';
393
 import contractForm from '@/views/flowable/form/business/contractForm.vue';
396
 import contractForm from '@/views/flowable/form/business/contractForm.vue';
394
 import ReturnBtn from '@/views/flowable/form/components/flowBtn/returnBtn.vue';
397
 import ReturnBtn from '@/views/flowable/form/components/flowBtn/returnBtn.vue';
395
 import ReturnComment from '@/views/flowable/form/components/flowBtn/returnComment.vue';
398
 import ReturnComment from '@/views/flowable/form/components/flowBtn/returnComment.vue';
398
   components: {
401
   components: {
399
     flow,
402
     flow,
400
     projectChoose,
403
     projectChoose,
404
+    ChooseContract,
401
     FileItem,
405
     FileItem,
402
     ChoosePartner,
406
     ChoosePartner,
403
     workTable,
407
     workTable,
708
                   commentTime: undefined
712
                   commentTime: undefined
709
                 },
713
                 },
710
               ]
714
               ]
711
-              let num=0;
715
+              let num = 0;
712
               for (let comment of this.commentList) {
716
               for (let comment of this.commentList) {
713
                 num = num + 1;
717
                 num = num + 1;
714
-                if(num<=3){
718
+                if (num <= 3) {
715
                   getUsersDeptLeaderByDept({ deptId: comment.deptId }).then(res => {
719
                   getUsersDeptLeaderByDept({ deptId: comment.deptId }).then(res => {
716
                     comment.userId = res.data.userId;
720
                     comment.userId = res.data.userId;
717
-                })}
718
-                else{
721
+                  })
722
+                }
723
+                else {
719
                   getUserByPost({ postName: '专职安全员' }).then(res => {
724
                   getUserByPost({ postName: '专职安全员' }).then(res => {
720
-                  comment.userId =res.data[0].userId;
721
-                })
725
+                    comment.userId = res.data[0].userId;
726
+                  })
722
                 }
727
                 }
723
               }
728
               }
724
             }
729
             }
833
       else if (val == '2') {
838
       else if (val == '2') {
834
         this.commentOpen = true;
839
         this.commentOpen = true;
835
         this.meetingOpen = false;
840
         this.meetingOpen = false;
836
-        let num=0;
841
+        let num = 0;
837
         for (let comment of this.commentList) {
842
         for (let comment of this.commentList) {
838
           num = num + 1;
843
           num = num + 1;
839
-          if(num<=3){
844
+          if (num <= 3) {
840
             getUsersDeptLeaderByDept({ deptId: comment.deptId }).then(res => {
845
             getUsersDeptLeaderByDept({ deptId: comment.deptId }).then(res => {
841
               comment.userId = res.data.userId;
846
               comment.userId = res.data.userId;
842
-          })}
843
-          else{
847
+            })
848
+          }
849
+          else {
844
             getUserByPost({ postName: '专职安全员' }).then(res => {
850
             getUserByPost({ postName: '专职安全员' }).then(res => {
845
-            comment.userId =res.data[0].userId;
846
-          })
851
+              comment.userId = res.data[0].userId;
852
+            })
847
           }
853
           }
848
         }
854
         }
849
       }
855
       }
892
         this.chooseProjectList.forEach(item => {
898
         this.chooseProjectList.forEach(item => {
893
           addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId })
899
           addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId })
894
         })
900
         })
901
+        this.connectContractList.forEach(item => {
902
+          addContractSubcontract({ subContractId: subContractId, contractId: item.contractId })
903
+        })
895
         for (let work of this.workList) {
904
         for (let work of this.workList) {
896
           work.contractId = subContractId;
905
           work.contractId = subContractId;
897
           await addContractWork(work);
906
           await addContractWork(work);
996
             this.chooseProjectList.forEach(item => {
1005
             this.chooseProjectList.forEach(item => {
997
               addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId })
1006
               addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId })
998
             })
1007
             })
1008
+            this.connectContractList.forEach(item => {
1009
+              addContractSubcontract({ subContractId: subContractId, contractId: item.contractId })
1010
+            })
999
             for (let work of this.workList) {
1011
             for (let work of this.workList) {
1000
               work.contractId = subContractId;
1012
               work.contractId = subContractId;
1001
               addContractWork(work);
1013
               addContractWork(work);
1065
         for (let item of this.chooseProjectList) {
1077
         for (let item of this.chooseProjectList) {
1066
           await addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId });
1078
           await addProjectSubcontract({ subContractId: subContractId, projectId: item.projectId });
1067
         }
1079
         }
1080
+        // 删除承接分包合同
1081
+        await delContractSubcontract(subContractId);
1082
+        // 添加新的承接分包合同
1083
+        for (let item of this.connectContractList) {
1084
+          await addContractSubcontract({ subContractId: subContractId, contractId: item.contractId });
1085
+        }
1068
         // 删除合同工作
1086
         // 删除合同工作
1069
         await delContractWork(subContractId);
1087
         await delContractWork(subContractId);
1070
         // 添加新的合同工作
1088
         // 添加新的合同工作
1120
         })
1138
         })
1121
       }
1139
       }
1122
     },
1140
     },
1141
+    async confirmContract(val) {
1142
+      let isSame = this.haveSameIds([val], this.connectContractList, 'contractId');
1143
+      if (isSame) {
1144
+        this.$message.error('请勿重复添加已有的合同');
1145
+        return
1146
+      }
1147
+      this.contractOpen = false;
1148
+      this.connectContractList.push(val)
1149
+
1150
+    },
1151
+    haveSameIds(arr1, arr2, key) {
1152
+      return arr1.some(obj1 => arr2.some(obj2 => obj1[key] === obj2[key]))
1153
+    },
1123
     // 获取合同详情
1154
     // 获取合同详情
1124
     fetchContracts(projectId) {
1155
     fetchContracts(projectId) {
1125
       return new Promise((resolve, reject) => {
1156
       return new Promise((resolve, reject) => {

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

2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-04-07 14:14:05
3
  * @Date: 2025-04-07 14:14:05
4
  * @LastEditors: wrh
4
  * @LastEditors: wrh
5
- * @LastEditTime: 2025-11-19 16:23:11
5
+ * @LastEditTime: 2025-12-17 16:24:24
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
262
 
262
 
263
             <div class="input-wrapper">
263
             <div class="input-wrapper">
264
               <el-input v-model="inputMessage" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 6 }"
264
               <el-input v-model="inputMessage" type="textarea" :rows="1" :autosize="{ minRows: 1, maxRows: 6 }"
265
-                placeholder="输入您的问题..." @keydown.native.enter="handleEnter" @keydown.native.ctrl.enter="handleCtrlEnter"
265
+                placeholder="输入您的问题..." @keydown.native.enter="handleKeyDown" @keydown.native.ctrl.enter="handleKeyDown"
266
                 class="message-input" resize="none" />
266
                 class="message-input" resize="none" />
267
               <div class="input-actions">
267
               <div class="input-actions">
268
                 <el-button circle size="small" class="action-btn" @click="handleFileUpload" icon="el-icon-paperclip">
268
                 <el-button circle size="small" class="action-btn" @click="handleFileUpload" icon="el-icon-paperclip">
294
 import { listDocument, uploadDocument } from "@/api/llm/document";
294
 import { listDocument, uploadDocument } from "@/api/llm/document";
295
 import { getAnswer, getAnswerWithDocument } from "@/api/llm/session";
295
 import { getAnswer, getAnswerWithDocument } from "@/api/llm/session";
296
 import logoImg from '@/assets/images/logo.png'
296
 import logoImg from '@/assets/images/logo.png'
297
+import { marked } from 'marked';
297
 
298
 
298
 export default {
299
 export default {
299
   name: 'ChatView',
300
   name: 'ChatView',
679
     },
680
     },
680
 
681
 
681
     formatMessage(content) {
682
     formatMessage(content) {
682
-      // 简单的消息格式化,可以扩展支持markdown等
683
-      return content.replace(/\n/g, '<br>');
683
+      // 使用marked.js解析markdown内容
684
+      return marked(content);
684
     },
685
     },
685
 
686
 
686
     formatMessageTime(time) {
687
     formatMessageTime(time) {
1324
     transform: rotate(360deg);
1325
     transform: rotate(360deg);
1325
   }
1326
   }
1326
 }
1327
 }
1328
+
1329
+/* Markdown样式 */
1330
+.message-bubble >>> .message-text {
1331
+  /* 标题样式 */
1332
+  h1 {
1333
+    font-size: 24px;
1334
+    font-weight: 700;
1335
+    margin: 16px 0 12px 0;
1336
+    color: #333;
1337
+  }
1338
+
1339
+  h2 {
1340
+    font-size: 20px;
1341
+    font-weight: 600;
1342
+    margin: 14px 0 10px 0;
1343
+    color: #333;
1344
+  }
1345
+
1346
+  h3 {
1347
+    font-size: 18px;
1348
+    font-weight: 600;
1349
+    margin: 12px 0 8px 0;
1350
+    color: #333;
1351
+  }
1352
+
1353
+  h4, h5, h6 {
1354
+    font-size: 16px;
1355
+    font-weight: 600;
1356
+    margin: 10px 0 6px 0;
1357
+    color: #333;
1358
+  }
1359
+
1360
+  /* 段落样式 */
1361
+  p {
1362
+    margin: 8px 0;
1363
+    line-height: 1.6;
1364
+  }
1365
+
1366
+  /* 列表样式 */
1367
+  ul, ol {
1368
+    margin: 8px 0;
1369
+    padding-left: 24px;
1370
+  }
1371
+
1372
+  li {
1373
+    margin: 4px 0;
1374
+    line-height: 1.6;
1375
+  }
1376
+
1377
+  /* 代码块样式 */
1378
+  pre {
1379
+    background-color: #f5f5f5;
1380
+    border-radius: 6px;
1381
+    padding: 12px;
1382
+    overflow-x: auto;
1383
+    margin: 12px 0;
1384
+    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
1385
+    font-size: 14px;
1386
+    line-height: 1.5;
1387
+  }
1388
+
1389
+  code {
1390
+    background-color: #f0f0f0;
1391
+    border-radius: 3px;
1392
+    padding: 2px 6px;
1393
+    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
1394
+    font-size: 14px;
1395
+  }
1396
+
1397
+  pre code {
1398
+    background-color: transparent;
1399
+    padding: 0;
1400
+  }
1401
+
1402
+  /* 引用样式 */
1403
+  blockquote {
1404
+    border-left: 4px solid #007bff;
1405
+    padding: 8px 12px;
1406
+    margin: 12px 0;
1407
+    background-color: #f8f9fa;
1408
+    color: #666;
1409
+    border-radius: 0 6px 6px 0;
1410
+  }
1411
+
1412
+  /* 表格样式 */
1413
+  table {
1414
+    border-collapse: collapse;
1415
+    width: 100%;
1416
+    margin: 12px 0;
1417
+  }
1418
+
1419
+  th, td {
1420
+    border: 1px solid #e9ecef;
1421
+    padding: 8px 12px;
1422
+    text-align: left;
1423
+  }
1424
+
1425
+  th {
1426
+    background-color: #f8f9fa;
1427
+    font-weight: 600;
1428
+  }
1429
+
1430
+  /* 链接样式 */
1431
+  a {
1432
+    color: #007bff;
1433
+    text-decoration: none;
1434
+    transition: color 0.2s ease;
1435
+  }
1436
+
1437
+  a:hover {
1438
+    color: #0056b3;
1439
+    text-decoration: underline;
1440
+  }
1441
+
1442
+  /* 粗体和斜体样式 */
1443
+  strong {
1444
+    font-weight: 600;
1445
+  }
1446
+
1447
+  em {
1448
+    font-style: italic;
1449
+  }
1450
+
1451
+  /* 水平线样式 */
1452
+  hr {
1453
+    border: none;
1454
+    border-top: 1px solid #e9ecef;
1455
+    margin: 20px 0;
1456
+  }
1457
+}
1327
 </style>
1458
 </style>

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

51
           {{ getUserName(scope.row.compiler) }}
51
           {{ getUserName(scope.row.compiler) }}
52
         </template>
52
         </template>
53
       </el-table-column>
53
       </el-table-column>
54
+      <el-table-column label="编制时间" align="center" prop="createTime" />
54
       <el-table-column label="审核人" align="center" prop="auditor">
55
       <el-table-column label="审核人" align="center" prop="auditor">
55
         <template slot-scope="scope">
56
         <template slot-scope="scope">
56
           {{ getUserName(scope.row.auditor) }}
57
           {{ getUserName(scope.row.auditor) }}

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

132
           <el-input v-model="form.expectKm" placeholder="请输入里程" style="width:130px;margin-right:10px;" />
132
           <el-input v-model="form.expectKm" placeholder="请输入里程" style="width:130px;margin-right:10px;" />
133
           <span>万千米</span>
133
           <span>万千米</span>
134
         </el-form-item>
134
         </el-form-item>
135
-        <el-form-item label="油耗(元/km)" prop="cost">
135
+        <el-form-item label="油耗(元/km)" prop="fuel">
136
           <el-input style="width:130px;margin-right:10px;" v-model="form.fuel" placeholder="请输入金额" />
136
           <el-input style="width:130px;margin-right:10px;" v-model="form.fuel" placeholder="请输入金额" />
137
           <span>元</span>
137
           <span>元</span>
138
         </el-form-item>
138
         </el-form-item>
139
-        <el-form-item label="保险(元/天)" prop="cost">
139
+        <el-form-item label="保险(元/天)" prop="insurance">
140
           <el-input style="width:130px;margin-right:10px;" v-model="form.insurance" placeholder="请输入金额" />
140
           <el-input style="width:130px;margin-right:10px;" v-model="form.insurance" placeholder="请输入金额" />
141
           <span>元</span>
141
           <span>元</span>
142
         </el-form-item>
142
         </el-form-item>
143
-        <el-form-item label="维修(元/天)" prop="cost">
143
+        <el-form-item label="维修(元/天)" prop="maintenance">
144
           <el-input style="width:130px;margin-right:10px;" v-model="form.maintenance" placeholder="请输入金额" />
144
           <el-input style="width:130px;margin-right:10px;" v-model="form.maintenance" placeholder="请输入金额" />
145
           <span>元</span>
145
           <span>元</span>
146
         </el-form-item>
146
         </el-form-item>
147
+        <el-form-item label="单日成本" prop="dayCost">
148
+          <el-input style="width:130px;margin-right:10px;" v-model="form.dayCost" placeholder="请输入金额" />
149
+          <span>元</span>
150
+        </el-form-item>
147
         <el-form-item label="驾驶员" prop="driver">
151
         <el-form-item label="驾驶员" prop="driver">
148
           <el-select v-model="form.driver" filterable placeholder="请选择" clearable>
152
           <el-select v-model="form.driver" filterable placeholder="请选择" clearable>
149
             <el-option v-for="item in driverList" :key="item.userId" :label="item.nickName" :value="item.userId">
153
             <el-option v-for="item in driverList" :key="item.userId" :label="item.nickName" :value="item.userId">

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

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-03-05 14:19:02
3
  * @Date: 2025-03-05 14:19:02
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-08-12 16:40:17
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2026-01-04 11:30:16
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="head-bg">
8
   <div class="head-bg">
22
         <div class="user-item">
22
         <div class="user-item">
23
           <div class="u-info-learn" style="cursor:pointer;">
23
           <div class="u-info-learn" style="cursor:pointer;">
24
             <em>{{ hours }}h</em>
24
             <em>{{ hours }}h</em>
25
-            <span>2025学时</span>
25
+            <span>{{new Date().getFullYear()+"学时"}}</span>
26
           </div>
26
           </div>
27
         </div>
27
         </div>
28
       </div>
28
       </div>

+ 4
- 4
oa-ui/src/views/oa/study/record.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2025-03-12 10:06:03
3
  * @Date: 2025-03-12 10:06:03
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2025-08-12 16:39:40
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2026-01-05 09:22:11
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container">
8
   <div class="app-container">
83
                   <!-- 人员节点 -->
83
                   <!-- 人员节点 -->
84
                   <span v-else class="user-node">
84
                   <span v-else class="user-node">
85
                     <i class="el-icon-user"></i>
85
                     <i class="el-icon-user"></i>
86
-                    {{ `${data.user.nickName} (学时:${data.getHours}h)` }}
86
+                    {{ `${data.user.nickName} (学时:${data.getHours.toFixed(1)}h)` }}
87
                   </span>
87
                   </span>
88
                 </div>
88
                 </div>
89
               </el-tree>
89
               </el-tree>
186
       getStudyStatistic(this.rankParams).then(res => {
186
       getStudyStatistic(this.rankParams).then(res => {
187
         this.rankList = res.rows.map((item, index) => ({
187
         this.rankList = res.rows.map((item, index) => ({
188
           ...item,
188
           ...item,
189
-          getHours: item.getHours ? item.getHours : 0,
189
+          getHours: item.getHours ? item.getHours.toFixed(1) : 0,
190
           rankIndex: (this.rankParams.pageNum - 1) * this.rankParams.pageSize + index + 1
190
           rankIndex: (this.rankParams.pageNum - 1) * this.rankParams.pageSize + index + 1
191
         }));
191
         }));
192
         this.rankTotal = res.total;
192
         this.rankTotal = res.total;

+ 4
- 4
oa-ui/src/views/statistics/components/borrowStatistics.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-10-18 11:17:48
3
  * @Date: 2024-10-18 11:17:48
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-12-20 10:00:35
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-26 15:00:24
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div style="width:100%;" v-loading="loading">
8
   <div style="width:100%;" v-loading="loading">
9
-    <div class="titles">借款和结算统计</div>
9
+    <div class="titles">借款统计</div>
10
     <div class="warpper">
10
     <div class="warpper">
11
       <div class="left">
11
       <div class="left">
12
         <div class="left-top" id="borrowBar"></div>
12
         <div class="left-top" id="borrowBar"></div>
318
         yAxis: [
318
         yAxis: [
319
           {
319
           {
320
             type: 'value',
320
             type: 'value',
321
-            name: '金额',
321
+            name: '单位:元',
322
           }
322
           }
323
         ],
323
         ],
324
         series: [
324
         series: [

+ 16
- 2
oa-ui/src/views/statistics/components/projectStatistics.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-10-11 16:41:17
3
  * @Date: 2024-10-11 16:41:17
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-10-24 16:16:05
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-24 19:13:16
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div style="width:100%;" v-loading="loading">
8
   <div style="width:100%;" v-loading="loading">
48
       archive:{},
48
       archive:{},
49
       complete:{},
49
       complete:{},
50
       settle:{},
50
       settle:{},
51
+      check:{},
51
       loading: true,
52
       loading: true,
52
       activeYear: '',
53
       activeYear: '',
53
       dataLoading: false,
54
       dataLoading: false,
93
         this.archive = this.datas.archive[0];
94
         this.archive = this.datas.archive[0];
94
         this.complete = this.datas.complete[0];
95
         this.complete = this.datas.complete[0];
95
         this.settle = this.datas.settle[0];
96
         this.settle = this.datas.settle[0];
97
+        this.check = this.datas.check[0];
96
         this.loading = false;
98
         this.loading = false;
97
       }
99
       }
98
 
100
 
189
             },
191
             },
190
             z:3
192
             z:3
191
           },
193
           },
194
+          {
195
+            name:'已核算',
196
+            type: 'line',
197
+            data: Object.values(this.check),
198
+            smooth: true,
199
+            areaStyle: {},
200
+            label: {
201
+              show: true,
202
+              position: 'top',
203
+            },
204
+            z:5
205
+          },
192
           {
206
           {
193
             name:'总数',
207
             name:'总数',
194
             type: 'line',
208
             type: 'line',

+ 89
- 59
oa-ui/src/views/statistics/components/settleStatistics.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-10-18 11:17:48
3
  * @Date: 2024-10-18 11:17:48
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-12-20 10:11:56
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-26 14:47:09
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div style="width:100%;" v-loading="loading">
8
   <div style="width:100%;" v-loading="loading">
9
-    <div class="titles">结算和算统计</div>
9
+    <div class="titles">结算和算统计</div>
10
     <div class="warpper">
10
     <div class="warpper">
11
       <div class="left">
11
       <div class="left">
12
         <div class="left-top" id="settleBar"></div>
12
         <div class="left-top" id="settleBar"></div>
30
       type: Object,
30
       type: Object,
31
       require: true,
31
       require: true,
32
     },
32
     },
33
+    checkData: {
34
+      type: Object,
35
+      require: true,
36
+    },
33
   },
37
   },
34
   watch: {
38
   watch: {
35
     settleType() {
39
     settleType() {
36
       this.initSettleTypePie(this.activeYear)
40
       this.initSettleTypePie(this.activeYear)
37
     },
41
     },
38
     settleData() {
42
     settleData() {
39
-      this.initDatas();
43
+      this.initSettleDatas();
44
+    },
45
+    checkData() {
46
+      this.initCheckDatas();
40
     }
47
     }
41
   },
48
   },
42
   data() {
49
   data() {
43
     return {
50
     return {
44
       loading: false,
51
       loading: false,
45
-      settleAmount: {},
46
       settleType: {},
52
       settleType: {},
47
       settleTypeAmount: {},
53
       settleTypeAmount: {},
48
       settleYear: {},
54
       settleYear: {},
49
-      settleYear: {},
50
       settleAmount: {},
55
       settleAmount: {},
51
-      yearProjectAmount: {},
52
-      yearProjectCount: {},
53
-      sumSettleAmount: 0,
56
+      yearSettleProjectAmount: {},
57
+      yearSettleProjectCount: {},
58
+      yearCheckProjectAmount: {},
59
+      yearCheckProjectCount: {},
54
       sumSettleAmount: 0,
60
       sumSettleAmount: 0,
61
+      sumCheckAmount: 0,
62
+      checkYear: {},
63
+      checkAmount: {},
55
       dataLoading: false,
64
       dataLoading: false,
56
       activeYear: ''
65
       activeYear: ''
57
     }
66
     }
58
   },
67
   },
59
   created() {
68
   created() {
60
     this.loading = true;
69
     this.loading = true;
61
-    this.initDatas();
70
+    this.initSettleDatas();
71
+    this.initCheckDatas();
62
   },
72
   },
63
   mounted() {
73
   mounted() {
64
     this.initSettleYearBar();
74
     this.initSettleYearBar();
66
     this.initSettleTypePie('');
76
     this.initSettleTypePie('');
67
     // this.initSettleTypeAmountPie('');
77
     // this.initSettleTypeAmountPie('');
68
     this.initSettleProjectLineBar();
78
     this.initSettleProjectLineBar();
69
-    this.initSettleAmountLine();
70
   },
79
   },
71
   methods: {
80
   methods: {
72
-    initDatas() {
81
+    initSettleDatas() {
73
       if (Object.keys(this.settleData).length !== 0) {
82
       if (Object.keys(this.settleData).length !== 0) {
74
         this.settleAmount = this.settleData.amount[0];
83
         this.settleAmount = this.settleData.amount[0];
75
         this.settleType = this.settleData.type[0];
84
         this.settleType = this.settleData.type[0];
76
         this.settleTypeAmount = this.settleData.typeAmount[0];
85
         this.settleTypeAmount = this.settleData.typeAmount[0];
77
         this.settleYear = this.settleData.year[0];
86
         this.settleYear = this.settleData.year[0];
78
-        this.yearProjectAmount = this.settleData.yearProjectAmount[0];
79
-        this.yearProjectCount = this.settleData.yearProjectCount[0];
87
+        this.yearSettleProjectAmount = this.settleData.yearProjectAmount[0];
88
+        this.yearSettleProjectCount = this.settleData.yearProjectCount[0];
80
         let sum = Object.values(this.settleAmount).reduce((accumulator, currentValue) => accumulator + currentValue, 0);
89
         let sum = Object.values(this.settleAmount).reduce((accumulator, currentValue) => accumulator + currentValue, 0);
81
         this.sumSettleAmount = (sum / 10000).toFixed(1)
90
         this.sumSettleAmount = (sum / 10000).toFixed(1)
82
         this.loading = false;
91
         this.loading = false;
84
         this.loading = true;
93
         this.loading = true;
85
       }
94
       }
86
     },
95
     },
96
+    initCheckDatas() {
97
+      if (Object.keys(this.checkData).length !== 0) {
98
+        this.checkAmount = this.checkData.amount[0];
99
+        this.checkYear = this.checkData.year[0];
100
+        this.yearCheckProjectAmount = this.checkData.yearProjectAmount[0];
101
+        this.yearCheckProjectCount = this.checkData.yearProjectCount[0];
102
+        let sum = Object.values(this.checkAmount).reduce((accumulator, currentValue) => accumulator + currentValue, 0);
103
+        this.sumCheckAmount = (sum / 10000).toFixed(1)
104
+        this.loading = false;
105
+      } else {
106
+        this.loading = true;
107
+      }
108
+    },
87
     clickYear(charts) {
109
     clickYear(charts) {
88
       let that = this;
110
       let that = this;
89
       charts.on('click', function (event) {
111
       charts.on('click', function (event) {
115
           height: '60%',
137
           height: '60%',
116
           containLabel: true
138
           containLabel: true
117
         },
139
         },
140
+        legend: {},
118
         graphic: [
141
         graphic: [
119
           {
142
           {
120
             type: 'text',
143
             type: 'text',
149
         },
172
         },
150
         series: [
173
         series: [
151
           {
174
           {
175
+            name: "结算",
152
             data: Object.values(this.settleYear),
176
             data: Object.values(this.settleYear),
153
             type: 'bar',
177
             type: 'bar',
154
             smooth: true,
178
             smooth: true,
159
             itemStyle: {
183
             itemStyle: {
160
               color: '#3498DB'
184
               color: '#3498DB'
161
             }
185
             }
186
+          },
187
+          {
188
+            name: "核算",
189
+            data: Object.values(this.checkYear),
190
+            type: 'bar',
191
+            smooth: true,
192
+            label: {
193
+              show: true,
194
+              position: 'top'
195
+            },
196
+            itemStyle: {
197
+              color: '#46CB2B'
198
+            }
162
           }
199
           }
163
         ]
200
         ]
164
       };
201
       };
170
         title: {
207
         title: {
171
           text: '各年结算金额',
208
           text: '各年结算金额',
172
           subtext: '结算总额:' + (Object.values(this.settleAmount).reduce((accumulator, currentValue) => {return accumulator + currentValue}, 0)).toFixed(2) + '元' +
209
           subtext: '结算总额:' + (Object.values(this.settleAmount).reduce((accumulator, currentValue) => {return accumulator + currentValue}, 0)).toFixed(2) + '元' +
173
-            '(约' + this.sumSettleAmount + '万元)'
210
+            '(约' + this.sumSettleAmount + '万元)' +
211
+            "\n" + 
212
+            '核算总额:' + (Object.values(this.checkAmount).reduce((accumulator, currentValue) => {return accumulator + currentValue}, 0)).toFixed(2) + '元' +
213
+            '(约' + this.sumCheckAmount + '万元)'
174
         },
214
         },
175
         grid: {
215
         grid: {
176
           left: '1%',
216
           left: '1%',
178
           bottom: '0%',
218
           bottom: '0%',
179
           height: '60%',
219
           height: '60%',
180
           containLabel: true
220
           containLabel: true
221
+        },        
222
+        legend: {
223
+          right: '0%',
224
+          orient: 'vertical'
181
         },
225
         },
182
         tooltip: {
226
         tooltip: {
183
           trigger: 'axis',
227
           trigger: 'axis',
198
         },
242
         },
199
         series: [
243
         series: [
200
           {
244
           {
201
-            min: 0,
245
+            name: "结算",
202
             data: Object.values(this.settleAmount),
246
             data: Object.values(this.settleAmount),
203
             type: 'line',
247
             type: 'line',
204
             smooth: true,
248
             smooth: true,
212
                 }
256
                 }
213
               }
257
               }
214
             }
258
             }
259
+          },
260
+          {
261
+            name: "核算",
262
+            data: Object.values(this.checkAmount),
263
+            type: 'line',
264
+            smooth: true,
265
+            label: {
266
+              show: true,
267
+              position: 'top',
268
+              formatter: function (params) {
269
+                let value = params.value;
270
+                if (value >= 10000) {
271
+                  return '约' + (value / 10000).toFixed(1) + '万元'
272
+                }
273
+              }
274
+            }
215
           }
275
           }
216
         ]
276
         ]
217
       };
277
       };
315
         xAxis: [
375
         xAxis: [
316
           {
376
           {
317
             type: 'category',
377
             type: 'category',
318
-            data: Object.keys(this.yearProjectAmount),
378
+            data: Object.keys(this.yearSettleProjectAmount),
319
             axisPointer: {
379
             axisPointer: {
320
               type: 'shadow'
380
               type: 'shadow'
321
             }
381
             }
324
         yAxis: [
384
         yAxis: [
325
           {
385
           {
326
             type: 'value',
386
             type: 'value',
327
-            name: '金额',
387
+            name: '单位:元',
328
           }
388
           }
329
         ],
389
         ],
330
         series: [
390
         series: [
331
           {
391
           {
392
+            name: "结算",
332
             type: 'line',
393
             type: 'line',
333
             tooltip: {
394
             tooltip: {
334
               valueFormatter: function (value) {
395
               valueFormatter: function (value) {
336
               }
397
               }
337
             },
398
             },
338
             smooth: true,
399
             smooth: true,
339
-            data: Object.values(this.yearProjectAmount),
400
+            data: Object.values(this.yearSettleProjectAmount),
340
             label: {
401
             label: {
341
               show: true,
402
               show: true,
342
               position: 'top',
403
               position: 'top',
348
               }
409
               }
349
             }
410
             }
350
           },
411
           },
351
-        ]
352
-      };
353
-      ehcartsInit(settleProjectChart, 'settleProject', option);
354
-    },
355
-    initSettleAmountLine() {
356
-      let option = {
357
-        title: {
358
-          text: '各年结算金额',
359
-          subtext: '结算总额:' + Object.values(this.settleAmount).reduce((accumulator, currentValue) => accumulator + currentValue, 0) + '元' +
360
-            '(约' + this.sumSettleAmount + '万元)'
361
-        },
362
-        grid: {
363
-          left: '1%',
364
-          right: '1%',
365
-          bottom: '0%',
366
-          height: '60%',
367
-          containLabel: true
368
-        },
369
-        tooltip: {
370
-          trigger: 'axis',
371
-          axisPointer: {
372
-            type: 'none',
373
-            label: {
374
-              backgroundColor: '#6a7985'
375
-            }
376
-          }
377
-        },
378
-        xAxis: {
379
-          type: 'category',
380
-          data: Object.keys(this.settleAmount),
381
-        },
382
-        yAxis: {
383
-          type: 'value',
384
-          name: '单位:元'
385
-        },
386
-        series: [
387
           {
412
           {
388
-            min: 0,
389
-            data: Object.values(this.settleAmount),
413
+            name: "核算",
390
             type: 'line',
414
             type: 'line',
415
+            tooltip: {
416
+              valueFormatter: function (value) {
417
+                return value + ' 元';
418
+              }
419
+            },
391
             smooth: true,
420
             smooth: true,
421
+            data: Object.values(this.yearCheckProjectAmount),
392
             label: {
422
             label: {
393
               show: true,
423
               show: true,
394
               position: 'top',
424
               position: 'top',
402
           }
432
           }
403
         ]
433
         ]
404
       };
434
       };
405
-      ehcartsInit(settleAmountChart, 'settleLine', option);
406
-    }
435
+      ehcartsInit(settleProjectChart, 'settleProject', option);
436
+    },
407
   },
437
   },
408
 }
438
 }
409
 </script>
439
 </script>

+ 10
- 3
oa-ui/src/views/statistics/index.vue Просмотреть файл

1
 <!--
1
 <!--
2
  * @Author: ysh
2
  * @Author: ysh
3
  * @Date: 2024-10-11 09:23:15
3
  * @Date: 2024-10-11 09:23:15
4
- * @LastEditors: Please set LastEditors
5
- * @LastEditTime: 2024-10-25 09:50:41
4
+ * @LastEditors: wrh
5
+ * @LastEditTime: 2025-12-25 18:31:30
6
 -->
6
 -->
7
 <template>
7
 <template>
8
   <div class="app-container bg">
8
   <div class="app-container bg">
16
       <car-device-statistics v-else-if="isActive == 'device'" :deviceData="deviceInfo"
16
       <car-device-statistics v-else-if="isActive == 'device'" :deviceData="deviceInfo"
17
         :carData="carInfo"></car-device-statistics>
17
         :carData="carInfo"></car-device-statistics>
18
       <borrow-statistics v-else-if="isActive == 'borrow'" :borrowData="borrowInfo"></borrow-statistics>
18
       <borrow-statistics v-else-if="isActive == 'borrow'" :borrowData="borrowInfo"></borrow-statistics>
19
-      <settle-statistics v-else-if="isActive == 'settle'" :settleData="settleInfo"></settle-statistics>
19
+      <settle-statistics v-else-if="isActive == 'settle'" :settleData="settleInfo" :checkData="checkInfo"></settle-statistics>
20
     </div>
20
     </div>
21
   </div>
21
   </div>
22
 </template>
22
 </template>
28
 import { getDeviceStatistic } from '@/api/oa/device/device';
28
 import { getDeviceStatistic } from '@/api/oa/device/device';
29
 import { getBorrowStatistic } from '@/api/oa/borrow/borrow';
29
 import { getBorrowStatistic } from '@/api/oa/borrow/borrow';
30
 import { getSettleStatistic } from '@/api/oa/settle/settle';
30
 import { getSettleStatistic } from '@/api/oa/settle/settle';
31
+import { getCheckStatistic } from '@/api/oa/budget/check';
31
 import ProjectStatistics from './components/projectStatistics.vue';
32
 import ProjectStatistics from './components/projectStatistics.vue';
32
 import contractStatistics from './components/contractStatistics.vue';
33
 import contractStatistics from './components/contractStatistics.vue';
33
 import topHead from './components/topHead.vue';
34
 import topHead from './components/topHead.vue';
45
       deviceInfo: {},
46
       deviceInfo: {},
46
       borrowInfo: {},
47
       borrowInfo: {},
47
       settleInfo:{},
48
       settleInfo:{},
49
+      checkInfo:{},
48
       dataLoading: true,
50
       dataLoading: true,
49
     }
51
     }
50
   },
52
   },
56
     this.getDeviceInfo();
58
     this.getDeviceInfo();
57
     this.getBorrowInfo();
59
     this.getBorrowInfo();
58
     this.getSettleInfo();
60
     this.getSettleInfo();
61
+    this.getCheckInfo();
59
   },
62
   },
60
   mounted() {
63
   mounted() {
61
 
64
 
90
       let res = await getSettleStatistic();
93
       let res = await getSettleStatistic();
91
       this.settleInfo = res.data;
94
       this.settleInfo = res.data;
92
     },
95
     },
96
+    async getCheckInfo(){
97
+      let res = await getCheckStatistic();
98
+      this.checkInfo = res.data;
99
+    },
93
     changeClick(val) {
100
     changeClick(val) {
94
       this.isActive = val
101
       this.isActive = val
95
     }
102
     }

+ 0
- 6
package-lock.json Просмотреть файл

1
-{
2
-  "name": "cmc-oa",
3
-  "lockfileVersion": 3,
4
-  "requires": true,
5
-  "packages": {}
6
-}

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