From 5ceca957811a0da3741cf4957e6f1fcfca807be6 Mon Sep 17 00:00:00 2001
From: wlzboy <66905212@qq.com>
Date: 星期五, 26 十二月 2025 23:42:00 +0800
Subject: [PATCH] feat:增加显示强制完成按钮控制

---
 app/APP配置数据库化说明.md                                                              |  173 ++++++++++++++++++++++++++++
 app/api/appConfig.js                                                            |   21 +++
 app/config.js                                                                   |    6 
 sql/app_config.sql                                                              |    8 +
 app/pagesTask/detail.vue                                                        |    8 +
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java |   66 +++++++++++
 app/App.vue                                                                     |   32 +++++
 7 files changed, 311 insertions(+), 3 deletions(-)

diff --git "a/app/APP\351\205\215\347\275\256\346\225\260\346\215\256\345\272\223\345\214\226\350\257\264\346\230\216.md" "b/app/APP\351\205\215\347\275\256\346\225\260\346\215\256\345\272\223\345\214\226\350\257\264\346\230\216.md"
new file mode 100644
index 0000000..a001dbe
--- /dev/null
+++ "b/app/APP\351\205\215\347\275\256\346\225\260\346\215\256\345\272\223\345\214\226\350\257\264\346\230\216.md"
@@ -0,0 +1,173 @@
+# APP閰嶇疆浠庢暟鎹簱璇诲彇鍔熻兘璇存槑
+
+## 姒傝堪
+
+灏咥PP鐨勫姛鑳藉紑鍏抽厤缃粠鏈湴 `config.js` 鏂囦欢鏀逛负浠庢暟鎹簱鍔ㄦ�佽鍙栵紝瀹炵幇鍚庡彴鍙厤缃寲绠$悊銆�
+
+## 瀹炵幇鍐呭
+
+### 1. 鍚庣瀹炵幇
+
+#### 1.1 鍒涘缓閰嶇疆鎺у埗鍣�
+**鏂囦欢**: `ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java`
+
+鎻愪緵涓や釜鎺ュ彛锛�
+- `GET /app/config/features` - 鑾峰彇鍔熻兘寮�鍏抽厤缃�
+- `GET /app/config/all` - 鑾峰彇瀹屾暣APP閰嶇疆
+
+鐗圭偣锛�
+- 鏃犻渶鏉冮檺鏍¢獙锛屾墍鏈夌櫥褰曠敤鎴烽兘鍙闂�
+- 鑷姩灏嗛厤缃�艰浆鎹负甯冨皵绫诲瀷
+
+#### 1.2 鏁版嵁搴撻厤缃�
+**鏂囦欢**: `sql/app_config.sql`
+
+鎻掑叆涓ゆ潯閰嶇疆璁板綍锛�
+```sql
+-- 灏辩华鎸夐挳閰嶇疆
+config_key: app.feature.showAssigneeReadyButton
+config_value: true/false
+
+-- 寮哄埗瀹屾垚鎸夐挳閰嶇疆
+config_key: app.feature.showForceCompleteButton
+config_value: true/false
+```
+
+### 2. 鍓嶇瀹炵幇
+
+#### 2.1 API鎺ュ彛鏂囦欢
+**鏂囦欢**: `app/api/appConfig.js`
+
+灏佽閰嶇疆鑾峰彇鎺ュ彛锛�
+- `getAppFeatures()` - 鑾峰彇鍔熻兘寮�鍏�
+- `getAppConfig()` - 鑾峰彇瀹屾暣閰嶇疆
+
+#### 2.2 搴旂敤鍚姩鍔犺浇
+**鏂囦欢**: `app/App.vue`
+
+淇敼閰嶇疆鍔犺浇閫昏緫锛�
+1. **搴旂敤鍚姩鏃�**锛�
+   - 鍏堜娇鐢ㄦ湰鍦伴粯璁ら厤缃紙config.js锛�
+   - 濡傛灉宸茬櫥褰曪紝浠庢湇鍔″櫒鍔犺浇閰嶇疆骞惰鐩栨湰鍦伴厤缃�
+   
+2. **鐢ㄦ埛鐧诲綍鍚�**锛�
+   - 鐩戝惉 `user-login` 浜嬩欢
+   - 鑷姩浠庢湇鍔″櫒鍔犺浇鏈�鏂伴厤缃�
+
+3. **閰嶇疆鍚堝苟绛栫暐**锛�
+   - 鏈嶅姟鍣ㄩ厤缃紭鍏堢骇楂樹簬鏈湴閰嶇疆
+   - 鏈湴閰嶇疆浣滀负榛樿鍊硷紙缃戠粶澶辫触鏃朵娇鐢級
+
+#### 2.3 鏈湴閰嶇疆淇濈暀
+**鏂囦欢**: `app/config.js`
+
+淇濈暀 features 閰嶇疆浣滀负榛樿鍊硷細
+```javascript
+features: {
+  showAssigneeReadyButton: true,
+  showForceCompleteButton: true
+}
+```
+
+### 3. 閰嶇疆椤硅鏄�
+
+| 閰嶇疆閿� | 璇存槑 | 鍙�夊�� | 榛樿鍊� |
+|-------|------|--------|--------|
+| app.feature.showAssigneeReadyButton | 鏄惁鏄剧ず鎵ц浜哄氨缁寜閽� | true/false | true |
+| app.feature.showForceCompleteButton | 鏄惁鏄剧ず寮哄埗瀹屾垚鎸夐挳 | true/false | true |
+
+## 浣跨敤鏂瑰紡
+
+### 鍚庡彴閰嶇疆
+
+1. **閫氳繃鍚庡彴绠$悊鐣岄潰**锛�
+   - 鐧诲綍鍚庡彴绠$悊绯荤粺
+   - 杩涘叆銆愮郴缁熺鐞嗐��->銆愬弬鏁拌缃��
+   - 鎼滅储 "APP-鏄剧ず" 鎵惧埌鐩稿叧閰嶇疆
+   - 淇敼 config_value 涓� `true` 鎴� `false`
+
+2. **鐩存帴淇敼鏁版嵁搴�**锛�
+```sql
+-- 闅愯棌寮哄埗瀹屾垚鎸夐挳
+UPDATE sys_config 
+SET config_value = 'false' 
+WHERE config_key = 'app.feature.showForceCompleteButton';
+
+-- 鏄剧ず寮哄埗瀹屾垚鎸夐挳
+UPDATE sys_config 
+SET config_value = 'true' 
+WHERE config_key = 'app.feature.showForceCompleteButton';
+```
+
+### APP鐢熸晥鏃舵満
+
+閰嶇疆淇敼鍚庯紝APP鍦ㄤ互涓嬫儏鍐典細鑾峰彇鏈�鏂伴厤缃細
+1. 鐢ㄦ埛閲嶆柊鐧诲綍
+2. 搴旂敤閲嶆柊鍚姩
+3. 浠庡悗鍙板垏鎹㈠洖鍓嶅彴锛堝鏋滃凡鐧诲綍锛�
+
+## 閰嶇疆浼樺厛绾�
+
+```
+鏈嶅姟鍣ㄩ厤缃� > 鏈湴榛樿閰嶇疆
+```
+
+- **鏈嶅姟鍣ㄩ厤缃彲鐢ㄦ椂**锛氫娇鐢ㄦ暟鎹簱涓殑閰嶇疆
+- **鏈嶅姟鍣ㄩ厤缃姞杞藉け璐�**锛氫娇鐢� config.js 涓殑榛樿閰嶇疆
+- **鐢ㄦ埛鏈櫥褰�**锛氫娇鐢� config.js 涓殑榛樿閰嶇疆
+
+## 鎵╁睍璇存槑
+
+### 娣诲姞鏂扮殑閰嶇疆椤�
+
+1. **鏁版嵁搴撴坊鍔犻厤缃�**锛�
+```sql
+INSERT INTO sys_config (config_name, config_key, config_value, config_type, create_by, create_time, remark) 
+VALUES ('APP-鏂板姛鑳藉紑鍏�', 'app.feature.newFeature', 'true', 'N', 'admin', sysdate(), '鏂板姛鑳藉紑鍏宠鏄�');
+```
+
+2. **鍚庣娣诲姞璇诲彇閫昏緫**锛�
+```java
+// AppConfigController.java
+String newFeature = configService.selectConfigByKey("app.feature.newFeature");
+features.put("newFeature", "true".equalsIgnoreCase(newFeature));
+```
+
+3. **鍓嶇config.js娣诲姞榛樿鍊�**锛�
+```javascript
+features: {
+  showAssigneeReadyButton: true,
+  showForceCompleteButton: true,
+  newFeature: true  // 鏂板
+}
+```
+
+4. **椤甸潰浣跨敤閰嶇疆**锛�
+```javascript
+// 鍦� methods 涓坊鍔犲垽鏂柟娉�
+showNewFeature() {
+  return !!(config && config.features && config.features.newFeature)
+}
+
+// 鍦ㄦā鏉夸腑浣跨敤
+<button v-if="showNewFeature()">鏂板姛鑳芥寜閽�</button>
+```
+
+## 娉ㄦ剰浜嬮」
+
+1. **閰嶇疆缂撳瓨**锛氳嫢渚濇鏋跺 sys_config 琛ㄦ湁缂撳瓨鏈哄埗锛屼慨鏀归厤缃悗鍙兘闇�瑕佸埛鏂扮紦瀛�
+2. **閰嶇疆鏍煎紡**锛歝onfig_value 鍙敮鎸佸瓧绗︿覆锛屽悗绔細杞崲涓哄竷灏斿��
+3. **鍏煎鎬�**锛氫繚鐣欐湰鍦伴粯璁ら厤缃‘淇濈綉缁滃紓甯告椂鍔熻兘鍙敤
+4. **瀹夊叏鎬�**锛氶厤缃帴鍙f棤闇�鏉冮檺锛岀‘淇濅笉鏆撮湶鏁忔劅淇℃伅
+
+## 鐩稿叧鏂囦欢娓呭崟
+
+### 鍚庣
+- `ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java` - 閰嶇疆鎺у埗鍣�
+- `sql/app_config.sql` - 閰嶇疆鏁版嵁SQL
+
+### 鍓嶇
+- `app/api/appConfig.js` - API鎺ュ彛
+- `app/App.vue` - 搴旂敤鍚姩閰嶇疆鍔犺浇
+- `app/config.js` - 鏈湴榛樿閰嶇疆
+- `app/pagesTask/detail.vue` - 浠诲姟璇︽儏椤碉紙浣跨敤閰嶇疆锛�
diff --git a/app/App.vue b/app/App.vue
index f74c66c..d5b65a7 100644
--- a/app/App.vue
+++ b/app/App.vue
@@ -5,6 +5,7 @@
   import { getUnreadCount } from '@/api/message'
   import storage from '@/utils/storage'
   import { redirectToLoginByEnvironment } from '@/utils/wechat'
