From b051f008e007a335948cd8f3b78c1f7629a4d6ac Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期一, 31 八月 2026 13:00:05 +0800
Subject: [PATCH] fix: 菜单高亮间歇性失效根因(el-menu 同路由导航回滚 activeIndex)——default-active 绑定路由+select 后宏任务纠正;feat: 修改密码(用户自改)+ admin 重置他人密码为 123456

---
 traffic-audit-web/src/views/Dashboard.vue                                                    |    2 
 traffic-audit-web/src/views/ReportExport.vue                                                 |    3 
 traffic-audit-web/src/views/DataImport.vue                                                   |    2 
 traffic-audit-server/src/main/java/com/trafficaudit/security/controller/LoginController.java |   39 +++++++++
 traffic-audit-server/src/main/java/com/trafficaudit/system/controller/UserController.java    |   31 +++++++
 traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java             |   12 +++
 traffic-audit-web/src/components/AppHeader.vue                                               |   76 ++++++++++++++++++
 traffic-audit-web/src/views/ExplainReview.vue                                                |    2 
 HANDOFF.md                                                                                   |    6 +
 traffic-audit-web/src/views/RuleManage.vue                                                   |    2 
 traffic-audit-web/src/main.js                                                                |    8 ++
 traffic-audit-web/src/views/DataView.vue                                                     |    2 
 traffic-audit-web/src/views/UserManage.vue                                                   |   15 +++
 traffic-audit-web/src/views/AuditResult.vue                                                  |    2 
 14 files changed, 191 insertions(+), 11 deletions(-)

diff --git a/HANDOFF.md b/HANDOFF.md
index d49a104..ef3069e 100644
--- a/HANDOFF.md
+++ b/HANDOFF.md
@@ -92,6 +92,12 @@
   sys_user 宸插姞 modules 鍒楋紱admin 瀵嗙爜宸查噸缃负 BCrypt锛坅dmin/admin123锛夈��
 - 鏃犲凡鐭ラ樆濉炴�ч棶棰樸��
 
