Преглед изворни кода

Merge remote-tracking branch 'upstream/master'

zyj пре 8 месеци
родитељ
комит
b46223e0f5
31 измењених фајлова са 254 додато и 436 уклоњено
  1. 3 3
      pom.xml
  2. 34 0
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
  3. 3 1
      ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
  4. 14 0
      ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
  5. 21 20
      ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
  6. 0 10
      ruoyi-ui/.eslintignore
  7. 0 199
      ruoyi-ui/.eslintrc.js
  8. 1 19
      ruoyi-ui/package.json
  9. 1 9
      ruoyi-ui/src/App.vue
  10. 1 0
      ruoyi-ui/src/assets/icons/svg/enter.svg
  11. 1 0
      ruoyi-ui/src/assets/icons/svg/more-up.svg
  12. 35 3
      ruoyi-ui/src/components/HeaderSearch/index.vue
  13. 0 1
      ruoyi-ui/src/components/PanThumb/index.vue
  14. 0 106
      ruoyi-ui/src/components/RightPanel/index.vue
  15. 1 1
      ruoyi-ui/src/directive/index.js
  16. 25 17
      ruoyi-ui/src/layout/components/Navbar.vue
  17. 28 7
      ruoyi-ui/src/layout/components/Settings/index.vue
  18. 10 1
      ruoyi-ui/src/layout/components/TagsView/index.vue
  19. 5 6
      ruoyi-ui/src/layout/index.vue
  20. 0 3
      ruoyi-ui/src/main.js
  21. 13 11
      ruoyi-ui/src/settings.js
  22. 5 3
      ruoyi-ui/src/store/getters.js
  23. 4 1
      ruoyi-ui/src/store/modules/settings.js
  24. 19 0
      ruoyi-ui/src/store/modules/user.js
  25. 13 0
      ruoyi-ui/src/utils/dynamicTitle.js
  26. 0 1
      ruoyi-ui/src/utils/generator/html.js
  27. 6 2
      ruoyi-ui/src/views/system/user/profile/index.vue
  28. 0 1
      ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
  29. 0 1
      ruoyi-ui/src/views/tool/build/index.vue
  30. 0 2
      ruoyi-ui/vue.config.js
  31. 11 8
      sql/ry_20250522.sql

+ 3 - 3
pom.xml

@@ -25,13 +25,13 @@
         <kaptcha.version>2.3.3</kaptcha.version>
         <pagehelper.boot.version>1.4.7</pagehelper.boot.version>
         <fastjson.version>2.0.53</fastjson.version>
-        <oshi.version>6.6.5</oshi.version>
-        <commons.io.version>2.13.0</commons.io.version>
+        <oshi.version>6.8.1</oshi.version>
+        <commons.io.version>2.19.0</commons.io.version>
         <poi.version>4.1.2</poi.version>
         <velocity.version>2.3</velocity.version>
         <jwt.version>0.9.1</jwt.version>
         <!-- override dependency version -->
-        <tomcat.version>9.0.102</tomcat.version>
+        <tomcat.version>9.0.105</tomcat.version>
         <logback.version>1.2.13</logback.version>
         <spring-security.version>5.7.12</spring-security.version>
         <spring-framework.version>5.3.39</spring-framework.version>

+ 34 - 0
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java

@@ -1,5 +1,6 @@
 package com.ruoyi.web.controller.system;
 
+import java.util.Date;
 import java.util.List;
 import java.util.Set;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -13,10 +14,14 @@ import com.ruoyi.common.core.domain.entity.SysMenu;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginBody;
 import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.framework.web.service.SysLoginService;
 import com.ruoyi.framework.web.service.SysPermissionService;
 import com.ruoyi.framework.web.service.TokenService;