+  import { getAppFeatures } from '@/api/appConfig'
 
   export default {
     data() {
@@ -29,6 +30,8 @@
           this.lastToken = token
           this.updateUnreadMessageBadge()
           // this.startMessagePolling()
+          // 鍔犺浇鏈嶅姟鍣ㄩ厤缃�
+          this.loadServerConfig()
         }
       })
       
@@ -91,8 +94,37 @@
         // 娉ㄦ剰锛氫笉鍦ㄥ簲鐢ㄥ惎鍔ㄦ椂鑷姩鍚姩杞
         // 鍙湁鍦ㄧ敤鎴蜂富鍔ㄧ櫥褰曟垚鍔熷悗鎵嶅惎鍔紙閫氳繃 user-login 浜嬩欢瑙﹀彂锛�
       },
+      
+      // 鍒濆鍖栭厤缃細鍚堝苟鏈湴閰嶇疆鍜屾湇鍔″櫒閰嶇疆
       initConfig() {
+        // 鍏堜娇鐢ㄦ湰鍦伴粯璁ら厤缃�
         this.globalData.config = config
+        
+        // 濡傛灉鐢ㄦ埛宸茬櫥褰曪紝灏濊瘯鍔犺浇鏈嶅姟鍣ㄩ厤缃�
+        if (getToken()) {
+          this.loadServerConfig()
+        } else {
+          console.log('鐢ㄦ埛鏈櫥褰曪紝浣跨敤鏈湴榛樿閰嶇疆')
+        }
+      },
+      
+      // 浠庢湇鍔″櫒鍔犺浇閰嶇疆
+      loadServerConfig() {
+        getAppFeatures().then(response => {
+          console.log('鍔犺浇鏈嶅姟鍣ㄩ厤缃垚鍔�:', response.data)
+          // 鍚堝苟閰嶇疆锛氭湇鍔″櫒閰嶇疆瑕嗙洊鏈湴閰嶇疆
+          if (response.data) {
+            this.globalData.config.features = Object.assign({}, 
+              this.globalData.config.features || {}, 
+              response.data
+            )
+            // 鏇存柊鍏ㄥ眬config瀵硅薄锛岀‘淇濆叾浠栧湴鏂逛篃鑳借幏鍙栧埌鏈�鏂伴厤缃�
+            config.features = this.globalData.config.features
+          }
+        }).catch(error => {
+          console.error('鍔犺浇鏈嶅姟鍣ㄩ厤缃け璐�:', error)
+          console.log('浣跨敤鏈湴榛樿閰嶇疆')
+        })
       },
       // 妫�鏌ョ櫥褰曠姸鎬佸苟鑷姩璺宠浆鍒板悎閫傜殑鐧诲綍椤甸潰
       checkLoginAndRedirect(options) {
diff --git a/app/api/appConfig.js b/app/api/appConfig.js
new file mode 100644
index 0000000..d3997da
--- /dev/null
+++ b/app/api/appConfig.js
@@ -0,0 +1,21 @@
+import request from '@/utils/request'
+
+/**
+ * 鑾峰彇APP鍔熻兘寮�鍏抽厤缃�
+ */
+export function getAppFeatures() {
+  return request({
+    url: '/app/config/features',
+    method: 'get'
+  })
+}
+
+/**
+ * 鑾峰彇瀹屾暣鐨凙PP閰嶇疆
+ */
+export function getAppConfig() {
+  return request({
+    url: '/app/config/all',
+    method: 'get'
+  })
+}
diff --git a/app/config.js b/app/config.js
index b122f66..90f3f3e 100644
--- a/app/config.js
+++ b/app/config.js
@@ -63,7 +63,9 @@
   
   // 鍔熻兘寮�鍏�
   features: {
-    // 鏄惁鏄剧ず鎵ц浜衡�滃氨缁�濇寜閽�
-    showAssigneeReadyButton: true
+    // 鏄惁鏄剧ず鎵ц浜�"灏辩华"鎸夐挳
+    showAssigneeReadyButton: true,
+    // 鏄惁鏄剧ず"寮哄埗瀹屾垚"鎸夐挳
+    showForceCompleteButton: true
   }
 }