+### 6. 08-31锛氳彍鍗曢珮浜棿姝囨�ф牴鍥犱慨澶嶏紙瀹為敜锛�+ 淇敼瀵嗙爜鍔熻兘锛堝凡瀹屾垚骞堕獙璇侊級
+- **鑿滃崟楂樹寒鏍瑰洜瀹為敜**锛氫笉鏄� el-tabs 閬楃暀闂锛岃�屾槸 Element UI `el-menu` 鐨� `handleItemClick` 鍦�**鍚岃矾鐢卞鑸�**锛坴ue-router NavigationDuplicated锛夋椂锛宍routeToItem` 鐨� onError 鍥炶皟鎶� `activeIndex` 鎭㈠涓虹偣鍑诲墠鏃у�硷紙鍏跺彧鎺掗櫎浜� push 鎶涘紓甯歌矾寰勶紝鏈帓闄ゅ悓璺敱鍥炶皟璺緞锛夈�傝Е鍙戝満鏅細涓婁竴娆¤彍鍗曞鑸湭瀹屾垚鏃跺揩閫熺偣鍙︿竴涓彍鍗曪紙濡傘�屾暟鎹鍏ャ�嶆湭鍒囧畬灏辩偣銆屽鏍哥粨鏋溿�嶏級鈫� 椤甸潰宸叉槸鐩爣椤典絾楂樹寒鍋滅暀鍦ㄦ棫鑿滃崟锛�**闂存瓏鎬с�佹椂濂芥椂鍧�**锛堝鐜帮細puppeteer 蹇�熻繛鐐癸紝puppeteer 鐢� node24锛歚C:\Users\jcxiong\.cache\codex-runtimes\codex-primary-runtime\dependencies\node\bin\node.exe`锛夈��
+- **淇**锛�8 涓〉闈� el-menu 缁熶竴鏀逛负 `ref="sideMenu"` + `:default-active="$route.path"` + `@select="onMenuSelect"`锛沗onMenuSelect` 鍔犲湪 main.js 鍏ㄥ眬 mixin锛坰etTimeout 瀹忎换鍔″己鍒剁籂姝� activeIndex锛屽畯浠诲姟鏅氫簬 push 鐨勫井浠诲姟 onError 鍥炶皟锛屼繚璇佹渶缁堥珮浜纭級銆傞獙璇侊細6 杞�3 鍦烘櫙锛堥『搴忕偣/蹇�熻繛鐐�/鍚岃矾鐢卞線杩旓級鍏ㄩ儴楂樹寒姝g‘銆�
+- **淇敼瀵嗙爜**锛氬悗绔� `POST /api/auth/change-password`锛堢敤鎴锋敼鑷繁瀵嗙爜锛岄渶鏃у瘑鐮佹牎楠屻�佹柊瀵嗙爜鈮�6浣嶃�佹柊鏃т笉鍚岋級+ `POST /api/user/reset-password`锛堜粎 admin锛岄噸缃粬浜轰负 123456锛宎dmin 鑷韩绂佹閲嶇疆锛夛紱JwtUtils 鏂板 `resolveUsername(Authorization澶�)`銆傚墠绔� AppHeader 鍏叡椤舵爮鍔犮�屼慨鏀瑰瘑鐮併�嶅脊绐楋紙鏃�/鏂�/纭锛夛紝UserManage 鎿嶄綔鍒楀姞銆岄噸缃瘑鐮併�嶆寜閽紙`isAdmin` 鎺у埗鏄剧ず锛岄潪 admin 闅愯棌+鍚庣 403 鍙屼繚闄╋級銆侫PI 涓� UI锛坅dmin/闈瀉dmin 鍙岃瑙掞級鍧囧凡楠岃瘉锛�**娴嬭瘯鍚庢暟鎹簱瀵嗙爜宸叉仮澶嶅師鐘�**锛坅dmin/admin123 鏈夋晥锛宑henzj 绛夊師 hash 鏈彉锛夈��
+- 娴嬭瘯鑴氭湰锛歚D:\Codex\_tools\pptr-core\menu_audit_rounds.js`锛堥珮浜洖褰掞級銆乣pwd_ui_test.js`锛堟敼瀵� UI锛夈��
+
 ## 浜屻�佸揩閫熷惎鍔�
 缁熶竴鐢ㄤ竴閿剼鏈紙蹇呴』娌欑澶�/鎻愭潈杩愯锛夛細
 ```
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/security/controller/LoginController.java b/traffic-audit-server/src/main/java/com/trafficaudit/security/controller/LoginController.java
index 212fd36..18572ae 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/security/controller/LoginController.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/security/controller/LoginController.java
@@ -83,6 +83,45 @@
         return Result.ok(data);
     }
 
+    /** 鐢ㄦ埛淇敼鑷繁鐨勫瘑鐮侊細闇�鎻愪緵鍘熷瘑鐮侊紝鏂板瘑鐮佽嚦灏� 6 浣� */
+    @PostMapping("/change-password")
+    public Result<Void> changePassword(@RequestHeader(value = "Authorization", required = false) String auth,
+                                       @RequestBody Map<String, Object> params) {
+        String username = jwtUtils.resolveUsername(auth);
+        if (username == null) {
+            return Result.error(401, "鏈櫥褰曟垨鐧诲綍宸茶繃鏈�");
+        }
+        String oldPassword = (String) params.get("oldPassword");
+        String newPassword = (String) params.get("newPassword");
+        if (oldPassword == null || oldPassword.isEmpty()) {
+            return Result.error(400, "璇疯緭鍏ュ師瀵嗙爜");
+        }
+        if (newPassword == null || newPassword.length() < 6) {
+            return Result.error(400, "鏂板瘑鐮侀暱搴︿笉鑳藉皯浜� 6 浣�");
+        }
+        if (newPassword.equals(oldPassword)) {
+            return Result.error(400, "鏂板瘑鐮佷笉鑳戒笌鍘熷瘑鐮佺浉鍚�");
+        }
+        User user = userMapper.selectOne(new LambdaQueryWrapper<User>().eq(User::getUsername, username));
+        if (user == null) {
+            return Result.error(404, "鐢ㄦ埛涓嶅瓨鍦�");
+        }
+        String encoded = user.getPassword();
+        boolean ok;
+        try {
+            ok = encoded != null && passwordEncoder.matches(oldPassword, encoded);
+        } catch (IllegalArgumentException e) {
+            // 搴撲腑瀵嗙爜涓嶆槸鍚堟硶 BCrypt 鏃跺洖閫�涓烘槑鏂囧姣旓紙涓庣櫥褰曚竴鑷达級
+            ok = encoded != null && encoded.equals(oldPassword);
+        }
+        if (!ok) {
+            return Result.error(400, "鍘熷瘑鐮侀敊璇�");
+        }
+        user.setPassword(passwordEncoder.encode(newPassword));
+        userMapper.updateById(user);
+        return Result.ok(null);
+    }
+
     @GetMapping("/captcha-config")
     public Result<Map<String, Object>> captchaConfig() {
         Map<String, Object> data = new HashMap<>();
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java b/traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java
index 1941595..1b8baa2 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/security/utils/JwtUtils.java
@@ -45,4 +45,16 @@
             return false;
         }
     }