+import com.ruoyi.system.service.ISysConfigService;
 import com.ruoyi.system.service.ISysMenuService;
 
 /**
@@ -39,6 +44,9 @@ public class SysLoginController
     @Autowired
     private TokenService tokenService;
 
+    @Autowired
+    private ISysConfigService configService;
+
     /**
      * 登录方法
      * 
@@ -79,6 +87,8 @@ public class SysLoginController
         ajax.put("user", user);
         ajax.put("roles", roles);
         ajax.put("permissions", permissions);
+        ajax.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate()));
+        ajax.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate()));
         return ajax;
     }
 
@@ -94,4 +104,28 @@ public class SysLoginController
         List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
         return AjaxResult.success(menuService.buildMenus(menus));
     }
+    
+    // 检查初始密码是否提醒修改
+    public boolean initPasswordIsModify(Date pwdUpdateDate)
+    {
+        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
+        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
+    }
+
+    // 检查密码是否过期
+    public boolean passwordIsExpiration(Date pwdUpdateDate)
+    {
+        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
+        if (passwordValidateDays != null && passwordValidateDays > 0)
+        {
+            if (StringUtils.isNull(pwdUpdateDate))
+            {
+                // 如果从未修改过初始密码,直接提醒过期
+                return true;
+            }
+            Date nowDate = DateUtils.getNowDate();
+            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
+        }
+        return false;
+    }
 }

+ 3 - 1
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java

@@ -17,6 +17,7 @@ import com.ruoyi.common.core.domain.AjaxResult;
 import com.ruoyi.common.core.domain.entity.SysUser;
 import com.ruoyi.common.core.domain.model.LoginUser;
 import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.DateUtils;
 import com.ruoyi.common.utils.SecurityUtils;
 import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.common.utils.file.FileUploadUtils;
@@ -106,7 +107,8 @@ public class SysProfileController extends BaseController
         newPassword = SecurityUtils.encryptPassword(newPassword);
         if (userService.resetUserPwd(userName, newPassword) > 0)
         {
-            // 更新缓存用户密码
+            // 更新缓存用户密码&密码最后更新时间
+            loginUser.getUser().setPwdUpdateDate(DateUtils.getNowDate());
             loginUser.getUser().setPassword(newPassword);
             tokenService.setLoginUser(loginUser);
             return success();

+ 14 - 0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java

@@ -70,6 +70,9 @@ public class SysUser extends BaseEntity
     @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
     private Date loginDate;
 
+    /** 密码最后更新时间 */
+    private Date pwdUpdateDate;
+
     /** 部门对象 */
     @Excels({
         @Excel(name = "部门名称", targetAttr = "deptName"),
@@ -248,6 +251,16 @@ public class SysUser extends BaseEntity
         this.loginDate = loginDate;
     }
 
+    public Date getPwdUpdateDate()
+    {
+        return pwdUpdateDate;
+    }
+
+    public void setPwdUpdateDate(Date pwdUpdateDate)
+    {
+        this.pwdUpdateDate = pwdUpdateDate;
+    }
+
     public SysDept getDept()
     {
         return dept;
@@ -314,6 +327,7 @@ public class SysUser extends BaseEntity
             .append("delFlag", getDelFlag())
             .append("loginIp", getLoginIp())
             .append("loginDate", getLoginDate())
+            .append("pwdUpdateDate", getPwdUpdateDate())
             .append("createBy", getCreateBy())
             .append("createTime", getCreateTime())
             .append("updateBy", getUpdateBy())

+ 21 - 20
ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml

@@ -5,24 +5,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 <mapper namespace="com.ruoyi.system.mapper.SysUserMapper">
 
     <resultMap type="SysUser" id="SysUserResult">
-        <id     property="userId"       column="user_id"      />
-        <result property="deptId"       column="dept_id"      />
-        <result property="userName"     column="user_name"    />
-        <result property="nickName"     column="nick_name"    />
-        <result property="email"        column="email"        />
-        <result property="phonenumber"  column="phonenumber"  />
-        <result property="sex"          column="sex"          />
-        <result property="avatar"       column="avatar"       />
-        <result property="password"     column="password"     />
-        <result property="status"       column="status"       />
-        <result property="delFlag"      column="del_flag"     />
-        <result property="loginIp"      column="login_ip"     />
-        <result property="loginDate"    column="login_date"   />
-        <result property="createBy"     column="create_by"    />
-        <result property="createTime"   column="create_time"  />
-        <result property="updateBy"     column="update_by"    />
-        <result property="updateTime"   column="update_time"  />
-        <result property="remark"       column="remark"       />
+        <id     property="userId"        column="user_id"         />
+        <result property="deptId"        column="dept_id"         />
+        <result property="userName"      column="user_name"       />
+        <result property="nickName"      column="nick_name"       />
+        <result property="email"         column="email"           />
+        <result property="phonenumber"   column="phonenumber"     />
+        <result property="sex"           column="sex"             />
+        <result property="avatar"        column="avatar"          />
+        <result property="password"      column="password"        />
+        <result property="status"        column="status"          />
+        <result property="delFlag"       column="del_flag"        />
+        <result property="loginIp"       column="login_ip"        />
+        <result property="loginDate"     column="login_date"      />
+        <result property="pwdUpdateDate" column="pwd_update_date" />
+        <result property="createBy"     column="create_by"        />
+        <result property="createTime"   column="create_time"      />
+        <result property="updateBy"     column="update_by"        />
+        <result property="updateTime"   column="update_time"      />
+        <result property="remark"       column="remark"           />
         <association property="dept"    javaType="SysDept"         resultMap="deptResult" />
         <collection  property="roles"   javaType="java.util.List"  resultMap="RoleResult" />
     </resultMap>
@@ -47,7 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 	
 	<sql id="selectUserVo">
-        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, 
+        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.pwd_update_date, u.create_by, u.create_time, u.remark, 
         d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
         r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
         from sys_user u
@@ -203,7 +204,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 	</update>
 	
 	<update id="resetUserPwd" parameterType="SysUser">
- 		update sys_user set password = #{password} where user_name = #{userName}
+ 		update sys_user set pwd_update_date = sysdate(), password = #{password} where user_name = #{userName}
 	</update>
 	
 	<delete id="deleteUserById" parameterType="Long">

+ 0 - 10
ruoyi-ui/.eslintignore

@@ -1,10 +0,0 @@
-# 忽略build目录下类型为js的文件的语法检查
-build/*.js
-# 忽略src/assets目录下文件的语法检查
-src/assets
-# 忽略public目录下文件的语法检查
-public
-# 忽略当前目录下为js的文件的语法检查
-*.js
-# 忽略当前目录下为vue的文件的语法检查
-*.vue

+ 0 - 199
ruoyi-ui/.eslintrc.js

@@ -1,199 +0,0 @@
-// ESlint 检查配置
-module.exports = {
-  root: true,
-  parserOptions: {
-    parser: 'babel-eslint',
-    sourceType: 'module'
-  },
-  env: {
-    browser: true,
-    node: true,
-    es6: true,
-  },
-  extends: ['plugin:vue/recommended', 'eslint:recommended'],
-
-  // add your custom rules here
-  //it is base on https://github.com/vuejs/eslint-config-vue
-  rules: {
-    "vue/max-attributes-per-line": [2, {
-      "singleline": 10,
-      "multiline": {
-        "max": 1,
-        "allowFirstLine": false
-      }
-    }],
-    "vue/singleline-html-element-content-newline": "off",
-    "vue/multiline-html-element-content-newline":"off",
-    "vue/name-property-casing": ["error", "PascalCase"],
-    "vue/no-v-html": "off",
-    'accessor-pairs': 2,
-    'arrow-spacing': [2, {
-      'before': true,
-      'after': true
-    }],
-    'block-spacing': [2, 'always'],
-    'brace-style': [2, '1tbs', {
-      'allowSingleLine': true
-    }],
-    'camelcase': [0, {
-      'properties': 'always'
-    }],
-    'comma-dangle': [2, 'never'],
-    'comma-spacing': [2, {
-      'before': false,
-      'after': true
-    }],
-    'comma-style': [2, 'last'],
-    'constructor-super': 2,
-    'curly': [2, 'multi-line'],
-    'dot-location': [2, 'property'],
-    'eol-last': 2,
-    'eqeqeq': ["error", "always", {"null": "ignore"}],
-    'generator-star-spacing': [2, {
-      'before': true,
-      'after': true
-    }],
-    'handle-callback-err': [2, '^(err|error)$'],
-    'indent': [2, 2, {
-      'SwitchCase': 1
-    }],
-    'jsx-quotes': [2, 'prefer-single'],
-    'key-spacing': [2, {
-      'beforeColon': false,
-      'afterColon': true
-    }],
-    'keyword-spacing': [2, {
-      'before': true,
-      'after': true
-    }],
-    'new-cap': [2, {
-      'newIsCap': true,
-      'capIsNew': false
-    }],
-    'new-parens': 2,
-    'no-array-constructor': 2,
-    'no-caller': 2,
-    'no-console': 'off',
-    'no-class-assign': 2,
-    'no-cond-assign': 2,
-    'no-const-assign': 2,
-    'no-control-regex': 0,
-    'no-delete-var': 2,
-    'no-dupe-args': 2,
-    'no-dupe-class-members': 2,
-    'no-dupe-keys': 2,
-    'no-duplicate-case': 2,
-    'no-empty-character-class': 2,
-    'no-empty-pattern': 2,
-    'no-eval': 2,
-    'no-ex-assign': 2,
-    'no-extend-native': 2,
-    'no-extra-bind': 2,
-    'no-extra-boolean-cast': 2,
-    'no-extra-parens': [2, 'functions'],
-    'no-fallthrough': 2,
-    'no-floating-decimal': 2,
-    'no-func-assign': 2,
-    'no-implied-eval': 2,
-    'no-inner-declarations': [2, 'functions'],
-    'no-invalid-regexp': 2,
-    'no-irregular-whitespace': 2,
-    'no-iterator': 2,
-    'no-label-var': 2,
-    'no-labels': [2, {
-      'allowLoop': false,
-      'allowSwitch': false
-    }],
-    'no-lone-blocks': 2,
-    'no-mixed-spaces-and-tabs': 2,
-    'no-multi-spaces': 2,
-    'no-multi-str': 2,
-    'no-multiple-empty-lines': [2, {
-      'max': 1
-    }],
-    'no-native-reassign': 2,
-    'no-negated-in-lhs': 2,
-    'no-new-object': 2,
-    'no-new-require': 2,
-    'no-new-symbol': 2,
-    'no-new-wrappers': 2,
-    'no-obj-calls': 2,
-    'no-octal': 2,
-    'no-octal-escape': 2,
-    'no-path-concat': 2,
-    'no-proto': 2,
-    'no-redeclare': 2,
-    'no-regex-spaces': 2,
-    'no-return-assign': [2, 'except-parens'],
-    'no-self-assign': 2,
-    'no-self-compare': 2,
-    'no-sequences': 2,
-    'no-shadow-restricted-names': 2,
-    'no-spaced-func': 2,
-    'no-sparse-arrays': 2,
-    'no-this-before-super': 2,
-    'no-throw-literal': 2,
-    'no-trailing-spaces': 2,
-    'no-undef': 2,
-    'no-undef-init': 2,
-    'no-unexpected-multiline': 2,
-    'no-unmodified-loop-condition': 2,
-    'no-unneeded-ternary': [2, {
-      'defaultAssignment': false
-    }],
-    'no-unreachable': 2,
-    'no-unsafe-finally': 2,
-    'no-unused-vars': [2, {
-      'vars': 'all',
-      'args': 'none'
-    }],
-    'no-useless-call': 2,
-    'no-useless-computed-key': 2,
-    'no-useless-constructor': 2,
-    'no-useless-escape': 0,
-    'no-whitespace-before-property': 2,
-    'no-with': 2,
-    'one-var': [2, {
-      'initialized': 'never'
-    }],
-    'operator-linebreak': [2, 'after', {
-      'overrides': {
-        '?': 'before',
-        ':': 'before'
-      }
-    }],
-    'padded-blocks': [2, 'never'],
-    'quotes': [2, 'single', {
-      'avoidEscape': true,
-      'allowTemplateLiterals': true
-    }],
-    'semi': [2, 'never'],
-    'semi-spacing': [2, {
-      'before': false,
-      'after': true
-    }],
-    'space-before-blocks': [2, 'always'],
-    'space-before-function-paren': [2, 'never'],
-    'space-in-parens': [2, 'never'],
-    'space-infix-ops': 2,
-    'space-unary-ops': [2, {
-      'words': true,
-      'nonwords': false
-    }],
-    'spaced-comment': [2, 'always', {
-      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
-    }],
-    'template-curly-spacing': [2, 'never'],
-    'use-isnan': 2,
-    'valid-typeof': 2,
-    'wrap-iife': [2, 'any'],
-    'yield-star-spacing': [2, 'both'],
-    'yoda': [2, 'never'],
-    'prefer-const': 2,
-    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
-    'object-curly-spacing': [2, 'always', {
-      objectsInObjects: false
-    }],
-    'array-bracket-spacing': [2, 'never']
-  }
-}

+ 1 - 19
ruoyi-ui/package.json

@@ -8,19 +8,7 @@
     "dev": "vue-cli-service serve",
     "build:prod": "vue-cli-service build",
     "build:stage": "vue-cli-service build --mode staging",
-    "preview": "node build/index.js --preview",
-    "lint": "eslint --ext .js,.vue src"
-  },
-  "husky": {
-    "hooks": {
-      "pre-commit": "lint-staged"
-    }
-  },
-  "lint-staged": {
-    "src/**/*.{js,vue}": [
-      "eslint --fix",
-      "git add"
-    ]
+    "preview": "node build/index.js --preview"
   },
   "keywords": [
     "vue",
@@ -56,23 +44,17 @@
     "vue": "2.6.12",
     "vue-count-to": "1.0.13",
     "vue-cropper": "0.5.5",
-    "vue-meta": "2.4.0",
     "vue-router": "3.4.9",
     "vuedraggable": "2.24.3",
     "vuex": "3.6.0"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "4.4.6",
-    "@vue/cli-plugin-eslint": "4.4.6",
     "@vue/cli-service": "4.4.6",
-    "babel-eslint": "10.1.0",
     "babel-plugin-dynamic-import-node": "2.3.3",
     "chalk": "4.1.0",
     "compression-webpack-plugin": "6.1.2",
     "connect": "3.6.6",
-    "eslint": "7.15.0",
-    "eslint-plugin-vue": "7.2.0",
-    "lint-staged": "10.5.3",
     "sass": "1.32.13",
     "sass-loader": "10.1.1",
     "script-ext-html-webpack-plugin": "2.1.5",

+ 1 - 9
ruoyi-ui/src/App.vue

@@ -10,15 +10,7 @@ import ThemePicker from "@/components/ThemePicker"
 
 export default {
   name: "App",
-  components: { ThemePicker },
-  metaInfo() {
-    return {
-      title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
-      titleTemplate: title => {
-        return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
-      }
-    }
-  }
+  components: { ThemePicker }
 }
 </script>
 <style scoped>

+ 1 - 0
ruoyi-ui/src/assets/icons/svg/enter.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746590936918" class="icon" viewBox="0 0 1194 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" xmlns:xlink="http://www.w3.org/1999/xlink" width="233.203125" height="200"><path d="M1151.9144 325.11999969V89.12a57.04000031 57.04000031 0 0 0-28.8-49.44 58.15999969 58.15999969 0 0 0-57.76000031 0 57.04000031 57.04000031 0 0 0-28.8 49.44v235.99999969c0.24 84.31999969-33.6 152.56000031-94.08 212.00000062-60.07999969 59.83999969-141.84 80.64-227.04 80.4H225.91440031L388.07439969 457.11999969a56.80000031 56.80000031 0 0 0 12.40000031-62.16 57.76000031 57.76000031 0 0 0-94.00000031-18.63999938L48.8744 631.20000031a56.88 56.88 0 0 0 0 80.79999938l264.96 262.56a58.08 58.08 0 0 0 96.55999969-25.59999938 56.80000031 56.80000031 0 0 0-14.95999969-55.2L232.07439969 731.67999969h483.44000062c116.56000031 0 226.15999969-32.08000031 308.64-113.76 82.15999969-80.80000031 128.23999969-178.15999969 127.83999938-292.87999969" p-id="5379"></path></svg>

+ 1 - 0
ruoyi-ui/src/assets/icons/svg/more-up.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1746760911144" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12537" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M395.21211 182.914448c0 62.669318 49.541323 113.472378 110.642936 113.472378 61.093427 0 110.652146-50.80306 110.65214601-113.472378 0-62.685691-49.559742-113.487727-110.65214601-113.487727C444.75241 69.426721 395.21211 120.22978 395.21211 182.914448zM395.21211 523.34693101c0 62.668295 49.541323 113.487727 110.642936 113.48772699 61.093427 0 110.652146-50.820456 110.652146-113.487727 0-62.669318-49.559742-113.472378-110.652146-113.472378C444.75241 409.874553 395.21211 460.67761301 395.21211 523.34693101zM395.21211 841.084529c0 62.686714 49.541323 113.488751 110.642936 113.488751 61.093427 0 110.652146-50.80203599 110.65214601-113.488751 0-62.669318-49.559742-113.471354-110.65214601-113.471354C444.75241 727.614198 395.21211 778.416234 395.21211 841.084529z" p-id="12538"></path></svg>

+ 35 - 3
ruoyi-ui/src/components/HeaderSearch/index.vue

@@ -16,11 +16,14 @@
         prefix-icon="el-icon-search"
         placeholder="菜单搜索,支持标题、URL模糊查询"
         clearable
+        @keyup.enter.native="selectActiveResult"
+        @keydown.up.native="navigateResult('up')"
+        @keydown.down.native="navigateResult('down')"
       >
       </el-input>
       <el-scrollbar wrap-class="right-scrollbar-wrapper">
         <div class="result-wrap">
-          <div class="search-item" v-for="item in options" :key="item.path">
+          <div class="search-item" v-for="(item, index) in options" :key="item.path" :style="activeStyle(index)" @mouseenter="activeIndex = index" @mouseleave="activeIndex = -1">
             <div class="left">
               <svg-icon class="menu-icon" :icon-class="item.icon" />
             </div>
@@ -32,6 +35,7 @@
                 {{ item.path }}
               </div>
             </div>
+            <svg-icon icon-class="enter" v-show="index === activeIndex"/>
           </div>
        </div>
       </el-scrollbar>
@@ -51,11 +55,15 @@ export default {
       search: '',
       options: [],
       searchPool: [],
+      activeIndex: -1,
       show: false,
       fuse: undefined
     }
   },
   computed: {
+    theme() {
+      return this.$store.state.settings.theme
+    },
     routes() {
       return this.$store.getters.defaultRoutes
     }
@@ -84,6 +92,7 @@ export default {
       this.search = ''
       this.options = []
       this.show = false
+      this.activeIndex = -1
     },
     change(val) {
       const path = val.path
@@ -162,11 +171,31 @@ export default {
       return res
     },
     querySearch(query) {
+      this.activeIndex = -1
       if (query !== '') {
         this.options = this.fuse.search(query).map((item) => item.item) ?? this.searchPool
       } else {
         this.options = this.searchPool
       }
+    },
+    activeStyle(index) {
+      if (index !== this.activeIndex) return {}
+      return {
+        "background-color": this.theme,
+        "color": "#fff"
+      }
+    },
+    navigateResult(direction) {
+      if (direction === "up") {
+        this.activeIndex = this.activeIndex <= 0 ? this.options.length - 1 : this.activeIndex - 1
+      } else if (direction === "down") {
+        this.activeIndex = this.activeIndex >= this.options.length - 1 ? 0 : this.activeIndex + 1
+      }
+    },
+    selectActiveResult() {
+      if (this.options.length > 0 && this.activeIndex >= 0) {
+        this.change(this.options[this.activeIndex])
+      }
     }
   }
 }