diff --git a/app/pagesTask/detail.vue b/app/pagesTask/detail.vue
index 375ace9..9077526 100644
--- a/app/pagesTask/detail.vue
+++ b/app/pagesTask/detail.vue
@@ -470,6 +470,7 @@
             鍙栨秷
           </button>
           <button 
+            v-if="showForceCompleteFeature() && taskDetail.taskStatus === 'PENDING'"
             class="action-btn force-complete" 
             @click="showForceCompleteTimeDialog()"
           >
@@ -1421,10 +1422,15 @@
         console.log('闄勪欢鍒犻櫎鎴愬姛:', attachmentId)
       },
 
-      // 鏄惁鏄剧ず鈥滃氨缁�濆姛鑳斤紙閰嶇疆寮�鍏筹級
+      // 鏄惁鏄剧ず"灏辩华"鍔熻兘锛堥厤缃紑鍏筹級
       showAssigneeReadyFeature() {
         return !!(config && config.features && config.features.showAssigneeReadyButton)
       },
+            
+      // 鏄惁鏄剧ず"寮哄埗瀹屾垚"鍔熻兘锛堥厤缃紑鍏筹級
+      showForceCompleteFeature() {
+        return !!(config && config.features && config.features.showForceCompleteButton)
+      },
 
       // 褰撳墠鐢ㄦ埛鏄惁涓鸿鎵ц浜�
       isAssigneeSelf(assignee) {
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java
new file mode 100644
index 0000000..2aba18e
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/app/AppConfigController.java
@@ -0,0 +1,66 @@
+package com.ruoyi.web.controller.app;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.system.service.ISysConfigService;
+
+/**
+ * APP閰嶇疆鎺у埗鍣�
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/app/config")
+public class AppConfigController extends BaseController
+{
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 鑾峰彇APP鍔熻兘寮�鍏抽厤缃�
+     * 涓嶉渶瑕佹潈闄愭牎楠岋紝鎵�鏈夌櫥褰曠敤鎴烽兘鍙互璁块棶
+     */
+    @GetMapping("/features")
+    public AjaxResult getFeatures()
+    {
+        Map<String, Object> features = new HashMap<>();
+        
+        // 璇诲彇灏辩华鎸夐挳閰嶇疆
+        String showAssigneeReadyButton = configService.selectConfigByKey("app.feature.showAssigneeReadyButton");
+        features.put("showAssigneeReadyButton", "true".equalsIgnoreCase(showAssigneeReadyButton));
+        
+        // 璇诲彇寮哄埗瀹屾垚鎸夐挳閰嶇疆
+        String showForceCompleteButton = configService.selectConfigByKey("app.feature.showForceCompleteButton");
+        features.put("showForceCompleteButton", "true".equalsIgnoreCase(showForceCompleteButton));
+        
+        return success(features);
+    }
+    
+    /**
+     * 鑾峰彇瀹屾暣鐨凙PP閰嶇疆
+     * 鍖呮嫭baseUrl銆乤ppInfo銆乫eatures绛�
+     */
+    @GetMapping("/all")
+    public AjaxResult getAllConfig()
+    {
+        Map<String, Object> config = new HashMap<>();
+        
+        // 鍔熻兘寮�鍏抽厤缃�
+        Map<String, Object> features = new HashMap<>();
+        String showAssigneeReadyButton = configService.selectConfigByKey("app.feature.showAssigneeReadyButton");
+        features.put("showAssigneeReadyButton", "true".equalsIgnoreCase(showAssigneeReadyButton));
+        
+        String showForceCompleteButton = configService.selectConfigByKey("app.feature.showForceCompleteButton");
+        features.put("showForceCompleteButton", "true".equalsIgnoreCase(showForceCompleteButton));
+        
+        config.put("features", features);
+        
+        return success(config);
+    }
+}
diff --git a/sql/app_config.sql b/sql/app_config.sql
new file mode 100644
index 0000000..d0155d3
--- /dev/null
+++ b/sql/app_config.sql
@@ -0,0 +1,8 @@
+-- APP鍔熻兘寮�鍏抽厤缃�
+-- 鎻掑叆灏辩华鎸夐挳閰嶇疆
+INSERT INTO sys_config (config_name, config_key, config_value, config_type, create_by, create_time, remark) 
+VALUES ('APP-鏄剧ず鎵ц浜哄氨缁寜閽�', 'app.feature.showAssigneeReadyButton', 'true', 'N', 'admin', sysdate(), '鎺у埗APP浠诲姟璇︽儏椤垫槸鍚︽樉绀烘墽琛屼汉灏辩华鎸夐挳锛坱rue鏄剧ず锛宖alse闅愯棌锛�');
+
+-- 鎻掑叆寮哄埗瀹屾垚鎸夐挳閰嶇疆
+INSERT INTO sys_config (config_name, config_key, config_value, config_type, create_by, create_time, remark) 
+VALUES ('APP-鏄剧ず寮哄埗瀹屾垚鎸夐挳', 'app.feature.showForceCompleteButton', 'true', 'N', 'admin', sysdate(), '鎺у埗APP浠诲姟璇︽儏椤垫槸鍚︽樉绀哄己鍒跺畬鎴愭寜閽紙true鏄剧ず锛宖alse闅愯棌锛�');

--
Gitblit v1.9.1