+
+    /** 浠� Authorization: Bearer xxx 璇锋眰澶磋В鏋愮敤鎴峰悕锛涙棤鏁堣繑鍥� null */
+    public String resolveUsername(String authorizationHeader) {
+        if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) {
+            return null;
+        }
+        try {
+            return getUsernameFromToken(authorizationHeader.substring(7));
+        } catch (Exception e) {
+            return null;
+        }
+    }
 }
diff --git a/traffic-audit-server/src/main/java/com/trafficaudit/system/controller/UserController.java b/traffic-audit-server/src/main/java/com/trafficaudit/system/controller/UserController.java
index d44adf3..4983ebf 100644
--- a/traffic-audit-server/src/main/java/com/trafficaudit/system/controller/UserController.java
+++ b/traffic-audit-server/src/main/java/com/trafficaudit/system/controller/UserController.java
@@ -2,6 +2,7 @@
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.trafficaudit.common.Result;
+import com.trafficaudit.security.utils.JwtUtils;
 import com.trafficaudit.system.entity.User;
 import com.trafficaudit.system.mapper.UserMapper;
 import org.springframework.security.crypto.password.PasswordEncoder;
@@ -22,6 +23,8 @@
     private UserMapper userMapper;
     @Resource
     private PasswordEncoder passwordEncoder;
+    @Resource
+    private JwtUtils jwtUtils;
 
     @GetMapping("/list")
     public Result<List<Map<String, Object>>> list(@RequestParam(value = "keyword", required = false) String keyword) {
@@ -92,6 +95,34 @@
         return Result.ok(null);
     }
 