@@ -189,11 +218,13 @@ export default {
 
 .result-wrap {
   height: 280px;
-  margin: 12px 0;
+  margin: 6px 0;
 
   .search-item {
     display: flex;
     height: 48px;
+    align-items: center;
+    padding-right: 10px;
 
     .left {
       width: 60px;
@@ -202,16 +233,17 @@ export default {
       .menu-icon {
         width: 18px;
         height: 18px;
-        margin-top: 5px;
       }
     }
 
     .search-info {
       padding-left: 5px;
+      margin-top: 10px;
       width: 100%;
       display: flex;
       flex-direction: column;
       justify-content: flex-start;
+      flex: 1;
 
       .menu-title,
       .menu-path {

+ 0 - 1
ruoyi-ui/src/components/PanThumb/index.vue

@@ -5,7 +5,6 @@
         <slot />
       </div>
     </div>
-    <!-- eslint-disable-next-line -->
     <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
   </div>
 </template>

+ 0 - 106
ruoyi-ui/src/components/RightPanel/index.vue

@@ -1,106 +0,0 @@
-<template>
-  <div ref="rightPanel" class="rightPanel-container">
-    <div class="rightPanel-background" />
-    <div class="rightPanel">
-      <div class="rightPanel-items">
-        <slot />
-      </div>
-    </div>
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RightPanel',
-  props: {
-    clickNotClose: {
-      default: false,
-      type: Boolean
-    }
-  },
-  computed: {
-    show: {
-      get() {
-        return this.$store.state.settings.showSettings
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
-      }
-    }
-  },
-  watch: {
-    show(value) {
-      if (value && !this.clickNotClose) {
-        this.addEventClick()
-      }
-    }
-  },
-  mounted() {
-    this.addEventClick()
-  },
-  beforeDestroy() {
-    const elx = this.$refs.rightPanel
-    elx.remove()
-  },
-  methods: {
-    addEventClick() {
-      window.addEventListener('click', this.closeSidebar)
-    },
-    closeSidebar(evt) {
-      const parent = evt.target.closest('.el-drawer__body')
-      if (!parent) {
-        this.show = false
-        window.removeEventListener('click', this.closeSidebar)
-      }
-    }
-  }
-}
-</script>
-
-<style lang="scss" scoped>
-.rightPanel-background {
-  position: fixed;
-  top: 0;
-  left: 0;
-  opacity: 0;
-  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
-  background: rgba(0, 0, 0, .2);
-  z-index: -1;
-}
-
-.rightPanel {
-  width: 100%;
-  max-width: 260px;
-  height: 100vh;
-  position: fixed;
-  top: 0;
-  right: 0;
-  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
-  transition: all .25s cubic-bezier(.7, .3, .1, 1);
-  transform: translate(100%);
-  background: #fff;
-  z-index: 40000;
-}
-
-.handle-button {
-  width: 48px;
-  height: 48px;
-  position: absolute;
-  left: -48px;
-  text-align: center;
-  font-size: 24px;
-  border-radius: 6px 0 0 6px !important;
-  z-index: 0;
-  pointer-events: auto;
-  cursor: pointer;
-  color: #fff;
-  line-height: 48px;
-  i {
-    font-size: 24px;
-    line-height: 48px;
-  }
-}
-</style>

+ 1 - 1
ruoyi-ui/src/directive/index.js

@@ -17,7 +17,7 @@ const install = function(Vue) {
 if (window.Vue) {
   window['hasRole'] = hasRole
   window['hasPermi'] = hasPermi
-  Vue.use(install) // eslint-disable-line
+  Vue.use(install)
 }
 
 export default install

+ 25 - 17
ruoyi-ui/src/layout/components/Navbar.vue

@@ -25,23 +25,24 @@
 
       </template>
 
-      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
+      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="hover">
         <div class="avatar-wrapper">
           <img :src="avatar" class="user-avatar">
-          <i class="el-icon-caret-bottom" />
+          <span class="user-nickname"> {{ nickName }} </span>
         </div>
         <el-dropdown-menu slot="dropdown">
           <router-link to="/user/profile">
             <el-dropdown-item>个人中心</el-dropdown-item>
           </router-link>
-          <el-dropdown-item @click.native="setting = true">
-            <span>布局设置</span>
-          </el-dropdown-item>
           <el-dropdown-item divided @click.native="logout">
             <span>退出登录</span>
           </el-dropdown-item>
         </el-dropdown-menu>
       </el-dropdown>
+
+      <div class="right-menu-item hover-effect setting" @click="setLayout" v-if="setting">
+        <svg-icon icon-class="more-up" />
+      </div>
     </div>
   </div>
 </template>
@@ -58,6 +59,7 @@ import RuoYiGit from '@/components/RuoYi/Git'
 import RuoYiDoc from '@/components/RuoYi/Doc'
 
 export default {
+  emits: ['setLayout'],
   components: {
     Breadcrumb,
     TopNav,
@@ -72,17 +74,12 @@ export default {
     ...mapGetters([
       'sidebar',
       'avatar',
-      'device'
+      'device',
+      'nickName'
     ]),
     setting: {
       get() {
         return this.$store.state.settings.showSettings
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
       }
     },
     topNav: {
@@ -95,6 +92,9 @@ export default {
     toggleSideBar() {
       this.$store.dispatch('app/toggleSideBar')
     },
+    setLayout(event) {
+      this.$emit('setLayout')
+    },
     logout() {
       this.$confirm('确定注销并退出系统吗?', '提示', {
         confirmButtonText: '确定',
@@ -173,17 +173,25 @@ export default {
     }
 
     .avatar-container {
-      margin-right: 30px;
+      margin-right: 0px;
+      padding-right: 0px;
 
       .avatar-wrapper {
-        margin-top: 5px;
+        margin-top: 10px;
         position: relative;
 
         .user-avatar {
           cursor: pointer;
-          width: 40px;
-          height: 40px;
-          border-radius: 10px;
+          width: 30px;
+          height: 30px;
+          border-radius: 50%;
+        }
+
+        .user-nickname{
+          position: relative;
+          bottom: 10px;
+          font-size: 14px;
+          font-weight: bold;
         }
 
         .el-icon-caret-bottom {

+ 28 - 7
ruoyi-ui/src/layout/components/Settings/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <el-drawer size="280px" :visible="visible" :with-header="false" :append-to-body="true" :show-close="false">
+  <el-drawer size="280px" :visible="showSettings" :with-header="false" :append-to-body="true" :before-close="closeSetting">
     <div class="drawer-container">
       <div>
         <div class="setting-drawer-content">
@@ -49,6 +49,11 @@
           <el-switch v-model="tagsView" class="drawer-switch" />
         </div>
 
+        <div class="drawer-item">
+          <span>显示页签图标</span>
+          <el-switch v-model="tagsIcon" :disabled="!tagsView" class="drawer-switch" />
+        </div>
+
         <div class="drawer-item">
           <span>固定 Header</span>
           <el-switch v-model="fixedHeader" class="drawer-switch" />
@@ -78,18 +83,15 @@ import ThemePicker from '@/components/ThemePicker'
 
 export default {
   components: { ThemePicker },
+  expose: ['openSetting'],
   data() {
     return {
       theme: this.$store.state.settings.theme,
-      sideTheme: this.$store.state.settings.sideTheme
+      sideTheme: this.$store.state.settings.sideTheme,
+      showSettings: false
     }
   },
   computed: {
-    visible: {
-      get() {
-        return this.$store.state.settings.showSettings
-      }
-    },
     fixedHeader: {
       get() {
         return this.$store.state.settings.fixedHeader
@@ -127,6 +129,17 @@ export default {
         })
       }
     },
+    tagsIcon: {
+      get() {
+        return this.$store.state.settings.tagsIcon
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'tagsIcon',
+          value: val
+        })
+      }
+    },
     sidebarLogo: {
       get() {
         return this.$store.state.settings.sidebarLogo
@@ -147,6 +160,7 @@ export default {
           key: 'dynamicTitle',
           value: val
         })
+        this.$store.dispatch('settings/setTitle', this.$store.state.settings.title)
       }
     },
   },
@@ -165,6 +179,12 @@ export default {
       })
       this.sideTheme = val
     },
+    openSetting() {
+      this.showSettings = true
+    },
+    closeSetting(){
+      this.showSettings = false
+    },
     saveSetting() {
       this.$modal.loading("正在保存到本地,请稍候...")
       this.$cache.local.set(
@@ -172,6 +192,7 @@ export default {
         `{
             "topNav":${this.topNav},
             "tagsView":${this.tagsView},
+            "tagsIcon":${this.tagsIcon},
             "fixedHeader":${this.fixedHeader},
             "sidebarLogo":${this.sidebarLogo},
             "dynamicTitle":${this.dynamicTitle},

+ 10 - 1
ruoyi-ui/src/layout/components/TagsView/index.vue

@@ -5,7 +5,7 @@
         v-for="tag in visitedViews"
         ref="tag"
         :key="tag.path"
-        :class="isActive(tag)?'active':''"
+        :class="{ 'active': isActive(tag), 'has-icon': tagsIcon }"
         :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
         tag="span"
         class="tags-view-item"
@@ -13,6 +13,7 @@
         @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
         @contextmenu.prevent.native="openMenu(tag,$event)"
       >
+        <svg-icon v-if="tagsIcon && tag.meta && tag.meta.icon && tag.meta.icon !== '#'" :icon-class="tag.meta.icon" />
         {{ tag.title }}
         <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
       </router-link>
@@ -52,6 +53,9 @@ export default {
     },
     theme() {
       return this.$store.state.settings.theme
+    },
+    tagsIcon() {
+      return this.$store.state.settings.tagsIcon
     }
   },
   watch: {
@@ -277,6 +281,11 @@ export default {
       }
     }
   }
+
+  .tags-view-item.active.has-icon::before {
+    content: none !important;
+  }
+
   .contextmenu {
     margin: 0;
     background: #fff;

+ 5 - 6
ruoyi-ui/src/layout/index.vue

@@ -4,19 +4,16 @@
     <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
     <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
       <div :class="{'fixed-header':fixedHeader}">
-        <navbar/>
+        <navbar @setLayout="setLayout"/>
         <tags-view v-if="needTagsView"/>
       </div>
       <app-main/>
-      <right-panel>
-        <settings/>
-      </right-panel>
+      <settings ref="settingRef"/>
     </div>
   </div>
 </template>
 
 <script>
-import RightPanel from '@/components/RightPanel'
 import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
 import ResizeMixin from './mixin/ResizeHandler'
 import { mapState } from 'vuex'
@@ -27,7 +24,6 @@ export default {
   components: {
     AppMain,
     Navbar,
-    RightPanel,
     Settings,
     Sidebar,
     TagsView
@@ -57,6 +53,9 @@ export default {
   methods: {
     handleClickOutside() {
       this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+    },
+    setLayout() {
+      this.$refs.settingRef.openSetting()
     }
   }
 }

+ 0 - 3
ruoyi-ui/src/main.js

@@ -33,8 +33,6 @@ import ImageUpload from "@/components/ImageUpload"
 import ImagePreview from "@/components/ImagePreview"
 // 字典标签组件
 import DictTag from '@/components/DictTag'
-// 头部标签组件
-import VueMeta from 'vue-meta'
 // 字典数据组件
 import DictData from '@/components/DictData'
 
@@ -60,7 +58,6 @@ Vue.component('ImagePreview', ImagePreview)
 
 Vue.use(directive)
 Vue.use(plugins)
-Vue.use(VueMeta)
 DictData.install()
 
 /**

+ 13 - 11
ruoyi-ui/src/settings.js

@@ -1,13 +1,18 @@
 module.exports = {
+  /**
+   * 网页标题
+   */
+  title: process.env.VUE_APP_TITLE,
+
   /**
    * 侧边栏主题 深色主题theme-dark,浅色主题theme-light
    */
   sideTheme: 'theme-dark',
 
   /**
-   * 是否系统布局配置
+   * 系统布局配置
    */
-  showSettings: false,
+  showSettings: true,
 
   /**
    * 是否显示顶部导航
@@ -18,6 +23,11 @@ module.exports = {
    * 是否显示 tagsView
    */
   tagsView: true,
+  
+  /**
+   * 显示页签图标
+   */
+  tagsIcon: false,
 
   /**
    * 是否固定头部
@@ -32,13 +42,5 @@ module.exports = {
   /**
    * 是否显示动态标题
    */
-  dynamicTitle: false,
-
-  /**
-   * @type {string | array} 'production' | ['production', 'development']
-   * @description Need show err logs component.
-   * The default is only used in the production env
-   * If you want to also use it in dev, you can pass ['production', 'development']
-   */
-  errorLog: 'production'
+  dynamicTitle: false
 }

+ 5 - 3
ruoyi-ui/src/store/getters.js

@@ -7,13 +7,15 @@ const getters = {
   cachedViews: state => state.tagsView.cachedViews,
   token: state => state.user.token,
   avatar: state => state.user.avatar,
+  id: state => state.user.id,
   name: state => state.user.name,
+  nickName: state => state.user.nickName,
   introduction: state => state.user.introduction,
   roles: state => state.user.roles,
   permissions: state => state.user.permissions,
   permission_routes: state => state.permission.routes,
-  topbarRouters:state => state.permission.topbarRouters,
-  defaultRoutes:state => state.permission.defaultRoutes,
-  sidebarRouters:state => state.permission.sidebarRouters
+  topbarRouters: state => state.permission.topbarRouters,
+  defaultRoutes: state => state.permission.defaultRoutes,
+  sidebarRouters: state => state.permission.sidebarRouters
 }
 export default getters

+ 4 - 1
ruoyi-ui/src/store/modules/settings.js

@@ -1,6 +1,7 @@
 import defaultSettings from '@/settings'
+import { useDynamicTitle } from '@/utils/dynamicTitle'
 
-const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
+const { sideTheme, showSettings, topNav, tagsView, tagsIcon, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
 
 const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
 const state = {
@@ -10,6 +11,7 @@ const state = {
   showSettings: showSettings,
   topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
   tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
+  tagsIcon: storageSetting.tagsIcon === undefined ? tagsIcon : storageSetting.tagsIcon,
   fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
   sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
   dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
@@ -30,6 +32,7 @@ const actions = {
   // 设置网页标题
   setTitle({ commit }, title) {
     state.title = title
+    useDynamicTitle()
   }
 }
 

+ 19 - 0
ruoyi-ui/src/store/modules/user.js

@@ -1,3 +1,5 @@
+import router from '@/router'
+import { MessageBox, } from 'element-ui'
 import { login, logout, getInfo } from '@/api/login'
 import { getToken, setToken, removeToken } from '@/utils/auth'
 import { isHttp, isEmpty } from "@/utils/validate"
@@ -8,6 +10,7 @@ const user = {
     token: getToken(),
     id: '',
     name: '',
+    nickName: '',
     avatar: '',
     roles: [],
     permissions: []
@@ -23,6 +26,9 @@ const user = {
     SET_NAME: (state, name) => {
       state.name = name
     },
+    SET_NICK_NAME: (state, nickName) => {
+      state.nickName = nickName
+    },
     SET_AVATAR: (state, avatar) => {
       state.avatar = avatar
     },
@@ -69,7 +75,20 @@ const user = {
           }
           commit('SET_ID', user.userId)
           commit('SET_NAME', user.userName)
+          commit('SET_NICK_NAME', user.nickName)
           commit('SET_AVATAR', avatar)
+          /* 初始密码提示 */
+          if(res.isDefaultModifyPwd) {
+            MessageBox.confirm('您的密码还是初始密码,请修改密码!',  '安全提示', {  confirmButtonText: '确定',  cancelButtonText: '取消',  type: 'warning' }).then(() => {
+              router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
+            }).catch(() => {})
+          }
+          /* 过期密码提示 */
+          if(!res.isDefaultModifyPwd && res.isPasswordExpired) {
+            MessageBox.confirm('您的密码已过期,请尽快修改密码!',  '安全提示', {  confirmButtonText: '确定',  cancelButtonText: '取消',  type: 'warning' }).then(() => {
+              router.push({ name: 'Profile', params: { activeTab: 'resetPwd' } })
+            }).catch(() => {})
+          }
           resolve(res)
         }).catch(error => {
           reject(error)

+ 13 - 0
ruoyi-ui/src/utils/dynamicTitle.js

@@ -0,0 +1,13 @@
+import store from '@/store'
+import defaultSettings from '@/settings'
+
+/**
+ * 动态修改标题
+ */
+export function useDynamicTitle() {
+  if (store.state.settings.dynamicTitle) {
+    document.title = store.state.settings.title + ' - ' + defaultSettings.title
+  } else {
+    document.title = defaultSettings.title
+  }
+}

+ 0 - 1
ruoyi-ui/src/utils/generator/html.js

@@ -1,4 +1,3 @@
-/* eslint-disable max-len */
 import { trigger } from './config'
 
 let confGlobal

+ 6 - 2
ruoyi-ui/src/views/system/user/profile/index.vue

@@ -44,7 +44,7 @@
           <div slot="header" class="clearfix">
             <span>基本资料</span>
           </div>
-          <el-tabs v-model="activeTab">
+          <el-tabs v-model="selectedTab">
             <el-tab-pane label="基本资料" name="userinfo">
               <userInfo :user="user" />
             </el-tab-pane>
@@ -72,10 +72,14 @@ export default {
       user: {},
       roleGroup: {},
       postGroup: {},
-      activeTab: "userinfo"
+      selectedTab: "userinfo"
     }
   },
   created() {
+    const activeTab = this.$route.params && this.$route.params.activeTab
+    if (activeTab) {
+      this.selectedTab = activeTab
+    }
     this.getUser()
   },
   methods: {

+ 0 - 1
ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue

@@ -115,7 +115,6 @@ export default {
   },
   computed: {},
   watch: {
-    // eslint-disable-next-line func-names
     'formData.value': function (val) {
       this.dataType = isNumberStr(val) ? 'number' : 'string'
     }

+ 0 - 1
ruoyi-ui/src/views/tool/build/index.vue

@@ -190,7 +190,6 @@ export default {
     }
   },
   watch: {
-    // eslint-disable-next-line func-names
     'activeData.label': function (val, oldVal) {
       if (
         this.activeData.placeholder === undefined

+ 0 - 2
ruoyi-ui/vue.config.js

@@ -25,8 +25,6 @@ module.exports = {
   outputDir: 'dist',
   // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
   assetsDir: 'static',
-  // 是否开启eslint保存检测,有效值:ture | false | 'error'
-  lintOnSave: process.env.NODE_ENV === 'development',
   // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
   productionSourceMap: false,
   transpileDependencies: ['quill'],

+ 11 - 8
sql/ry_20250417.sql → sql/ry_20250522.sql

@@ -56,6 +56,7 @@ create table sys_user (
   del_flag          char(1)         default '0'                comment '删除标志(0代表存在 2代表删除)',
   login_ip          varchar(128)    default ''                 comment '最后登录IP',
   login_date        datetime                                   comment '最后登录时间',
+  pwd_update_date   datetime                                   comment '密码最后更新时间',
   create_by         varchar(64)     default ''                 comment '创建者',
   create_time       datetime                                   comment '创建时间',
   update_by         varchar(64)     default ''                 comment '更新者',
@@ -67,8 +68,8 @@ create table sys_user (
 -- ----------------------------
 -- 初始化-用户信息表数据
 -- ----------------------------
-insert into sys_user values(1,  103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '管理员');
-insert into sys_user values(2,  105, 'ry',    '若依', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '测试员');
+insert into sys_user values(1,  103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '管理员');
+insert into sys_user values(2,  105, 'ry',    '若依', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), sysdate(), 'admin', sysdate(), '', null, '测试员');
 
 
 -- ----------------------------
@@ -546,12 +547,14 @@ create table sys_config (
   primary key (config_id)
 ) engine=innodb auto_increment=100 comment = '参数配置表';
 
-insert into sys_config values(1, '主框架页-默认皮肤样式名称',     'sys.index.skinName',            'skin-blue',     'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
-insert into sys_config values(2, '用户管理-账号初始密码',         'sys.user.initPassword',         '123456',        'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
-insert into sys_config values(3, '主框架页-侧边栏主题',           'sys.index.sideTheme',           'theme-dark',    'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' );
-insert into sys_config values(4, '账号自助-验证码开关',           'sys.account.captchaEnabled',    'true',          'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
-insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser',      'false',         'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
-insert into sys_config values(6, '用户登录-黑名单列表',           'sys.login.blackIPList',         '',              'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
+insert into sys_config values(1, '主框架页-默认皮肤样式名称',     'sys.index.skinName',               'skin-blue',     'Y', 'admin', sysdate(), '', null, '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
+insert into sys_config values(2, '用户管理-账号初始密码',         'sys.user.initPassword',            '123456',        'Y', 'admin', sysdate(), '', null, '初始化密码 123456' );
+insert into sys_config values(3, '主框架页-侧边栏主题',           'sys.index.sideTheme',              'theme-dark',    'Y', 'admin', sysdate(), '', null, '深色主题theme-dark,浅色主题theme-light' );
+insert into sys_config values(4, '账号自助-验证码开关',           'sys.account.captchaEnabled',       'true',          'Y', 'admin', sysdate(), '', null, '是否开启验证码功能(true开启,false关闭)');
+insert into sys_config values(5, '账号自助-是否开启用户注册功能', 'sys.account.registerUser',         'false',         'Y', 'admin', sysdate(), '', null, '是否开启注册用户功能(true开启,false关闭)');
+insert into sys_config values(6, '用户登录-黑名单列表',           'sys.login.blackIPList',            '',              'Y', 'admin', sysdate(), '', null, '设置登录IP黑名单限制,多个匹配项以;分隔,支持匹配(*通配、网段)');
+insert into sys_config values(7, '用户管理-初始密码修改策略',     'sys.account.initPasswordModify',   '1',             'Y', 'admin', sysdate(), '', null, '0:初始密码修改策略关闭,没有任何提示,1:提醒用户,如果未修改初始密码,则在登录时就会提醒修改密码对话框');
+insert into sys_config values(8, '用户管理-账号密码更新周期',     'sys.account.passwordValidateDays', '0',             'Y', 'admin', sysdate(), '', null, '密码更新周期(填写数字,数据初始化值为0不限制,若修改必须为大于0小于365的正整数),如果超过这个周期登录系统时,则在登录时就会提醒修改密码对话框');
 
 
 -- ----------------------------