+    /** admin 閲嶇疆浠栦汉瀵嗙爜涓� 123456 */
+    @PostMapping("/reset-password")
+    public Result<Void> resetPassword(@RequestHeader(value = "Authorization", required = false) String auth,
+                                      @RequestBody Map<String, Object> params) {
+        String operator = jwtUtils.resolveUsername(auth);
+        if (operator == null) {
+            return Result.error(401, "鏈櫥褰曟垨鐧诲綍宸茶繃鏈�");
+        }
+        if (!"admin".equals(operator)) {
+            return Result.error(403, "浠� admin 鍙互閲嶇疆鍏朵粬鐢ㄦ埛瀵嗙爜");
+        }
+        Object idObj = params.get("id");
+        if (idObj == null) {
+            return Result.error(400, "缂哄皯鐢ㄦ埛 id");
+        }
+        Long id = Long.valueOf(idObj.toString());
+        User u = userMapper.selectById(id);
+        if (u == null) {
+            return Result.error(404, "鐢ㄦ埛涓嶅瓨鍦�");
+        }
+        if ("admin".equals(u.getUsername())) {
+            return Result.error(400, "admin 瀵嗙爜涓嶅厑璁搁噸缃�");
+        }
+        u.setPassword(passwordEncoder.encode("123456"));
+        userMapper.updateById(u);
+        return Result.ok(null);
+    }
+
     @PostMapping("/delete")
     public Result<Void> delete(@RequestParam("id") Long id) {
         User u = userMapper.selectById(id);
diff --git a/traffic-audit-web/src/components/AppHeader.vue b/traffic-audit-web/src/components/AppHeader.vue
index f4e1b04..aeec948 100644
--- a/traffic-audit-web/src/components/AppHeader.vue
+++ b/traffic-audit-web/src/components/AppHeader.vue
@@ -5,18 +5,62 @@
       <span class="header-user">
         <i class="el-icon-user"></i> {{ username }}
       </span>
+      <el-button type="text" class="header-link" @click="openChangePwd">
+        <i class="el-icon-key"></i> 淇敼瀵嗙爜
+      </el-button>
       <el-button type="text" class="header-logout" @click="logout">
         <i class="el-icon-switch-button"></i> 閫�鍑虹櫥褰�
       </el-button>
     </div>
+
+    <el-dialog title="淇敼瀵嗙爜" :visible.sync="pwdDialogVisible" width="420px" @closed="resetPwdForm">
+      <el-form ref="pwdForm" :model="pwdForm" :rules="pwdRules" label-width="90px">
+        <el-form-item label="鍘熷瘑鐮�" prop="oldPassword">
+          <el-input v-model="pwdForm.oldPassword" type="password" show-password placeholder="璇疯緭鍏ュ師瀵嗙爜"></el-input>
+        </el-form-item>
+        <el-form-item label="鏂板瘑鐮�" prop="newPassword">
+          <el-input v-model="pwdForm.newPassword" type="password" show-password placeholder="鑷冲皯 6 浣�"></el-input>
+        </el-form-item>
+        <el-form-item label="纭鏂板瘑鐮�" prop="confirmPassword">
+          <el-input v-model="pwdForm.confirmPassword" type="password" show-password placeholder="鍐嶆杈撳叆鏂板瘑鐮�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer">
+        <el-button @click="pwdDialogVisible = false">鍙栨秷</el-button>
+        <el-button type="primary" :loading="pwdSaving" @click="submitPwd">淇濆瓨</el-button>
+      </div>
+    </el-dialog>
   </el-header>
 </template>
 
 <script>
+import api from '@/api'
+
 export default {
   name: 'AppHeader',
   props: {
     title: { type: String, required: true }
+  },
+  data() {
+    return {
+      pwdDialogVisible: false,
+      pwdSaving: false,
+      pwdForm: { oldPassword: '', newPassword: '', confirmPassword: '' },
+      pwdRules: {
+        oldPassword: [{ required: true, message: '璇疯緭鍏ュ師瀵嗙爜', trigger: 'blur' }],
+        newPassword: [
+          { required: true, message: '璇疯緭鍏ユ柊瀵嗙爜', trigger: 'blur' },
+          { min: 6, message: '鏂板瘑鐮侀暱搴︿笉鑳藉皯浜� 6 浣�', trigger: 'blur' }
+        ],
+        confirmPassword: [
+          { required: true, message: '璇峰啀娆¤緭鍏ユ柊瀵嗙爜', trigger: 'blur' },
+          {
+            validator: (rule, value, cb) => (value === this.pwdForm.newPassword ? cb() : cb(new Error('涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�'))),
+            trigger: 'blur'
+          }
+        ]
+      }
+    }
   },
   computed: {
     username() {
@@ -24,6 +68,34 @@
     }
   },
   methods: {
+    openChangePwd() {
+      this.pwdForm = { oldPassword: '', newPassword: '', confirmPassword: '' }
+      this.pwdDialogVisible = true
+      this.$nextTick(() => this.$refs.pwdForm && this.$refs.pwdForm.clearValidate())
+    },
+    resetPwdForm() {
+      this.$refs.pwdForm && this.$refs.pwdForm.clearValidate()
+    },
+    submitPwd() {
+      this.$refs.pwdForm.validate(valid => {
+        if (!valid) return
+        this.pwdSaving = true
+        api.post('/auth/change-password', {
+          oldPassword: this.pwdForm.oldPassword,
+          newPassword: this.pwdForm.newPassword
+        })
+          .then(() => {
+            this.$message.success('瀵嗙爜淇敼鎴愬姛')
+            this.pwdDialogVisible = false
+          })
+          .catch(err => {
+            if (err && err._toast) return
+            const d = err && err.response && err.response.data
+            this.$message.error((d && d.message) || '瀵嗙爜淇敼澶辫触')
+          })
+          .finally(() => { this.pwdSaving = false })
+      })
+    },
     logout() {
       this.$confirm('纭畾閫�鍑虹櫥褰曞悧锛�', '鎻愮ず', {
         confirmButtonText: '閫�鍑�',
@@ -62,6 +134,8 @@
   line-height: normal;
 }
 .header-user { opacity: 0.92; }
+.header-link { color: #fff; font-size: 14px; padding: 0; }
+.header-link:hover { color: #ffd04b; }
 .header-logout { color: #fff; font-size: 14px; padding: 0; }
 .header-logout:hover { color: #ffd04b; }
-</style>
\ No newline at end of file
+</style>
diff --git a/traffic-audit-web/src/main.js b/traffic-audit-web/src/main.js
index 7aea668..44e467e 100644
--- a/traffic-audit-web/src/main.js
+++ b/traffic-audit-web/src/main.js
@@ -10,6 +10,14 @@
 // 鍏ㄥ眬鐧诲嚭锛氭竻闄ょ櫥褰曟�佸苟鍥炵櫥褰曢〉锛堝悇椤甸潰渚ц竟鏍忋�岄��鍑虹櫥褰曘�嶈彍鍗曞叡鐢級
 Vue.mixin({
   methods: {
+    // el-menu 鍚岃矾鐢卞鑸紙NavigationDuplicated锛夋椂 Element UI 浼氭妸楂樹寒鍥炴粴涓虹偣鍑诲墠鏃у�硷紱
+    // 鐐瑰嚮鍚庡欢杩熶竴涓畯浠诲姟寮哄埗绾犳锛堝畯浠诲姟鏅氫簬 push 鐨勫井浠诲姟鍥炶皟锛屼繚璇佹渶缁堥珮浜纭級銆�
+    onMenuSelect(index) {
+      setTimeout(() => {
+        const menu = this.$refs.sideMenu
+        if (menu && menu.activeIndex !== index) menu.activeIndex = index
+      }, 0)
+    },
     logout() {
       sessionStorage.removeItem('token')
       sessionStorage.removeItem('username')
diff --git a/traffic-audit-web/src/views/AuditResult.vue b/traffic-audit-web/src/views/AuditResult.vue
index 9f19f80..fb821eb 100644
--- a/traffic-audit-web/src/views/AuditResult.vue
+++ b/traffic-audit-web/src/views/AuditResult.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 瀹℃牳缁撴灉"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/audit">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/Dashboard.vue b/traffic-audit-web/src/views/Dashboard.vue
index 8e72c44..ea88d0e 100644
--- a/traffic-audit-web/src/views/Dashboard.vue
+++ b/traffic-audit-web/src/views/Dashboard.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 宸ヤ綔鍙�"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/dashboard">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/DataImport.vue b/traffic-audit-web/src/views/DataImport.vue
index 40a4c6f..3eee788 100644
--- a/traffic-audit-web/src/views/DataImport.vue
+++ b/traffic-audit-web/src/views/DataImport.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 鏁版嵁瀵煎叆"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/import">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/DataView.vue b/traffic-audit-web/src/views/DataView.vue
index 6084401..875f9ab 100644
--- a/traffic-audit-web/src/views/DataView.vue
+++ b/traffic-audit-web/src/views/DataView.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 鏁版嵁鏌ョ湅"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/data">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/ExplainReview.vue b/traffic-audit-web/src/views/ExplainReview.vue
index 8e7bcd9..f622ecc 100644
--- a/traffic-audit-web/src/views/ExplainReview.vue
+++ b/traffic-audit-web/src/views/ExplainReview.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 浼佷笟瑙i噴"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/explain">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/ReportExport.vue b/traffic-audit-web/src/views/ReportExport.vue
index 4619e2f..ba187d1 100644
--- a/traffic-audit-web/src/views/ReportExport.vue
+++ b/traffic-audit-web/src/views/ReportExport.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 鎶ヨ〃鐢熸垚"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router :default-active="activeMenu">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
@@ -154,7 +154,6 @@
   data() {
     return {
       loading: '',
-      activeMenu: '/report',
       activeKey: '',
       updatedAt: '',
       // 鏌ヨ鏉′欢锛歝ycle 鍛ㄦ湡锛坢onth 鏈堟姤 / quarter 瀛f姤 / year 骞存姤锛夛紝period 鎶ヨ〃鏈燂紙鏈堜唤 yyyy-MM 鎴栧勾浠� yyyy锛�
diff --git a/traffic-audit-web/src/views/RuleManage.vue b/traffic-audit-web/src/views/RuleManage.vue
index ed091d7..260f61c 100644
--- a/traffic-audit-web/src/views/RuleManage.vue
+++ b/traffic-audit-web/src/views/RuleManage.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 瑙勫垯绠$悊"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router default-active="/rules">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
diff --git a/traffic-audit-web/src/views/UserManage.vue b/traffic-audit-web/src/views/UserManage.vue
index 93694d5..4c2651a 100644
--- a/traffic-audit-web/src/views/UserManage.vue
+++ b/traffic-audit-web/src/views/UserManage.vue
@@ -3,7 +3,7 @@
     <app-header title="浜ら�氱粺璁℃姤琛ㄥ鏍哥郴缁� - 鐢ㄦ埛绠$悊"></app-header>
     <el-container>
       <el-aside width="200px">
-        <el-menu router :default-active="activeMenu">
+        <el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
           <el-menu-item index="/dashboard">宸ヤ綔鍙�</el-menu-item>
           <el-menu-item index="/import">鏁版嵁瀵煎叆</el-menu-item>
           <el-menu-item index="/data">鏁版嵁鏌ョ湅</el-menu-item>
@@ -43,6 +43,7 @@
               <el-table-column label="鎿嶄綔" width="140" align="center">
                 <template slot-scope="{ row }">
                   <el-button type="text" size="mini" @click="openEdit(row)">缂栬緫</el-button>
+                  <el-button v-if="isAdmin" type="text" size="mini" @click="resetPwd(row)">閲嶇疆瀵嗙爜</el-button>
                   <el-button type="text" size="mini" style="color:#f56c6c" @click="removeUser(row)">鍒犻櫎</el-button>
                 </template>
               </el-table-column>
@@ -101,7 +102,6 @@
   name: 'UserManage',
   data() {
     return {
-      activeMenu: '/users',
       keyword: '',
       list: [],
       loading: false,
@@ -113,6 +113,11 @@
         username: [{ required: true, message: '璇疯緭鍏ョ敤鎴峰悕', trigger: 'blur' }],
         password: [{ required: true, message: '璇疯緭鍏ュ垵濮嬪瘑鐮�', trigger: 'blur' }]
       }
+    }
+  },
+  computed: {
+    isAdmin() {
+      return sessionStorage.getItem('username') === 'admin'
     }
   },
   mounted() { this.loadList() },
@@ -168,6 +173,12 @@
           .finally(() => { this.saving = false })
       })
     },
+    resetPwd(row) {
+      this.$confirm('纭畾灏嗙敤鎴枫��' + (row.realName || row.username) + '銆嶇殑瀵嗙爜閲嶇疆涓� 123456 鍚楋紵', '閲嶇疆瀵嗙爜', { type: 'warning' })
+        .then(() => api.post('/user/reset-password', { id: row.id }))
+        .then(() => { this.$message.success('宸查噸缃负 123456'); this.loadList() })
+        .catch(() => {})
+    },
     removeUser(row) {
       this.$confirm('纭畾鍒犻櫎鐢ㄦ埛銆�' + (row.realName || row.username) + '銆嶅悧锛�', '鍒犻櫎纭', { type: 'warning' })
         .then(() => api.post('/user/delete', null, { params: { id: row.id } }))

--
Gitblit v1.9.1