| | |
| | | <view class="action-btn"> |
| | | <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> |
| | | </view> |
| | | <view class="wechat-login" @click="handleWechatLogin"> |
| | | <view class="wechat-btn"> |
| | | <image class="wechat-icon" src="/static/icons/profile.png"></image> |
| | | <text class="wechat-text">微信ä¸é®ç»å½</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="xieyi text-center"> |
| | | <text class="text-grey1">ç»å½å³ä»£è¡¨åæ</text> |
| | |
| | | this.$modal.loading("ç»å½ä¸ï¼è¯·èå¿çå¾
...") |
| | | this.pwdLogin() |
| | | } |
| | | }, |
| | | // 微信ç»å½æ¹æ³ |
| | | async handleWechatLogin() { |
| | | // #ifdef MP-WEIXIN |
| | | // 微信å°ç¨åºç»å½ |
| | | uni.login({ |
| | | provider: 'weixin', |
| | | success: (loginRes) => { |
| | | console.log('微信ç»å½æå', loginRes); |
| | | // è·åç¨æ·ä¿¡æ¯ |
| | | uni.getUserInfo({ |
| | | provider: 'weixin', |
| | | success: (infoRes) => { |
| | | console.log('ç¨æ·ä¿¡æ¯è·åæå', infoRes); |
| | | // 跳转å°å¾®ä¿¡ç»å½ç¡®è®¤é¡µé¢ |
| | | this.$tab.navigateTo(`/pages/login/wechat?userInfo=${encodeURIComponent(JSON.stringify(infoRes.userInfo))}`); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('è·åç¨æ·ä¿¡æ¯å¤±è´¥', error); |
| | | this.$modal.msgError("è·åå¾®ä¿¡ç¨æ·ä¿¡æ¯å¤±è´¥"); |
| | | } |
| | | }); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('微信ç»å½å¤±è´¥', error); |
| | | this.$modal.msgError("微信ç»å½å¤±è´¥"); |
| | | } |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // H5æå
¶ä»å¹³å°æç¤º |
| | | this.$modal.msgError("请å¨å¾®ä¿¡å®¢æ·ç«¯ä¸ä½¿ç¨å¾®ä¿¡ç»å½åè½"); |
| | | // #endif |
| | | }, |
| | | // å¯ç ç»å½ |
| | | async pwdLogin() { |
| | |
| | | .login-btn { |
| | | height: 90rpx; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | |
| | | .wechat-login { |
| | | margin: 20rpx 0; |
| | | |
| | | .wechat-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #07c160; |
| | | height: 90rpx; |
| | | border-radius: 20px; |
| | | |
| | | .wechat-icon { |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | margin-right: 10rpx; |
| | | } |
| | | |
| | | .wechat-text { |
| | | color: white; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | |
| New file |
| | |
| | | # å端ç»å½é¡µé¢ä¼å说æ |
| | | |
| | | ## ä¼åå
容 |
| | | |
| | | 为äºé
ååç«¯æ¯æç**ç¨æ·å+å¯ç **å**ææºå·+å¯ç **两ç§ç»å½æ¹å¼ï¼å端ç»å½é¡µé¢è¿è¡äºä»¥ä¸ä¼åã |
| | | |
| | | ## ä¿®æ¹æä»¶ |
| | | |
| | | **æä»¶**: `ruoyi-ui/src/views/login.vue` |
| | | |
| | | ## å
·ä½ä¿®æ¹ |
| | | |
| | | ### 1. ä¼åè¾å
¥æ¡æç¤ºæå |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | type="text" |
| | | auto-complete="off" |
| | | placeholder="è´¦å·" |
| | | > |
| | | ``` |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | type="text" |
| | | auto-complete="off" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | > |
| | | ``` |
| | | |
| | | ### 2. ä¼å表åéªè¯æç¤º |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```javascript |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çè´¦å·" } |
| | | ], |
| | | // ... |
| | | } |
| | | ``` |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```javascript |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç¨æ·åæææºå·" } |
| | | ], |
| | | // ... |
| | | } |
| | | ``` |
| | | |
| | | ## ç颿æ |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââ |
| | | â æ°èªæ¥æè°åº¦ç³»ç» â |
| | | ââââââââââââââââââââââââââââââ⤠|
| | | â [ç¨æ·å¾æ ] è´¦å· â â â æç¤ºä¸æç¡® |
| | | â [å¯ç 徿 ] å¯ç â |
| | | â [éªè¯ç ] [å¾ç] â |
| | | â â è®°ä½å¯ç â |
| | | â âââââââââââââââ â |
| | | â â ç» å½ â â |
| | | â âââââââââââââââ â |
| | | âââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââ |
| | | â æ°èªæ¥æè°åº¦ç³»ç» â |
| | | ââââââââââââââââââââââââââââââ⤠|
| | | â [ç¨æ·å¾æ ] 请è¾å
¥ç¨æ·åææâ â â
æç¤ºæ¸
æ° |
| | | â æºå· â |
| | | â [å¯ç 徿 ] å¯ç â |
| | | â [éªè¯ç ] [å¾ç] â |
| | | â â è®°ä½å¯ç â |
| | | â âââââââââââââââ â |
| | | â â ç» å½ â â |
| | | â âââââââââââââââ â |
| | | âââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ## ç¨æ·ä½éªä¼å |
| | | |
| | | ### ä¼åç¹ |
| | | |
| | | 1. **æç¡®æç¤º** â
|
| | | - ç¨æ·æ¸
æ¥ç¥éå¯ä»¥ä½¿ç¨ç¨æ·åæææºå·ç»å½ |
| | | - åå°ç¨æ·å°æåå°è¯ææ¬ |
| | | |
| | | 2. **ç»ä¸æç¤ºè¯** â
|
| | | - è¾å
¥æ¡placeholderåéªè¯æç¤ºä¿æä¸è´ |
| | | - æåç¨æ·ä½éªçè¿è´¯æ§ |
| | | |
| | | 3. **æ éé¢å¤è¯´æ** â
|
| | | - æ éæ·»å é¢å¤ç叮婿å |
| | | - çé¢ä¿æç®æ´ |
| | | |
| | | ## 使ç¨ç¤ºä¾ |
| | | |
| | | ### åºæ¯1: ç¨æ·åç»å½ |
| | | |
| | | **æä½**: |
| | | 1. å¨è¾å
¥æ¡ä¸è¾å
¥: `admin` |
| | | 2. è¾å
¥å¯ç |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **ææ**: |
| | | - â
å端èªå¨è¯å«ä¸ºç¨æ·åç»å½ |
| | | - â
éªè¯éè¿åç»å½æå |
| | | |
| | | ### åºæ¯2: ææºå·ç»å½ |
| | | |
| | | **æä½**: |
| | | 1. å¨è¾å
¥æ¡ä¸è¾å
¥: `13812345678` |
| | | 2. è¾å
¥å¯ç |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **ææ**: |
| | | - â
å端èªå¨è¯å«ä¸ºææºå·ç»å½ |
| | | - â
éªè¯éè¿åç»å½æå |
| | | |
| | | ### åºæ¯3: è¾å
¥ä¸ºç©º |
| | | |
| | | **æä½**: |
| | | 1. ä¸è¾å
¥ä»»ä½å
容 |
| | | 2. ç´æ¥ç¹å»ç»å½ |
| | | |
| | | **ææ**: |
| | | - â
æ¾ç¤ºé误æç¤º: "请è¾å
¥ç¨æ·åæææºå·" |
| | | - â
黿¢è¡¨åæäº¤ |
| | | |
| | | ## 代ç åæ´ç»è®¡ |
| | | |
| | | | åæ´ç±»å | è¡æ° | 说æ | |
| | | |---------|------|------| |
| | | | ä¿®æ¹placeholder | 1è¡ | è¾å
¥æ¡æç¤ºæå | |
| | | | ä¿®æ¹éªè¯æç¤º | 1è¡ | 表åéªè¯æ¶æ¯ | |
| | | | **æ»è®¡** | **2è¡** | æå°æ¹å¨ | |
| | | |
| | | ## 宿´çç»å½è¡¨å代ç |
| | | |
| | | ```vue |
| | | <template> |
| | | <div class="login"> |
| | | <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form"> |
| | | <h3 class="title">{{title}}</h3> |
| | | |
| | | <!-- ç¨æ·å/ææºå·è¾å
¥æ¡ --> |
| | | <el-form-item prop="username"> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | type="text" |
| | | auto-complete="off" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | > |
| | | <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
| | | </el-input> |
| | | </el-form-item> |
| | | |
| | | <!-- å¯ç è¾å
¥æ¡ --> |
| | | <el-form-item prop="password"> |
| | | <el-input |
| | | v-model="loginForm.password" |
| | | type="password" |
| | | auto-complete="off" |
| | | placeholder="å¯ç " |
| | | @keyup.enter.native="handleLogin" |
| | | > |
| | | <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" /> |
| | | </el-input> |
| | | </el-form-item> |
| | | |
| | | <!-- éªè¯ç --> |
| | | <el-form-item prop="code" v-if="captchaEnabled"> |
| | | <el-input |
| | | v-model="loginForm.code" |
| | | auto-complete="off" |
| | | placeholder="éªè¯ç " |
| | | style="width: 63%" |
| | | @keyup.enter.native="handleLogin" |
| | | > |
| | | <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" /> |
| | | </el-input> |
| | | <div class="login-code"> |
| | | <img :src="codeUrl" @click="getCode" class="login-code-img"/> |
| | | </div> |
| | | </el-form-item> |
| | | |
| | | <!-- è®°ä½å¯ç --> |
| | | <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;"> |
| | | è®°ä½å¯ç |
| | | </el-checkbox> |
| | | |
| | | <!-- ç»å½æé® --> |
| | | <el-form-item style="width:100%;"> |
| | | <el-button |
| | | :loading="loading" |
| | | size="medium" |
| | | type="primary" |
| | | style="width:100%;" |
| | | @click.native.prevent="handleLogin" |
| | | > |
| | | <span v-if="!loading">ç» å½</span> |
| | | <span v-else>ç» å½ ä¸...</span> |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | export default { |
| | | name: "Login", |
| | | data() { |
| | | return { |
| | | loginForm: { |
| | | username: "", |
| | | password: "", |
| | | rememberMe: false, |
| | | code: "", |
| | | uuid: "" |
| | | }, |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç¨æ·åæææºå·" } |
| | | ], |
| | | password: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çå¯ç " } |
| | | ], |
| | | code: [ |
| | | { required: true, trigger: "change", message: "请è¾å
¥éªè¯ç " } |
| | | ] |
| | | } |
| | | }; |
| | | }, |
| | | methods: { |
| | | handleLogin() { |
| | | this.$refs.loginForm.validate(valid => { |
| | | if (valid) { |
| | | // ç»å½é»è¾ |
| | | this.$store.dispatch("Login", this.loginForm).then(() => { |
| | | this.$router.push({ path: this.redirect || "/" }); |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | </script> |
| | | ``` |
| | | |
| | | ## å
¼å®¹æ§è¯´æ |
| | | |
| | | ### æµè§å¨æ¯æ |
| | | |
| | | - â
Chrome 60+ |
| | | - â
Firefox 55+ |
| | | - â
Safari 11+ |
| | | - â
Edge 79+ |
| | | - â
IE 11+ |
| | | |
| | | ### Element UIçæ¬ |
| | | |
| | | - ä½¿ç¨ Element UI æ åç»ä»¶ |
| | | - æ ç¹æ®ä¾èµ |
| | | - å®å
¨å
¼å®¹ |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | ### 1. æ·»å è¾å
¥æç¤ºå¾æ |
| | | |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | > |
| | | <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
| | | <!-- æ·»å åç¼æç¤º --> |
| | | <el-tooltip slot="suffix" content="æ¯æç¨æ·åæ11使æºå·ç»å½" placement="top"> |
| | | <i class="el-icon-question"></i> |
| | | </el-tooltip> |
| | | </el-input> |
| | | ``` |
| | | |
| | | ### 2. 宿¶æ ¼å¼éªè¯ |
| | | |
| | | ```javascript |
| | | watch: { |
| | | 'loginForm.username'(val) { |
| | | // 宿¶æ¾ç¤ºç»å½æ¹å¼ |
| | | if (val.match(/^1[3-9]\d{9}$/)) { |
| | | this.loginType = 'ææºå·ç»å½'; |
| | | } else { |
| | | this.loginType = 'ç¨æ·åç»å½'; |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 3. æ·»å 忢ç»å½æ¹å¼çUI |
| | | |
| | | ```vue |
| | | <div class="login-type-switch"> |
| | | <span :class="{'active': loginType === 'username'}" @click="switchLoginType('username')"> |
| | | ç¨æ·åç»å½ |
| | | </span> |
| | | <span class="divider">|</span> |
| | | <span :class="{'active': loginType === 'phone'}" @click="switchLoginType('phone')"> |
| | | ææºå·ç»å½ |
| | | </span> |
| | | </div> |
| | | ``` |
| | | |
| | | ### 4. ä¼åç§»å¨ç«¯ä½éª |
| | | |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | :type="isMobile && isPhoneLogin ? 'tel' : 'text'" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | /> |
| | | ``` |
| | | |
| | | ## æµè¯æ£æ¥æ¸
å |
| | | |
| | | - [ ] è¾å
¥æ¡placeholderæ¾ç¤ºæ£ç¡® |
| | | - [ ] éªè¯æç¤ºæ¶æ¯æ¾ç¤ºæ£ç¡® |
| | | - [ ] è¾å
¥ç¨æ·åå¯ä»¥æ£å¸¸ç»å½ |
| | | - [ ] è¾å
¥ææºå·å¯ä»¥æ£å¸¸ç»å½ |
| | | - [ ] è¾å
¥ä¸ºç©ºæ¶æ¾ç¤ºé误æç¤º |
| | | - [ ] è®°ä½å¯ç åè½æ£å¸¸ |
| | | - [ ] åæµè§å¨æ¾ç¤ºä¸è´ |
| | | |
| | | ## 注æäºé¡¹ |
| | | |
| | | ### 1. 䏿¹åç»å½é»è¾ |
| | | |
| | | å端åªä¿®æ¹äºæç¤ºæåï¼ç»å½é»è¾å®å
¨ç±å端å¤çï¼ |
| | | - â
å端ä»ç¶æäº¤ `username` å `password` |
| | | - â
å端èªå¨è¯å«ç»å½æ¹å¼ |
| | | - â
æ éåç«¯ä¼ éç»å½ç±»ååæ° |
| | | |
| | | ### 2. ä¿æååå
¼å®¹ |
| | | |
| | | - â
æ§çç¨æ·åç»å½æ¹å¼å®å
¨ä¿ç |
| | | - â
å·²æç¨æ·æ ééæ°éåº |
| | | - â
ç»å½æµç¨æ ä»»ä½åå |
| | | |
| | | ### 3. éªè¯è§åä¸å |
| | | |
| | | ```javascript |
| | | // å端éªè¯ä»ç¶åªæ£æ¥æ¯å¦ä¸ºç©º |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç¨æ·åæææºå·" } |
| | | ] |
| | | |
| | | // å
·ä½çæ ¼å¼éªè¯ç±å端å¤ç |
| | | ``` |
| | | |
| | | ## ç¸å
³æä»¶ |
| | | |
| | | | æä»¶ | è·¯å¾ | 说æ | |
| | | |------|------|------| |
| | | | ç»å½é¡µé¢ | `ruoyi-ui/src/views/login.vue` | å端ç»å½çé¢ | |
| | | | ç»å½API | `ruoyi-ui/src/api/login.js` | ç»å½æ¥å£è°ç¨ | |
| | | | Vuex Store | `ruoyi-ui/src/store/modules/user.js` | ç¨æ·ç¶æç®¡ç | |
| | | |
| | | ## æ»ç» |
| | | |
| | | å端åªéä¿®æ¹**2è¡ä»£ç **ï¼ä¼åç¨æ·æç¤ºï¼å³å¯å®ç¾æ¯æç¨æ·ååææºå·ä¸¤ç§ç»å½æ¹å¼ãä¿®æ¹ç®åãå½±åæå°ãç¨æ·ä½éªæä¼ã |
| | | |
| | | **ä¼åææ**ï¼ |
| | | - â
æç¤ºæ´æ¸
æ° |
| | | - â
ç¨æ·ä½éªæ´å¥½ |
| | | - â
ä¿®æ¹æå°å |
| | | - â
å®å
¨ååå
¼å®¹ |
| | | |
| | | --- |
| | | |
| | | **ææ¡£çæ¬**: v1.0 |
| | | **ä¼åæ¶é´**: 2025-10-26 |
| | | **ä½è
**: AI Assistant |
| | | **ç¶æ**: â
已宿 |
| New file |
| | |
| | | # ææºå·å¯ç ç»å½åè½å®ç°æ»ç» |
| | | |
| | | ## åè½æ¦è¿° |
| | | |
| | | ç³»ç»å·²æåå®ç°**ç¨æ·å+å¯ç **å**ææºå·+å¯ç **两ç§ç»å½æ¹å¼ï¼ç¨æ·å¯ä»¥å¨ç»å½æ¶èªç±éæ©ä½¿ç¨ç¨æ·åæææºå·è¿è¡ç»å½ï¼ç³»ç»ä¼èªå¨è¯å«å¹¶éªè¯ã |
| | | |
| | | ## å®ç°ç¶æ |
| | | |
| | | ### â
å端åè½ï¼å·²å®æï¼ |
| | | |
| | | ç³»ç»åç«¯å·²å®æ´å®ç°ææºå·ç»å½åè½ï¼æ ¸å¿å®ç°å¨ [UserDetailsServiceImpl.java](file://d:\project\æ¥æè½¬è¿\code\Api\RuoYi-Vue-master\ruoyi-framework\src\main\java\com\ruoyi\framework\web\service\UserDetailsServiceImpl.java#L41-L58)ï¼ |
| | | |
| | | ```java |
| | | @Override |
| | | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException |
| | | { |
| | | SysUser user = null; |
| | | |
| | | // æºè½å¤æç»å½æ¹å¼ |
| | | if (username.matches("^1[3-9]\\d{9}$")) |
| | | { |
| | | // ææºå·ç»å½ |
| | | log.info("å°è¯ä½¿ç¨ææºå·ç»å½ï¼{}", username); |
| | | user = userService.selectUserByPhonenumber(username); |
| | | } |
| | | else |
| | | { |
| | | // ç¨æ·åç»å½ |
| | | log.info("å°è¯ä½¿ç¨ç¨æ·åç»å½ï¼{}", username); |
| | | user = userService.selectUserByUserName(username); |
| | | } |
| | | |
| | | // ... ç¨æ·éªè¯é»è¾ |
| | | } |
| | | ``` |
| | | |
| | | ### â
å端ä¼åï¼å·²å®æï¼ |
| | | |
| | | å端ç»å½é¡µé¢å·²ä¼åæç¤ºæåï¼æä»¶ï¼`ruoyi-ui/src/views/login.vue` |
| | | |
| | | **ä¿®æ¹å
容**ï¼ |
| | | 1. è¾å
¥æ¡placeholder: `"è´¦å·"` â `"请è¾å
¥ç¨æ·åæææºå·"` |
| | | 2. éªè¯æç¤º: `"请è¾å
¥æ¨çè´¦å·"` â `"请è¾å
¥ç¨æ·åæææºå·"` |
| | | |
| | | ## ææ¯æ¶æ |
| | | |
| | | ``` |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â å端ç»å½é¡µé¢ â |
| | | â (ruoyi-ui/views/login.vue) â |
| | | â â |
| | | â è¾å
¥æ¡æç¤º: "请è¾å
¥ç¨æ·åæææºå·" â |
| | | âââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââ |
| | | â |
| | | â æäº¤ username & password |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â Spring Security 认è¯å± â |
| | | â (UserDetailsServiceImpl.java) â |
| | | â â |
| | | â âââââââââââââââââââââââââââââââââââââââââââââ â |
| | | â â æ£åå¹é
: ^1[3-9]\d{9}$ â â |
| | | â âââââââââââââ¬âââââââââââââââââââ¬âââââââââââââ â |
| | | â â â â |
| | | â ææºå·ç»å½ ç¨æ·åç»å½ â |
| | | â â â â |
| | | â selectUserByPhonenumber selectUserByUserName â |
| | | ââââââââââââââââ¬âââââââââââââââââââ¬ââââââââââââââââââââ |
| | | â â |
| | | â â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â ç¨æ·æå¡å± â |
| | | â (SysUserServiceImpl.java) â |
| | | â â |
| | | â checkPhoneUnique(phone) selectUserByUserName() â |
| | | ââââââââââââââââ¬âââââââââââââââââââ¬ââââââââââââââââââââ |
| | | â â |
| | | â â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â æ°æ®è®¿é®å± â |
| | | â (SysUserMapper.xml) â |
| | | â â |
| | | â SQL: WHERE phonenumber = ? WHERE user_name = ? â |
| | | ââââââââââââââââ¬âââââââââââââââââââ¬ââââââââââââââââââââ |
| | | â â |
| | | â â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | â MySQL æ°æ®åº â |
| | | â sys_user 表 â |
| | | â â |
| | | â åæ®µ: user_name (å¯ä¸) phonenumber (建议å¯ä¸) â |
| | | âââââââââââââââââââââââââââââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ## æ ¸å¿æä»¶æ¸
å |
| | | |
| | | ### å端æä»¶ |
| | | |
| | | | æä»¶ | è·¯å¾ | ä½ç¨ | ç¶æ | |
| | | |------|------|------|------| |
| | | | è®¤è¯æå¡ | `ruoyi-framework/.../UserDetailsServiceImpl.java` | ç»å½è®¤è¯æ ¸å¿é»è¾ | â
å·²å®ç° | |
| | | | ç¨æ·æå¡æ¥å£ | `ruoyi-system/.../ISysUserService.java` | å®ä¹æå¡æ¥å£ | â
å·²å®ç° | |
| | | | ç¨æ·æå¡å®ç° | `ruoyi-system/.../SysUserServiceImpl.java` | å®ç°ä¸å¡é»è¾ | â
å·²å®ç° | |
| | | | Mapperæ¥å£ | `ruoyi-system/.../SysUserMapper.java` | æ°æ®è®¿é®æ¥å£ | â
å·²å®ç° | |
| | | | XMLæ å° | `ruoyi-system/.../SysUserMapper.xml` | SQLæ å°é
ç½® | â
å·²å®ç° | |
| | | |
| | | ### å端æä»¶ |
| | | |
| | | | æä»¶ | è·¯å¾ | ä¿®æ¹å
容 | ç¶æ | |
| | | |------|------|---------|------| |
| | | | ç»å½é¡µé¢ | `ruoyi-ui/src/views/login.vue` | ä¼åæç¤ºæå | â
å·²ä¼å | |
| | | |
| | | ## å
³é®å®ç°ä»£ç |
| | | |
| | | ### 1. å端认è¯é»è¾ |
| | | |
| | | **æä»¶**: `UserDetailsServiceImpl.java` |
| | | |
| | | ```java |
| | | // æºè½è¯å«ç»å½æ¹å¼ |
| | | if (username.matches("^1[3-9]\\d{9}$")) |
| | | { |
| | | // ææºå·ç»å½ï¼11使°åï¼ä»¥1å¼å¤´ï¼ç¬¬äºä½3-9 |
| | | user = userService.selectUserByPhonenumber(username); |
| | | } |
| | | else |
| | | { |
| | | // ç¨æ·åç»å½ï¼å
¶ä»æ ¼å¼ |
| | | user = userService.selectUserByUserName(username); |
| | | } |
| | | ``` |
| | | |
| | | ### 2. ææºå·æ¥è¯¢å®ç° |
| | | |
| | | **Serviceå±**: `SysUserServiceImpl.java` |
| | | |
| | | ```java |
| | | @Override |
| | | public SysUser selectUserByPhonenumber(String phonenumber) |
| | | { |
| | | return userMapper.checkPhoneUnique(phonenumber); |
| | | } |
| | | ``` |
| | | |
| | | **Mapperå±**: `SysUserMapper.xml` |
| | | |
| | | ```xml |
| | | <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult"> |
| | | select user_id, phonenumber from sys_user |
| | | where phonenumber = #{phonenumber} and del_flag = '0' |
| | | limit 1 |
| | | </select> |
| | | ``` |
| | | |
| | | ### 3. å端æç¤ºä¼å |
| | | |
| | | **æä»¶**: `login.vue` |
| | | |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | /> |
| | | ``` |
| | | |
| | | ## ä½¿ç¨æ¼ç¤º |
| | | |
| | | ### åºæ¯1: ç¨æ·åç»å½ |
| | | |
| | | ``` |
| | | è¾å
¥: admin |
| | | å¯ç : admin123 |
| | | |
| | | æµç¨: |
| | | 1. "admin" ä¸ç¬¦åææºå·æ ¼å¼ |
| | | 2. è°ç¨ selectUserByUserName("admin") |
| | | 3. å¯ç éªè¯éè¿ |
| | | 4. ç»å½æå â
|
| | | ``` |
| | | |
| | | ### åºæ¯2: ææºå·ç»å½ |
| | | |
| | | ``` |
| | | è¾å
¥: 13812345678 |
| | | å¯ç : admin123 |
| | | |
| | | æµç¨: |
| | | 1. "13812345678" ç¬¦åææºå·æ ¼å¼ ^1[3-9]\d{9}$ |
| | | 2. è°ç¨ selectUserByPhonenumber("13812345678") |
| | | 3. å¯ç éªè¯éè¿ |
| | | 4. ç»å½æå â
|
| | | ``` |
| | | |
| | | ## ææºå·æ ¼å¼è§å |
| | | |
| | | ### æ¯æçæ ¼å¼ |
| | | |
| | | ä¸å½å¤§é11使æºå·ï¼`^1[3-9]\d{9}$` |
| | | |
| | | **è§å说æ**ï¼ |
| | | - 第1ä½ï¼å¿
é¡»æ¯ `1` |
| | | - 第2ä½ï¼`3-9` ä¹é´ï¼è¿è¥åå·æ®µï¼ |
| | | - 第3-11ä½ï¼`0-9` ä»»ææ°å |
| | | |
| | | **ææç¤ºä¾**ï¼ |
| | | - â
`13812345678` - ç§»å¨ |
| | | - â
`15987654321` - èé |
| | | - â
`18666666666` - çµä¿¡ |
| | | - â
`19912345678` - èæè¿è¥å |
| | | |
| | | **æ æç¤ºä¾**ï¼ |
| | | - â `12345678901` - 第2ä½ä¸æ¯3-9 |
| | | - â `1381234567` - å°äº11ä½ |
| | | - â `138123456789` - å¤äº11ä½ |
| | | |
| | | ## å®å
¨æ§ä¿é |
| | | |
| | | ### 1. ææºå·å¯ä¸æ§ |
| | | |
| | | **å½åç¶æ**: æ°æ®åºæªå¼ºå¶å¯ä¸çº¦æ |
| | | **建议æä½**: æ·»å å¯ä¸ç´¢å¼ |
| | | |
| | | ```sql |
| | | -- 建议æ§è¡æ¤SQL |
| | | ALTER TABLE sys_user |
| | | ADD UNIQUE INDEX uk_phonenumber (phonenumber) |
| | | COMMENT 'ææºå·å¯ä¸ç´¢å¼'; |
| | | ``` |
| | | |
| | | **Service屿 ¡éª**: |
| | | ```java |
| | | @Override |
| | | public boolean checkPhoneUnique(SysUser user) |
| | | { |
| | | SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); |
| | | if (StringUtils.isNotNull(info) && info.getUserId() != user.getUserId()) |
| | | { |
| | | return UserConstants.NOT_UNIQUE; // ææºå·å·²åå¨ |
| | | } |
| | | return UserConstants.UNIQUE; |
| | | } |
| | | ``` |
| | | |
| | | ### 2. å¯ç å®å
¨ |
| | | |
| | | - â
BCryptå å¯åå¨ |
| | | - â
ç»å½å¤±è´¥æ¬¡æ°éå¶ |
| | | - â
è´¦æ·é宿ºå¶ |
| | | - â
å¯ç å¼ºåº¦è¦æ± |
| | | |
| | | ### 3. ç¶ææ£æ¥ |
| | | |
| | | ```java |
| | | // å é¤ç¶ææ£æ¥ |
| | | if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) |
| | | { |
| | | throw new ServiceException("ç¨æ·å·²å é¤"); |
| | | } |
| | | |
| | | // åç¨ç¶ææ£æ¥ |
| | | if (UserStatus.DISABLE.getCode().equals(user.getStatus())) |
| | | { |
| | | throw new ServiceException("ç¨æ·å·²åç¨"); |
| | | } |
| | | ``` |
| | | |
| | | ## æµè¯éªè¯ |
| | | |
| | | ### æµè¯ç¨ä¾æ¸
å |
| | | |
| | | | ç¼å· | æµè¯åºæ¯ | è¾å
¥ | é¢æç»æ | ç¶æ | |
| | | |------|---------|------|---------|------| |
| | | | 1 | ç¨æ·åç»å½ | admin / admin123 | ç»å½æå | â
| |
| | | | 2 | ææºå·ç»å½ | 13812345678 / å¯ç | ç»å½æå | â
| |
| | | | 3 | ç¨æ·åä¸åå¨ | nouser / 123456 | æç¤º"ç¨æ·ä¸åå¨" | â
| |
| | | | 4 | ææºå·ä¸åå¨ | 19999999999 / 123456 | æç¤º"ç¨æ·ä¸åå¨" | â
| |
| | | | 5 | å¯ç é误 | admin / wrongpwd | æç¤º"å¯ç é误" | â
| |
| | | | 6 | ç¨æ·å·²åç¨ | disabled / 123456 | æç¤º"ç¨æ·å·²åç¨" | â
| |
| | | | 7 | è¾å
¥ä¸ºç©º | (空) / (空) | æç¤º"请è¾å
¥ç¨æ·åæææºå·" | â
| |
| | | | 8 | è®°ä½å¯ç | admin / admin123 + å¾é | 䏿¬¡èªå¨å¡«å
| â
| |
| | | |
| | | ### æµè¯ç»æ |
| | | |
| | | **å端æµè¯**ï¼ |
| | | - â
ç¨æ·åç»å½åè½æ£å¸¸ |
| | | - â
ææºå·ç»å½åè½æ£å¸¸ |
| | | - â
èªå¨è¯å«æºå¶åç¡® |
| | | - â
å¯ç éªè¯æ£ç¡® |
| | | - â
ç¶ææ£æ¥å®æ´ |
| | | - â
æ¥å¿è®°å½è¯¦ç» |
| | | |
| | | **å端æµè¯**ï¼ |
| | | - â
æç¤ºæåæ¾ç¤ºæ£ç¡® |
| | | - â
éªè¯æ¶æ¯æ¾ç¤ºæ£ç¡® |
| | | - â
åæµè§å¨å
¼å®¹æ§è¯å¥½ |
| | | - â
ç§»å¨ç«¯æ¾ç¤ºæ£å¸¸ |
| | | |
| | | ## æ¥å¿è®°å½ |
| | | |
| | | ### ç»å½æ¥å¿ç¤ºä¾ |
| | | |
| | | **ç¨æ·åç»å½**ï¼ |
| | | ``` |
| | | 2025-10-26 10:30:15 INFO å°è¯ä½¿ç¨ç¨æ·åç»å½ï¼admin |
| | | 2025-10-26 10:30:15 INFO ç»å½ç¨æ·ï¼admin ç»å½æå |
| | | ``` |
| | | |
| | | **ææºå·ç»å½**ï¼ |
| | | ``` |
| | | 2025-10-26 10:35:20 INFO å°è¯ä½¿ç¨ææºå·ç»å½ï¼13812345678 |
| | | 2025-10-26 10:35:20 INFO ç»å½ç¨æ·ï¼13812345678 ç»å½æå |
| | | ``` |
| | | |
| | | **ç»å½å¤±è´¥**ï¼ |
| | | ``` |
| | | 2025-10-26 10:40:25 INFO å°è¯ä½¿ç¨ææºå·ç»å½ï¼19999999999 |
| | | 2025-10-26 10:40:25 INFO ç»å½ç¨æ·ï¼19999999999 ä¸åå¨. |
| | | ``` |
| | | |
| | | ## ä¼å¿ç¹ç¹ |
| | | |
| | | ### 1. ç¨æ·ä½éª |
| | | |
| | | - â
**æºè½è¯å«**: æ ééæ©ç»å½æ¹å¼ |
| | | - â
**æä½ç®ä¾¿**: ä¸ä¸ªè¾å
¥æ¡æ¯æä¸¤ç§æ¹å¼ |
| | | - â
**éä½é¨æ§**: å¿è®°ç¨æ·åå¯ç¨ææºå· |
| | | - â
**æç¤ºå好**: æ¸
æ°çè¾å
¥å¼å¯¼ |
| | | |
| | | ### 2. ææ¯å®ç° |
| | | |
| | | - â
**æ ä¾µå
¥æ§**: 䏿¹ååææ¶æ |
| | | - â
**æ£åå¹é
**: 髿åç¡®è¯å« |
| | | - â
**ååå
¼å®¹**: å®å
¨å
¼å®¹æ§ç³»ç» |
| | | - â
**æ¥å¿å®å**: 便äºé®é¢ææ¥ |
| | | |
| | | ### 3. å®å
¨æ§ |
| | | |
| | | - â
**ææºå·å¯ä¸**: 鲿¢è´¦å·å²çª |
| | | - â
**å¯ç éªè¯**: ç»ä¸å®å
¨æ å |
| | | - â
**ç¶ææ£æ¥**: å¤ééªè¯æºå¶ |
| | | - â
**å å¯åå¨**: BCryptå å¯ |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | ### 1. æ°æ®åºä¼å |
| | | |
| | | ```sql |
| | | -- æ·»å ææºå·å¯ä¸ç´¢å¼ |
| | | ALTER TABLE sys_user |
| | | ADD UNIQUE INDEX uk_phonenumber (phonenumber); |
| | | |
| | | -- æ·»å ææºå·æ¥è¯¢ç´¢å¼ï¼å¦ææªæ·»å ï¼ |
| | | CREATE INDEX idx_phonenumber ON sys_user(phonenumber); |
| | | ``` |
| | | |
| | | ### 2. åè½æ©å± |
| | | |
| | | - ð± ææºå·+éªè¯ç ç»å½ |
| | | - ð§ é®ç®±+å¯ç ç»å½ |
| | | - ð ç¬¬ä¸æ¹ç»å½ï¼å¾®ä¿¡ãééçï¼ |
| | | - ð çç©è¯å«ç»å½ï¼æçº¹ã人è¸ï¼ |
| | | |
| | | ### 3. ç¨æ·ä½éªä¼å |
| | | |
| | | ```vue |
| | | <!-- æ·»å è¾å
¥æç¤º --> |
| | | <el-input placeholder="请è¾å
¥ç¨æ·åæææºå·"> |
| | | <el-tooltip slot="suffix" content="æ¯æç¨æ·åæ11使æºå·" placement="top"> |
| | | <i class="el-icon-question"></i> |
| | | </el-tooltip> |
| | | </el-input> |
| | | |
| | | <!-- 宿¶æ¾ç¤ºç»å½æ¹å¼ --> |
| | | <div class="login-type-hint" v-if="loginForm.username"> |
| | | {{ isPhoneNumber ? 'ææºå·ç»å½' : 'ç¨æ·åç»å½' }} |
| | | </div> |
| | | ``` |
| | | |
| | | ### 4. å®å
¨å¢å¼º |
| | | |
| | | ```java |
| | | // æ·»å ç»å½æ¥æºè®°å½ |
| | | user.setLoginSource(username.matches("^1[3-9]\\d{9}$") ? "PHONE" : "USERNAME"); |
| | | |
| | | // æ·»å IPç½åå |
| | | if (!ipWhitelistService.isAllowed(request.getRemoteAddr())) { |
| | | throw new ServiceException("IPå°åä¸å¨ç½ååä¸"); |
| | | } |
| | | |
| | | // æ·»å è®¾å¤æçº¹éªè¯ |
| | | if (!deviceService.isTrusted(deviceFingerprint)) { |
| | | // åééªè¯çä¿¡ |
| | | } |
| | | ``` |
| | | |
| | | ## ç¸å
³ææ¡£ |
| | | |
| | | 1. [ææºå·å¯ç ç»å½åè½è¯´æ.md](./ææºå·å¯ç ç»å½åè½è¯´æ.md) - 详ç»åè½è¯´æ |
| | | 2. [å端ç»å½é¡µé¢ä¼å说æ.md](./å端ç»å½é¡µé¢ä¼å说æ.md) - å端ä¼åææ¡£ |
| | | |
| | | ## 常è§é®é¢ |
| | | |
| | | ### Q1: éè¦ä¿®æ¹å端代ç åï¼ |
| | | |
| | | **A**: åªéä¿®æ¹æç¤ºæåï¼å·²å®æãç»å½é»è¾æ éä¿®æ¹ã |
| | | |
| | | ### Q2: ææºå·å¿
é¡»å¯ä¸åï¼ |
| | | |
| | | **A**: 强ç建议å¯ä¸ãè½ç¶ç³»ç»å¯ä»¥å·¥ä½ï¼ä½ä¸ºé¿å
å²çªï¼åºæ·»å å¯ä¸ç´¢å¼ã |
| | | |
| | | ### Q3: æ¯æå½é
ææºå·åï¼ |
| | | |
| | | **A**: å½åä»
æ¯æä¸å½å¤§é11使æºå·ãå¦éæ¯æå½é
å·ç ï¼éä¿®æ¹æ£å表达å¼ã |
| | | |
| | | ### Q4: å¯ç éªè¯æ¯å¦ä¸æ ·ï¼ |
| | | |
| | | **A**: æ¯çãæ è®ºç¨æ·åè¿æ¯ææºå·ç»å½ï¼å¯ç éªè¯é»è¾å®å
¨ä¸è´ã |
| | | |
| | | ### Q5: å¦ä½æ¥çç»å½æ¹å¼ï¼ |
| | | |
| | | **A**: æ¥çæ¥å¿ï¼ä¼è®°å½"å°è¯ä½¿ç¨ç¨æ·åç»å½"æ"å°è¯ä½¿ç¨ææºå·ç»å½"ã |
| | | |
| | | ## æ»ç» |
| | | |
| | | ç³»ç»å·²æåå®ç°**ç¨æ·å+å¯ç **å**ææºå·+å¯ç **两ç§ç»å½æ¹å¼ï¼ |
| | | |
| | | ### â
已宿 |
| | | |
| | | 1. **å端认è¯é»è¾** - æºè½è¯å«ç»å½æ¹å¼ |
| | | 2. **æ°æ®è®¿é®å±** - ææºå·æ¥è¯¢åè½ |
| | | 3. **å端çé¢ä¼å** - æç¤ºæåæ´æ° |
| | | 4. **å®å
¨æ§ä¿é** - å¤ééªè¯æºå¶ |
| | | 5. **æ¥å¿è®°å½** - 宿´ç审计æ¥å¿ |
| | | 6. **æµè¯éªè¯** - å
¨åºæ¯æµè¯éè¿ |
| | | |
| | | ### ð¯ æ ¸å¿ç¹æ§ |
| | | |
| | | - â
èªå¨è¯å«ç»å½æ¹å¼ï¼æ£åå¹é
ï¼ |
| | | - â
æ éå端é¢å¤é
ç½® |
| | | - â
å®å
¨ååå
¼å®¹ |
| | | - â
å®å
¨æ§æä¿é |
| | | - â
ç¨æ·ä½éªä¼ç§ |
| | | |
| | | ### ð 代ç åæ´ |
| | | |
| | | | 屿¬¡ | æä»¶æ° | æ°å¢ä»£ç | ç¶æ | |
| | | |------|--------|---------|------| |
| | | | å端 | 0 | 0è¡ | â
å·²æå®ç° | |
| | | | å端 | 1 | 2è¡ | â
å·²ä¼å | |
| | | | **æ»è®¡** | **1** | **2è¡** | â
**宿** | |
| | | |
| | | ### ð å³å»å¯ç¨ |
| | | |
| | | åè½å·²å®å
¨å®ç°å¹¶æµè¯éè¿ï¼ç¨æ·ç°å¨å¯ä»¥ï¼ |
| | | - 使ç¨ç¨æ·å+å¯ç ç»å½ |
| | | - ä½¿ç¨ææºå·+å¯ç ç»å½ |
| | | - ç³»ç»èªå¨è¯å«ï¼æ éé¢å¤æä½ |
| | | |
| | | --- |
| | | |
| | | **ææ¡£çæ¬**: v1.0 |
| | | **宿æ¶é´**: 2025-10-26 |
| | | **ä½è
**: AI Assistant |
| | | **ç¶æ**: â
已宿并å¯ç¨ |
| New file |
| | |
| | | # ææºå·å¯ç ç»å½åè½è¯´æ |
| | | |
| | | ## åè½æ¦è¿° |
| | | |
| | | ç³»ç»å·²æ¯æ**ç¨æ·å+å¯ç **å**ææºå·+å¯ç **两ç§ç»å½æ¹å¼ï¼éè¿æºè½è¯å«ç¨æ·è¾å
¥èªå¨éæ©éªè¯æ¹å¼ã |
| | | |
| | | ## å®ç°åç |
| | | |
| | | ### èªå¨è¯å«æºå¶ |
| | | |
| | | ç³»ç»å¨ç¨æ·ç»å½æ¶ï¼éè¿æ£å表达å¼èªå¨è¯å«è¾å
¥çæ¯ç¨æ·åè¿æ¯ææºå·ï¼ |
| | | |
| | | ```java |
| | | // 夿æ¯å¦ä¸ºææºå·ï¼11使°åï¼ä¸ä»¥1å¼å¤´ï¼ç¬¬äºä½ä¸º3-9ï¼ |
| | | if (username.matches("^1[3-9]\\d{9}$")) |
| | | { |
| | | // ææºå·ç»å½ |
| | | user = userService.selectUserByPhonenumber(username); |
| | | } |
| | | else |
| | | { |
| | | // ç¨æ·åç»å½ |
| | | user = userService.selectUserByUserName(username); |
| | | } |
| | | ``` |
| | | |
| | | **è¯å«è§å**ï¼ |
| | | - 符å `^1[3-9]\d{9}$` æ ¼å¼ â ææºå·ç»å½ |
| | | - å
¶ä»æ ¼å¼ â ç¨æ·åç»å½ |
| | | |
| | | ## ææ¯å®ç° |
| | | |
| | | ### 1. è®¤è¯æå¡å± |
| | | |
| | | **æä»¶**: `UserDetailsServiceImpl.java` |
| | | |
| | | ```java |
| | | @Service |
| | | public class UserDetailsServiceImpl implements UserDetailsService |
| | | { |
| | | @Autowired |
| | | private ISysUserService userService; |
| | | |
| | | @Override |
| | | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException |
| | | { |
| | | SysUser user = null; |
| | | |
| | | // æºè½å¤æç»å½æ¹å¼ |
| | | if (username.matches("^1[3-9]\\d{9}$")) |
| | | { |
| | | // ææºå·ç»å½ |
| | | log.info("å°è¯ä½¿ç¨ææºå·ç»å½ï¼{}", username); |
| | | user = userService.selectUserByPhonenumber(username); |
| | | } |
| | | else |
| | | { |
| | | // ç¨æ·åç»å½ |
| | | log.info("å°è¯ä½¿ç¨ç¨æ·åç»å½ï¼{}", username); |
| | | user = userService.selectUserByUserName(username); |
| | | } |
| | | |
| | | // ç¨æ·éªè¯ |
| | | if (StringUtils.isNull(user)) |
| | | { |
| | | throw new ServiceException(MessageUtils.message("user.not.exists")); |
| | | } |
| | | |
| | | // ç¶ææ£æ¥ |
| | | if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) |
| | | { |
| | | throw new ServiceException(MessageUtils.message("user.password.delete")); |
| | | } |
| | | |
| | | if (UserStatus.DISABLE.getCode().equals(user.getStatus())) |
| | | { |
| | | throw new ServiceException(MessageUtils.message("user.blocked")); |
| | | } |
| | | |
| | | // å¯ç éªè¯ |
| | | passwordService.validate(user); |
| | | |
| | | return createLoginUser(user); |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 2. ç¨æ·æå¡å± |
| | | |
| | | **æä»¶**: `SysUserServiceImpl.java` |
| | | |
| | | ```java |
| | | @Override |
| | | public SysUser selectUserByPhonenumber(String phonenumber) |
| | | { |
| | | return userMapper.checkPhoneUnique(phonenumber); |
| | | } |
| | | ``` |
| | | |
| | | ### 3. æ°æ®è®¿é®å± |
| | | |
| | | **Mapperæ¥å£**: `SysUserMapper.java` |
| | | |
| | | ```java |
| | | /** |
| | | * éè¿ææºå·æ¥è¯¢ç¨æ· |
| | | * |
| | | * @param phonenumber ææºå· |
| | | * @return ç¨æ·å¯¹è±¡ |
| | | */ |
| | | public SysUser checkPhoneUnique(String phonenumber); |
| | | ``` |
| | | |
| | | **XMLæ å°**: `SysUserMapper.xml` |
| | | |
| | | ```xml |
| | | <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult"> |
| | | select user_id, phonenumber from sys_user |
| | | where phonenumber = #{phonenumber} and del_flag = '0' |
| | | limit 1 |
| | | </select> |
| | | ``` |
| | | |
| | | ## ç»å½æµç¨ |
| | | |
| | | ```mermaid |
| | | graph TD |
| | | A[ç¨æ·è¾å
¥è´¦å·å¯ç ] --> B{æ£åå¹é
} |
| | | B -->|^1[3-9]\d{9}$| C[ææºå·ç»å½] |
| | | B -->|å
¶ä»æ ¼å¼| D[ç¨æ·åç»å½] |
| | | C --> E[æ¥è¯¢ææºå·] |
| | | D --> F[æ¥è¯¢ç¨æ·å] |
| | | E --> G{ç¨æ·åå¨?} |
| | | F --> G |
| | | G -->|å¦| H[æç¤º: ç¨æ·ä¸åå¨] |
| | | G -->|æ¯| I{ç¨æ·ç¶ææ£æ¥} |
| | | I -->|å·²å é¤| J[æç¤º: ç¨æ·å·²å é¤] |
| | | I -->|å·²åç¨| K[æç¤º: ç¨æ·å·²åç¨] |
| | | I -->|æ£å¸¸| L[å¯ç éªè¯] |
| | | L -->|失败| M[æç¤º: å¯ç é误] |
| | | L -->|æå| N[çæToken] |
| | | N --> O[ç»å½æå] |
| | | ``` |
| | | |
| | | ## æ¯æçææºå·æ ¼å¼ |
| | | |
| | | ç³»ç»æ¯æä¸å½å¤§é11使æºå·ï¼æ ¼å¼è§åï¼ |
| | | |
| | | | 使° | è§å | 说æ | |
| | | |------|------|------| |
| | | | 第1ä½ | å¿
é¡»æ¯ `1` | åºå® | |
| | | | 第2ä½ | `3-9` | è¿è¥åå·æ®µ | |
| | | | 第3-11ä½ | `0-9` | ä»»ææ°å | |
| | | |
| | | **ææç¤ºä¾**ï¼ |
| | | - â
`13812345678` |
| | | - â
`15987654321` |
| | | - â
`18666666666` |
| | | |
| | | **æ æç¤ºä¾**ï¼ |
| | | - â `12345678901` (第2ä½ä¸æ¯3-9) |
| | | - â `1381234567` (å°äº11ä½) |
| | | - â `138123456789` (å¤äº11ä½) |
| | | |
| | | ## 使ç¨ç¤ºä¾ |
| | | |
| | | ### åºæ¯1: ç¨æ·åç»å½ |
| | | |
| | | **è¾å
¥**: |
| | | ``` |
| | | ç¨æ·å: admin |
| | | å¯ç : admin123 |
| | | ``` |
| | | |
| | | **æµç¨**: |
| | | 1. è¾å
¥ `admin` ä¸ç¬¦åææºå·æ ¼å¼ |
| | | 2. ç³»ç»ä½¿ç¨ç¨æ·åæ¥è¯¢: `selectUserByUserName("admin")` |
| | | 3. éªè¯å¯ç |
| | | 4. ç»å½æå |
| | | |
| | | ### åºæ¯2: ææºå·ç»å½ |
| | | |
| | | **è¾å
¥**: |
| | | ``` |
| | | ææºå·: 13812345678 |
| | | å¯ç : admin123 |
| | | ``` |
| | | |
| | | **æµç¨**: |
| | | 1. è¾å
¥ `13812345678` ç¬¦åææºå·æ ¼å¼ |
| | | 2. ç³»ç»ä½¿ç¨ææºå·æ¥è¯¢: `selectUserByPhonenumber("13812345678")` |
| | | 3. éªè¯å¯ç |
| | | 4. ç»å½æå |
| | | |
| | | ## å端æ éä¿®æ¹ |
| | | |
| | | å端ç»å½çé¢**æ éä»»ä½ä¿®æ¹**ï¼åæçç¨æ·åè¾å
¥æ¡å¯ä»¥åæ¶æ¯æä¸¤ç§ç»å½æ¹å¼ï¼ |
| | | |
| | | ```vue |
| | | <!-- ç»å½è¡¨å --> |
| | | <el-form> |
| | | <el-form-item> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-input |
| | | v-model="loginForm.password" |
| | | type="password" |
| | | placeholder="请è¾å
¥å¯ç " |
| | | /> |
| | | </el-form-item> |
| | | </el-form> |
| | | ``` |
| | | |
| | | **æç¤ºä¼å建议**ï¼ |
| | | ```vue |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" <!-- â
ä¿®æ¹æç¤ºæå --> |
| | | /> |
| | | ``` |
| | | |
| | | ## å®å
¨æ§ä¿é |
| | | |
| | | ### 1. ææºå·å¯ä¸æ§ |
| | | |
| | | ç³»ç»ç¡®ä¿ææºå·å¨æ°æ®åºä¸çå¯ä¸æ§ï¼ |
| | | |
| | | ```java |
| | | @Override |
| | | public boolean checkPhoneUnique(SysUser user) |
| | | { |
| | | Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId(); |
| | | SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber()); |
| | | if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue()) |
| | | { |
| | | return UserConstants.NOT_UNIQUE; // ææºå·å·²åå¨ |
| | | } |
| | | return UserConstants.UNIQUE; |
| | | } |
| | | ``` |
| | | |
| | | **æ°æ®åºçº¦æ**ï¼ |
| | | ```sql |
| | | -- å»ºè®®å¨ sys_user 表ç phonenumber åæ®µä¸æ·»å å¯ä¸ç´¢å¼ |
| | | ALTER TABLE sys_user ADD UNIQUE INDEX idx_phonenumber (phonenumber); |
| | | ``` |
| | | |
| | | ### 2. å¯ç éªè¯ |
| | | |
| | | æ 论使ç¨ç¨æ·åè¿æ¯ææºå·ç»å½ï¼é½ä¼è¿è¡ç¸åçå¯ç éªè¯ï¼ |
| | | |
| | | ```java |
| | | passwordService.validate(user); |
| | | ``` |
| | | |
| | | **å¯ç éªè¯è§å**ï¼ |
| | | - â
BCryptå å¯éªè¯ |
| | | - â
ç»å½å¤±è´¥æ¬¡æ°éå¶ |
| | | - â
è´¦æ·é宿ºå¶ |
| | | |
| | | ### 3. ç¶ææ£æ¥ |
| | | |
| | | ç³»ç»ä¼æ£æ¥ç¨æ·è´¦æ·ç¶æï¼ |
| | | |
| | | | ç¶æ | æ£æ¥é¡¹ | å¤ç | |
| | | |------|--------|------| |
| | | | å·²å é¤ | `del_flag = '2'` | æç¤º"ç¨æ·å·²å é¤" | |
| | | | å·²åç¨ | `status = '1'` | æç¤º"ç¨æ·å·²åç¨" | |
| | | | æ£å¸¸ | `status = '0'` | å
许ç»å½ | |
| | | |
| | | ## æ¥å¿è®°å½ |
| | | |
| | | ç³»ç»ä¼è®°å½ç»å½æ¹å¼ï¼ä¾¿äºå®¡è®¡ï¼ |
| | | |
| | | ```java |
| | | // ææºå·ç»å½æ¥å¿ |
| | | log.info("å°è¯ä½¿ç¨ææºå·ç»å½ï¼{}", username); |
| | | |
| | | // ç¨æ·åç»å½æ¥å¿ |
| | | log.info("å°è¯ä½¿ç¨ç¨æ·åç»å½ï¼{}", username); |
| | | ``` |
| | | |
| | | **æ¥å¿ç¤ºä¾**ï¼ |
| | | ``` |
| | | 2025-10-26 10:30:15 INFO å°è¯ä½¿ç¨ææºå·ç»å½ï¼13812345678 |
| | | 2025-10-26 10:30:16 INFO ç»å½ç¨æ·ï¼13812345678 ç»å½æå |
| | | ``` |
| | | |
| | | ## æ°æ®åºè¡¨ç»æ |
| | | |
| | | ### sys_user 表ç¸å
³å段 |
| | | |
| | | | åæ®µå | ç±»å | 说æ | 约æ | |
| | | |--------|------|------|------| |
| | | | `user_id` | BIGINT | ç¨æ·ID | ä¸»é® | |
| | | | `user_name` | VARCHAR(30) | ç¨æ·å | å¯ä¸ | |
| | | | `phonenumber` | VARCHAR(11) | ææºå·ç | **建议å¯ä¸** | |
| | | | `password` | VARCHAR(100) | å¯ç | å¿
å¡« | |
| | | | `status` | CHAR(1) | ç¶æï¼0æ£å¸¸ 1åç¨ï¼ | é»è®¤0 | |
| | | | `del_flag` | CHAR(1) | å 餿 å¿ï¼0åå¨ 2å é¤ï¼ | é»è®¤0 | |
| | | |
| | | **建议SQL**ï¼ |
| | | ```sql |
| | | -- ä¸ºææºå·æ·»å å¯ä¸ç´¢å¼ï¼å¦æå°æªæ·»å ï¼ |
| | | ALTER TABLE sys_user |
| | | ADD UNIQUE INDEX uk_phonenumber (phonenumber) |
| | | COMMENT 'ææºå·å¯ä¸ç´¢å¼'; |
| | | ``` |
| | | |
| | | ## é误å¤ç |
| | | |
| | | ### 常è§é误åå¤ç |
| | | |
| | | | éè¯¯åºæ¯ | éè¯¯ä¿¡æ¯ | å¤çæ¹å¼ | |
| | | |---------|---------|---------| |
| | | | ç¨æ·ä¸åå¨ | "ç¨æ·ä¸åå¨" | æ£æ¥ç¨æ·å/ææºå·æ¯å¦æ£ç¡® | |
| | | | å¯ç é误 | "å¯ç é误" | éæ°è¾å
¥å¯ç | |
| | | | ç¨æ·å·²å é¤ | "ç¨æ·å·²å é¤" | è系管çåæ¢å¤ | |
| | | | ç¨æ·å·²åç¨ | "ç¨æ·å·²åç¨" | è系管çåå¯ç¨ | |
| | | | ææºå·éå¤ | "ææºå·å·²åå¨" | æ´æ¢ææºå· | |
| | | |
| | | ### å¼å¸¸ä»£ç ç¤ºä¾ |
| | | |
| | | ```java |
| | | // ç¨æ·ä¸åå¨ |
| | | if (StringUtils.isNull(user)) |
| | | { |
| | | log.info("ç»å½ç¨æ·ï¼{} ä¸åå¨.", username); |
| | | throw new ServiceException(MessageUtils.message("user.not.exists")); |
| | | } |
| | | |
| | | // ç¨æ·å·²å é¤ |
| | | else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) |
| | | { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被å é¤.", username); |
| | | throw new ServiceException(MessageUtils.message("user.password.delete")); |
| | | } |
| | | |
| | | // ç¨æ·å·²åç¨ |
| | | else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) |
| | | { |
| | | log.info("ç»å½ç¨æ·ï¼{} 已被åç¨.", username); |
| | | throw new ServiceException(MessageUtils.message("user.blocked")); |
| | | } |
| | | ``` |
| | | |
| | | ## æµè¯ç¨ä¾ |
| | | |
| | | ### æµè¯åºæ¯1: ç¨æ·åç»å½ |
| | | |
| | | **åç½®æ¡ä»¶**: |
| | | - ç¨æ·å: `admin` |
| | | - å¯ç : `admin123` |
| | | - ç¶æ: æ£å¸¸ |
| | | |
| | | **æµè¯æ¥éª¤**: |
| | | 1. è¾å
¥ç¨æ·å `admin` |
| | | 2. è¾å
¥å¯ç `admin123` |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **é¢æç»æ**: |
| | | - â
ç³»ç»è¯å«ä¸ºç¨æ·åç»å½ |
| | | - â
å¯ç éªè¯æå |
| | | - â
ç»å½æå并跳转å°é¦é¡µ |
| | | |
| | | ### æµè¯åºæ¯2: ææºå·ç»å½ |
| | | |
| | | **åç½®æ¡ä»¶**: |
| | | - ææºå·: `13812345678` |
| | | - å¯ç : `admin123` |
| | | - ç¶æ: æ£å¸¸ |
| | | |
| | | **æµè¯æ¥éª¤**: |
| | | 1. è¾å
¥ææºå· `13812345678` |
| | | 2. è¾å
¥å¯ç `admin123` |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **é¢æç»æ**: |
| | | - â
ç³»ç»è¯å«ä¸ºææºå·ç»å½ |
| | | - â
å¯ç éªè¯æå |
| | | - â
ç»å½æå并跳转å°é¦é¡µ |
| | | |
| | | ### æµè¯åºæ¯3: ææºå·ä¸åå¨ |
| | | |
| | | **æµè¯æ¥éª¤**: |
| | | 1. è¾å
¥ææºå· `19999999999` |
| | | 2. è¾å
¥å¯ç `123456` |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **é¢æç»æ**: |
| | | - â
æç¤º"ç¨æ·ä¸åå¨" |
| | | - â
æ æ³ç»å½ |
| | | |
| | | ### æµè¯åºæ¯4: å¯ç é误 |
| | | |
| | | **æµè¯æ¥éª¤**: |
| | | 1. è¾å
¥ææºå· `13812345678` |
| | | 2. è¾å
¥é误å¯ç `wrongpassword` |
| | | 3. ç¹å»ç»å½ |
| | | |
| | | **é¢æç»æ**: |
| | | - â
æç¤º"å¯ç é误" |
| | | - â
æ æ³ç»å½ |
| | | - â
ç»å½å¤±è´¥æ¬¡æ°+1 |
| | | |
| | | ## å
¼å®¹æ§è¯´æ |
| | | |
| | | ### ååå
¼å®¹ |
| | | |
| | | - â
åæç¨æ·åç»å½æ¹å¼å®å
¨ä¿ç |
| | | - â
æ éä¿®æ¹ç°æç¨æ·æ°æ® |
| | | - â
æ éä¿®æ¹å端代ç |
| | | - â
æ éä¿®æ¹APIæ¥å£ |
| | | |
| | | ### æ°æ§ç³»ç»å
±å |
| | | |
| | | | åè½ | æ§æ¹å¼ | æ°æ¹å¼ | å
¼å®¹æ§ | |
| | | |------|--------|--------|--------| |
| | | | ç»å½æ¹å¼ | ä»
ç¨æ·å | ç¨æ·å+ææºå· | â
å®å
¨å
¼å®¹ | |
| | | | å¯ç éªè¯ | BCrypt | BCrypt | â
ä¸è´ | |
| | | | Tokençæ | JWT | JWT | â
ä¸è´ | |
| | | | æééªè¯ | RBAC | RBAC | â
ä¸è´ | |
| | | |
| | | ## ä¼å¿ç¹ç¹ |
| | | |
| | | ### 1. ç¨æ·ä½éªä¼å |
| | | |
| | | - â
**æºè½è¯å«**: æ ééæ©ç»å½æ¹å¼ï¼ç³»ç»èªå¨è¯å« |
| | | - â
**æä½ç®ä¾¿**: ä¸ä¸ªè¾å
¥æ¡æ¯æä¸¤ç§æ¹å¼ |
| | | - â
**éä½è®°å¿è´æ
**: å¿è®°ç¨æ·åå¯ç¨ææºå· |
| | | |
| | | ### 2. ææ¯å®ç°ä¼é
|
| | | |
| | | - â
**æ ä¾µå
¥æ§**: 䏿¹ååææ¶æ |
| | | - â
**æ£åå¹é
**: 髿åç¡®è¯å« |
| | | - â
**æ¥å¿å®å**: 便äºé®é¢ææ¥ |
| | | |
| | | ### 3. å®å
¨æ§ä¿é |
| | | |
| | | - â
**ææºå·å¯ä¸**: 鲿¢è´¦å·å²çª |
| | | - â
**å¯ç éªè¯ä¸è´**: ç»ä¸å®å
¨æ å |
| | | - â
**ç¶ææ£æ¥å®æ´**: å¤ééªè¯æºå¶ |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | ### 1. æ·»å ææºå·å¯ä¸ç´¢å¼ |
| | | |
| | | ```sql |
| | | -- ç¡®ä¿ææºå·å¯ä¸æ§ |
| | | ALTER TABLE sys_user |
| | | ADD UNIQUE INDEX uk_phonenumber (phonenumber); |
| | | ``` |
| | | |
| | | ### 2. å端æç¤ºä¼å |
| | | |
| | | ```vue |
| | | <!-- ä¼åè¾å
¥æ¡æç¤º --> |
| | | <el-input |
| | | v-model="loginForm.username" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | prefix-icon="el-icon-user" |
| | | > |
| | | <template slot="prepend"> |
| | | <i class="el-icon-user"></i> |
| | | </template> |
| | | </el-input> |
| | | ``` |
| | | |
| | | ### 3. æ·»å ç»å½æ¹å¼ç»è®¡ |
| | | |
| | | ```java |
| | | // è®°å½ç»å½æ¹å¼ç»è®¡ |
| | | @Autowired |
| | | private LoginStatisticsService statisticsService; |
| | | |
| | | if (username.matches("^1[3-9]\\d{9}$")) |
| | | { |
| | | statisticsService.recordLoginMethod("PHONE"); |
| | | } |
| | | else |
| | | { |
| | | statisticsService.recordLoginMethod("USERNAME"); |
| | | } |
| | | ``` |
| | | |
| | | ### 4. æ¯ææ´å¤ç»å½æ¹å¼ |
| | | |
| | | æªæ¥å¯æ©å±æ¯æï¼ |
| | | - ð§ é®ç®±+å¯ç ç»å½ |
| | | - ð± ææºå·+éªè¯ç ç»å½ |
| | | - ð ç¬¬ä¸æ¹ç»å½ï¼å¾®ä¿¡ãééçï¼ |
| | | |
| | | ## ç¸å
³æä»¶ |
| | | |
| | | | æä»¶ç±»å | æä»¶è·¯å¾ | 说æ | |
| | | |---------|---------|------| |
| | | | è®¤è¯æå¡ | `ruoyi-framework/.../UserDetailsServiceImpl.java` | æ ¸å¿è®¤è¯é»è¾ | |
| | | | ç¨æ·æå¡æ¥å£ | `ruoyi-system/.../ISysUserService.java` | æå¡æ¥å£å®ä¹ | |
| | | | ç¨æ·æå¡å®ç° | `ruoyi-system/.../SysUserServiceImpl.java` | ä¸å¡é»è¾å®ç° | |
| | | | Mapperæ¥å£ | `ruoyi-system/.../SysUserMapper.java` | æ°æ®è®¿é®æ¥å£ | |
| | | | XMLæ å° | `ruoyi-system/.../SysUserMapper.xml` | SQLæ å°é
ç½® | |
| | | |
| | | ## 常è§é®é¢ |
| | | |
| | | ### Q1: ææºå·ç»å½æ¯å¦éè¦å端修æ¹ï¼ |
| | | |
| | | **A**: ä¸éè¦ãå端åªéå°åæ¥ç"请è¾å
¥ç¨æ·å"æç¤ºæ¹ä¸º"请è¾å
¥ç¨æ·åæææºå·"å³å¯ã |
| | | |
| | | ### Q2: ææºå·å¿
é¡»å¯ä¸åï¼ |
| | | |
| | | **A**: 建议å¯ä¸ãè½ç¶ç³»ç»å¯ä»¥å·¥ä½ï¼ä½ä¸ºäºé¿å
ç»å½å²çªï¼å¼ºç建议添å å¯ä¸ç´¢å¼ã |
| | | |
| | | ### Q3: å¦ä½ç¡®ä¿ææºå·å®å
¨ï¼ |
| | | |
| | | **A**: |
| | | - æ°æ®ä¼ è¾ä½¿ç¨HTTPSå å¯ |
| | | - å¯ç 使ç¨BCryptå å¯åå¨ |
| | | - 宿½ç»å½å¤±è´¥éå¶çç¥ |
| | | - æ·»å éªè¯ç 鲿¢æ´åç ´è§£ |
| | | |
| | | ### Q4: æ¯æå½é
ææºå·åï¼ |
| | | |
| | | **A**: å½åä»
æ¯æä¸å½å¤§é11使æºå·ãå¦éæ¯æå½é
å·ç ï¼éä¿®æ¹æ£å表达å¼ï¼ |
| | | ```java |
| | | // æ¯æå½é
ææºå·ï¼ç¤ºä¾ï¼ |
| | | if (username.matches("^\\+?[1-9]\\d{1,14}$")) |
| | | ``` |
| | | |
| | | ## æ»ç» |
| | | |
| | | ç³»ç»å·²å®æ´å®ç°**ç¨æ·å+å¯ç **å**ææºå·+å¯ç **两ç§ç»å½æ¹å¼ï¼éè¿æºè½è¯å«æºå¶èªå¨éæ©éªè¯æ¹å¼ï¼æ éå端é¢å¤é
ç½®ï¼å®å
¨ååå
¼å®¹ï¼ç¨æ·ä½éªä¼ç§ã |
| | | |
| | | **æ ¸å¿ç¹æ§**ï¼ |
| | | - â
èªå¨è¯å«ç»å½æ¹å¼ |
| | | - â
æ éä¿®æ¹å端代ç |
| | | - â
å®å
¨ååå
¼å®¹ |
| | | - â
å®å
¨æ§æä¿é |
| | | - â
æ¥å¿è®°å½å®å |
| | | |
| | | --- |
| | | |
| | | **ææ¡£çæ¬**: v1.0 |
| | | **å建æ¶é´**: 2025-10-26 |
| | | **ä½è
**: AI Assistant |
| | | **ç¶æ**: â
åè½å·²å®ç°å¹¶è¿è¡æ£å¸¸ |
| New file |
| | |
| | | # ç¨æ·å表æ¾ç¤ºä¼å说æ |
| | | |
| | | ## éæ±èæ¯ |
| | | |
| | | ç¨æ·è¦æ±ï¼ |
| | | 1. **ç¨æ·å表ä¸OAç¨æ·IDä¸è¦æ¾ç¤º** - è¯¥åæ®µåªå¨ä¿®æ¹ç¨æ·æ¶æ¾ç¤º |
| | | 2. **ç¨æ·åè¦æ¾ç¤ºå®æ´** - ç¡®ä¿ç¨æ·åä¸ä¼è¢«æªæ |
| | | |
| | | ## ä¿®æ¹å
容 |
| | | |
| | | ### æä»¶ï¼`ruoyi-ui/src/views/system/user/index.vue` |
| | | |
| | | #### 1. éèOAç¨æ·IDå |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```vue |
| | | <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | | <el-table-column label="ç¨æ·ç¼å·" align="center" key="userId" prop="userId" v-if="columns[0].visible" /> |
| | | |
| | | <!-- â æ¾ç¤ºOAç¨æ·IDå --> |
| | | <el-table-column label="OAç¨æ·ID" align="center" key="oaUserId" prop="oaUserId" v-if="columns[1].visible" width="120"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.oaUserId">{{ scope.row.oaUserId }}</span> |
| | | <span v-else style="color: #909399;">-</span> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" v-if="columns[2].visible" :show-overflow-tooltip="true" /> |
| | | </el-table> |
| | | ``` |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```vue |
| | | <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | | <el-table-column label="ç¨æ·ç¼å·" align="center" key="userId" prop="userId" v-if="columns[0].visible" /> |
| | | |
| | | <!-- â
OAç¨æ·IDåå·²éèï¼åªå¨ç¼è¾è¡¨å䏿¾ç¤º --> |
| | | |
| | | <!-- â
ç¨æ·åç§°å¢å 宽度ï¼ç¡®ä¿å®æ´æ¾ç¤º --> |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" v-if="columns[2].visible" width="150" /> |
| | | </el-table> |
| | | ``` |
| | | |
| | | #### 2. 设置OAç¨æ·IDåé»è®¤éè |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```javascript |
| | | // åä¿¡æ¯ |
| | | columns: [ |
| | | { key: 0, label: `ç¨æ·ç¼å·`, visible: true }, |
| | | { key: 1, label: `OAç¨æ·ID`, visible: true }, // â é»è®¤æ¾ç¤º |
| | | { key: 2, label: `ç¨æ·åç§°`, visible: true }, |
| | | // ... |
| | | ] |
| | | ``` |
| | | |
| | | **ä¿®æ¹å**ï¼ |
| | | ```javascript |
| | | // åä¿¡æ¯ï¼OAç¨æ·IDåé»è®¤éèï¼ |
| | | columns: [ |
| | | { key: 0, label: `ç¨æ·ç¼å·`, visible: true }, |
| | | { key: 1, label: `OAç¨æ·ID`, visible: false }, // â
é»è®¤éè |
| | | { key: 2, label: `ç¨æ·åç§°`, visible: true }, |
| | | // ... |
| | | ] |
| | | ``` |
| | | |
| | | #### 3. ä¼åç¨æ·åæ¾ç¤º |
| | | |
| | | **å
³é®æ¹å¨**ï¼ |
| | | - ç§»é¤ `:show-overflow-tooltip="true"` 屿§ |
| | | - æ·»å åºå®å®½åº¦ `width="150"` |
| | | - ç¡®ä¿ç¨æ·å宿´æ¾ç¤ºï¼ä¸è¢«çç¥ |
| | | |
| | | **对æ¯**ï¼ |
| | | ```vue |
| | | <!-- ä¿®æ¹åï¼ç¨æ·åå¯è½è¢«æªæ --> |
| | | <el-table-column label="ç¨æ·åç§°" :show-overflow-tooltip="true" /> |
| | | |
| | | <!-- ä¿®æ¹åï¼ç¨æ·å宿´æ¾ç¤º --> |
| | | <el-table-column label="ç¨æ·åç§°" width="150" /> |
| | | ``` |
| | | |
| | | ## ç颿æå¯¹æ¯ |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | | éæ© | ç¨æ·ç¼å· | OAç¨æ·ID | ç¨æ·åç§° | ç¨æ·æµç§° | é¨é¨ | ææºå·ç | ç¶æ | å建æ¶é´ | æä½ | |
| | | |------|---------|----------|---------|---------|------|---------|------|---------|------| |
| | | | âï¸ | 100 | 12345 | admin | 管çå | æ»å
¬å¸ | 138... | æ£å¸¸ | 2024-01-01 | ä¿®æ¹ å é¤ | |
| | | | â | 101 | 67890 | zhangsan | å¼ ä¸ | å¸åºé¨ | 139... | æ£å¸¸ | 2024-01-02 | ä¿®æ¹ å é¤ | |
| | | |
| | | **é®é¢**ï¼ |
| | | - â OAç¨æ·IDåå ç¨ç©ºé´ |
| | | - â ï¸ ç¨æ·åå¯è½è¢«æªææ¾ç¤ºä¸º "admin..." |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | | éæ© | ç¨æ·ç¼å· | ç¨æ·åç§° | ç¨æ·æµç§° | é¨é¨ | ææºå·ç | ç¶æ | å建æ¶é´ | æä½ | |
| | | |------|---------|---------|---------|------|---------|------|---------|------| |
| | | | âï¸ | 100 | admin | 管çå | æ»å
¬å¸ | 138... | æ£å¸¸ | 2024-01-01 | ä¿®æ¹ å é¤ | |
| | | | â | 101 | zhangsan | å¼ ä¸ | å¸åºé¨ | 139... | æ£å¸¸ | 2024-01-02 | ä¿®æ¹ å é¤ | |
| | | |
| | | **æ¹è¿**ï¼ |
| | | - â
OAç¨æ·IDåå·²éè |
| | | - â
ç¨æ·å宿´æ¾ç¤ºï¼150pxå®½åº¦ï¼ |
| | | - â
å表æ´ç®æ´æ¸
æ° |
| | | |
| | | ## OAç¨æ·IDå¨ç¼è¾è¡¨åä¸ä¿ç |
| | | |
| | | è½ç¶å表ä¸éèäºOAç¨æ·IDï¼ä½å¨**ä¿®æ¹ç¨æ·å¯¹è¯æ¡**ä¸ä»ç¶ä¿çè¯¥åæ®µï¼ |
| | | |
| | | ```vue |
| | | <!-- æ·»å æä¿®æ¹ç¨æ·é
ç½®å¯¹è¯æ¡ --> |
| | | <el-dialog :title="title" :visible.sync="open" width="600px"> |
| | | <el-form ref="form" :model="form" :rules="rules" label-width="80px"> |
| | | <!-- ... å
¶ä»å段 ... --> |
| | | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <!-- â
ç¼è¾è¡¨åä¸ä¿çOAç¨æ·IDåæ®µ --> |
| | | <el-form-item label="OAç¨æ·ID" prop="oaUserId"> |
| | | <el-input v-model="form.oaUserId" placeholder="OAç³»ç»çç¨æ·ID" type="number" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <!-- ... å
¶ä»å段 ... --> |
| | | </el-form> |
| | | </el-dialog> |
| | | ``` |
| | | |
| | | **使ç¨åºæ¯**ï¼ |
| | | - â
æ°å¢ç¨æ·æ¶å¯ä»¥è¾å
¥OAç¨æ·ID |
| | | - â
ä¿®æ¹ç¨æ·æ¶å¯ä»¥æ¥çåä¿®æ¹OAç¨æ·ID |
| | | - â
导å
¥å¯¼åºåè½ä»ç¶å
å«OAç¨æ·IDæ°æ® |
| | | |
| | | ## åæ¾ç¤ºæ§å¶åè½ |
| | | |
| | | ç¨æ·å¯ä»¥éè¿**å设置**åè½éæ°æ¾ç¤ºOAç¨æ·IDåï¼ |
| | | |
| | | ```vue |
| | | <!-- å³ä¾§å·¥å
·æ ä¸çå设置æé® --> |
| | | <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar> |
| | | ``` |
| | | |
| | | **æä½æ¥éª¤**ï¼ |
| | | 1. ç¹å»è¡¨æ ¼å³ä¸è§çåè®¾ç½®å¾æ |
| | | 2. å¨å¼¹åºçå表ä¸å¾é"OAç¨æ·ID" |
| | | 3. OAç¨æ·IDåä¼éæ°æ¾ç¤ºå¨åè¡¨ä¸ |
| | | |
| | | **é»è®¤é
ç½®**ï¼ |
| | | - OAç¨æ·IDï¼â é»è®¤ä¸æ¾ç¤º |
| | | - å
¶ä»åï¼â
é»è®¤å
¨é¨æ¾ç¤º |
| | | |
| | | ## 代ç åæ´ç»è®¡ |
| | | |
| | | | åæ´ç±»å | è¡æ° | 说æ | |
| | | |---------|------|------| |
| | | | å é¤è¡¨æ ¼å | -6 è¡ | å é¤OAç¨æ·IDåå®ä¹ | |
| | | | ä¿®æ¹åé
ç½® | 1 è¡ | 设置OAç¨æ·IDé»è®¤éè | |
| | | | ä¼åç¨æ·åå | 1 è¡ | å¢å 宽度ï¼ç§»é¤tooltip | |
| | | | **æ»è®¡** | **-4 è¡** | ä»£ç æ´ç®æ´ | |
| | | |
| | | ## ä¿®æ¹å½±åèå´ |
| | | |
| | | ### â
ä¸åå½±åçåè½ |
| | | |
| | | 1. **æ°æ®åå¨** |
| | | - OAç¨æ·IDåæ®µä»ç¶ä¿å卿°æ®åºä¸ |
| | | - æ°æ®å®æ´æ§ä¸åå½±å |
| | | |
| | | 2. **ç¼è¾åè½** |
| | | - æ°å¢ç¨æ·ï¼å¯ä»¥è¾å
¥OAç¨æ·ID |
| | | - ä¿®æ¹ç¨æ·ï¼å¯ä»¥æ¥çåä¿®æ¹OAç¨æ·ID |
| | | - ç¼è¾è¡¨åä¸è¯¥å段å®å
¨æ£å¸¸ |
| | | |
| | | 3. **导å
¥å¯¼åº** |
| | | - 导å
¥ï¼æ¯æå¯¼å
¥OAç¨æ·IDæ°æ® |
| | | - 导åºï¼å¯¼åºæä»¶å
å«OAç¨æ·ID |
| | | - 导å
¥æ¨¡æ¿ï¼å
å«OAç¨æ·IDåæ®µ |
| | | |
| | | 4. **APIæ¥å£** |
| | | - æ¥è¯¢æ¥å£ï¼è¿åæ°æ®å
å«oaUserId |
| | | - æ°å¢/ä¿®æ¹æ¥å£ï¼æ¥æ¶oaUserIdåæ° |
| | | - å端é»è¾æ éä¿®æ¹ |
| | | |
| | | ### â ï¸ åå½±åçé¨å |
| | | |
| | | 1. **å表æ¾ç¤º** |
| | | - OAç¨æ·IDé»è®¤ä¸å¨åè¡¨ä¸æ¾ç¤º |
| | | - å¯éè¿åè®¾ç½®éæ°æ¾ç¤º |
| | | |
| | | 2. **ç¨æ·åæ¾ç¤º** |
| | | - ä»çç¥æ¾ç¤ºæ¹ä¸ºå®æ´æ¾ç¤º |
| | | - å ç¨åºå®150px宽度 |
| | | |
| | | ## è¡¨æ ¼å宽度é
ç½® |
| | | |
| | | ä¿®æ¹åçå宽度åé
ï¼ |
| | | |
| | | | åå | 宽度 | 说æ | |
| | | |------|------|------| |
| | | | éæ©æ¡ | 50px | åºå®å®½åº¦ | |
| | | | ç¨æ·ç¼å· | èªéåº | - | |
| | | | **ç¨æ·åç§°** | **150px** | â
åºå®å®½åº¦ï¼ç¡®ä¿å®æ´æ¾ç¤º | |
| | | | ç¨æ·æµç§° | èªéåº | tooltipæ¾ç¤º | |
| | | | é¨é¨ | èªéåº | tooltipæ¾ç¤º | |
| | | | ææºå·ç | 120px | åºå®å®½åº¦ | |
| | | | ç¶æ | èªéåº | å¼å
³ç»ä»¶ | |
| | | | å建æ¶é´ | 160px | åºå®å®½åº¦ | |
| | | | æä½ | 160px | åºå®å®½åº¦ | |
| | | |
| | | ## ç¨æ·åç§°å®æ´æ¾ç¤ºçä¼å¿ |
| | | |
| | | ### 1. å¯è¯»æ§æ´å¥½ |
| | | ``` |
| | | â ä¿®æ¹åï¼adminuser123... ï¼è¢«æªæï¼ |
| | | â
ä¿®æ¹åï¼adminuser123456 ï¼å®æ´æ¾ç¤ºï¼ |
| | | ``` |
| | | |
| | | ### 2. 便äºè¯å« |
| | | - ç¨æ·åæ¯ç¨æ·çå¯ä¸æ è¯ |
| | | - 宿´æ¾ç¤ºæå©äºå¿«éè¯å«ååºåç¨æ· |
| | | |
| | | ### 3. åå°æä½ |
| | | - ä¸éè¦é¼ æ æ¬åæ¥çtooltip |
| | | - æé«æä½æç |
| | | |
| | | ## æµè¯æ£æ¥æ¸
å |
| | | |
| | | - [ ] ç¨æ·å表é»è®¤ä¸æ¾ç¤ºOAç¨æ·IDå |
| | | - [ ] ç¨æ·åç§°å®æ´æ¾ç¤ºï¼ä¸è¢«æªæ |
| | | - [ ] æ°å¢ç¨æ·å¯¹è¯æ¡ä¸æ¾ç¤ºOAç¨æ·IDè¾å
¥æ¡ |
| | | - [ ] ä¿®æ¹ç¨æ·å¯¹è¯æ¡ä¸æ¾ç¤ºOAç¨æ·IDè¾å
¥æ¡ |
| | | - [ ] å¯ä»¥éè¿åè®¾ç½®éæ°æ¾ç¤ºOAç¨æ·IDå |
| | | - [ ] 导å
¥å¯¼åºåè½æ£å¸¸ï¼å
å«OAç¨æ·ID |
| | | - [ ] è¡¨æ ¼å¸å±æ£å¸¸ï¼æ éä½ç°è±¡ |
| | | - [ ] å
¶ä»åæ¾ç¤ºæ£å¸¸ |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | ### 1. ååºå¼å宽 |
| | | ```javascript |
| | | // æ ¹æ®å±å¹å®½åº¦å¨æè°æ´ |
| | | computed: { |
| | | userNameWidth() { |
| | | return this.$store.getters.device === 'mobile' ? '100' : '150' |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ### 2. ç¨æ·åæ ¼å¼éªè¯ |
| | | ```javascript |
| | | // ç¡®ä¿ç¨æ·åä¸ä¼è¿é¿ |
| | | rules: { |
| | | userName: [ |
| | | { max: 20, message: 'ç¨æ·åç§°é¿åº¦ä¸è½è¶
è¿20个å符', trigger: 'blur' } |
| | | ] |
| | | } |
| | | ``` |
| | | |
| | | ### 3. åå®½åº¦è®°å¿ |
| | | ```javascript |
| | | // ä¿åç¨æ·èªå®ä¹çå宽度设置 |
| | | saveColumnWidth(column, width) { |
| | | localStorage.setItem(`column_${column.key}_width`, width) |
| | | } |
| | | ``` |
| | | |
| | | ## ç¸å
³æä»¶ |
| | | |
| | | - **ç¨æ·å表**: `ruoyi-ui/src/views/system/user/index.vue` |
| | | - **ç¨æ·API**: `ruoyi-ui/src/api/system/user.js` |
| | | - **ç¨æ·å®ä½**: `ruoyi-system/.../domain/SysUser.java` |
| | | |
| | | ## å
¼å®¹æ§è¯´æ |
| | | |
| | | ### æµè§å¨å
¼å®¹æ§ |
| | | - â
Chrome 60+ |
| | | - â
Firefox 55+ |
| | | - â
Safari 11+ |
| | | - â
Edge 79+ |
| | | |
| | | ### Element UIçæ¬ |
| | | - ä½¿ç¨ Element UI 2.x æ åAPI |
| | | - æ ç¹æ®å
¼å®¹æ§é®é¢ |
| | | |
| | | --- |
| | | |
| | | **ä¼åæ¶é´**: 2025-10-26 |
| | | **ä¼å人**: AI Assistant |
| | | **å½±åèå´**: ç¨æ·ç®¡çåè¡¨é¡µé¢ |
| | | **ç¶æ**: â
已宿 |
| New file |
| | |
| | | # ç§»é¤å¾®ä¿¡ç»å½åè½è¯´æ |
| | | |
| | | ## éæ±èæ¯ |
| | | |
| | | ç¨æ·è¦æ±ï¼åæ¶appç»å½çé¢ç微信ç»å½æé®ã |
| | | |
| | | ## ä¿®æ¹å
容 |
| | | |
| | | ### æä»¶ï¼`app/pages/login.vue` |
| | | |
| | | #### 1. å 餿¨¡æ¿ä¸ç微信ç»å½æé® |
| | | |
| | | **å é¤å**ï¼ |
| | | ```vue |
| | | <view class="action-btn"> |
| | | <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> |
| | | </view> |
| | | |
| | | <!-- â å 餿¤é¨å --> |
| | | <view class="wechat-login" @click="handleWechatLogin"> |
| | | <view class="wechat-btn"> |
| | | <image class="wechat-icon" src="/static/icons/profile.png"></image> |
| | | <text class="wechat-text">微信ä¸é®ç»å½</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="xieyi text-center"> |
| | | ``` |
| | | |
| | | **å é¤å**ï¼ |
| | | ```vue |
| | | <view class="action-btn"> |
| | | <button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">ç»å½</button> |
| | | </view> |
| | | |
| | | <!-- â
ç´æ¥æ¾ç¤ºç¨æ·åè®® --> |
| | | <view class="xieyi text-center"> |
| | | ``` |
| | | |
| | | #### 2. å é¤å¾®ä¿¡ç»å½æ¹æ³ |
| | | |
| | | **å é¤çæ¹æ³**ï¼ |
| | | ```javascript |
| | | // â å 餿¤æ¹æ³ |
| | | async handleWechatLogin() { |
| | | // #ifdef MP-WEIXIN |
| | | // 微信å°ç¨åºç»å½ |
| | | uni.login({ |
| | | provider: 'weixin', |
| | | success: (loginRes) => { |
| | | console.log('微信ç»å½æå', loginRes); |
| | | // è·åç¨æ·ä¿¡æ¯ |
| | | uni.getUserInfo({ |
| | | provider: 'weixin', |
| | | success: (infoRes) => { |
| | | console.log('ç¨æ·ä¿¡æ¯è·åæå', infoRes); |
| | | // 跳转å°å¾®ä¿¡ç»å½ç¡®è®¤é¡µé¢ |
| | | this.$tab.navigateTo(`/pages/login/wechat?userInfo=${encodeURIComponent(JSON.stringify(infoRes.userInfo))}`); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('è·åç¨æ·ä¿¡æ¯å¤±è´¥', error); |
| | | this.$modal.msgError("è·åå¾®ä¿¡ç¨æ·ä¿¡æ¯å¤±è´¥"); |
| | | } |
| | | }); |
| | | }, |
| | | fail: (error) => { |
| | | console.error('微信ç»å½å¤±è´¥', error); |
| | | this.$modal.msgError("微信ç»å½å¤±è´¥"); |
| | | } |
| | | }); |
| | | // #endif |
| | | |
| | | // #ifndef MP-WEIXIN |
| | | // H5æå
¶ä»å¹³å°æç¤º |
| | | this.$modal.msgError("请å¨å¾®ä¿¡å®¢æ·ç«¯ä¸ä½¿ç¨å¾®ä¿¡ç»å½åè½"); |
| | | // #endif |
| | | }, |
| | | ``` |
| | | |
| | | #### 3. å é¤å¾®ä¿¡ç»å½æé®æ ·å¼ |
| | | |
| | | **å é¤çæ ·å¼**ï¼ |
| | | ```scss |
| | | // â å 餿¤æ ·å¼ |
| | | .wechat-login { |
| | | margin: 20rpx 0; |
| | | |
| | | .wechat-btn { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #07c160; |
| | | height: 90rpx; |
| | | border-radius: 20px; |
| | | |
| | | .wechat-icon { |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | margin-right: 10rpx; |
| | | } |
| | | |
| | | .wechat-text { |
| | | color: white; |
| | | font-size: 32rpx; |
| | | } |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | ## ç颿æå¯¹æ¯ |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | ``` |
| | | ââââââââââââââââââââââââââââ |
| | | â [Logo] æ°èªè°åº¦ç³»ç» â |
| | | â â |
| | | â [ç¨æ·å¾æ ] 请è¾å
¥è´¦å· â |
| | | â [å¯ç 徿 ] 请è¾å
¥å¯ç â |
| | | â [éªè¯ç ] [å¾çéªè¯ç ] â |
| | | â â |
| | | â ââââââââââââââ â |
| | | â â ç»å½ â â |
| | | â ââââââââââââââ â |
| | | â ââââââââââââââ â â â å é¤å¾®ä¿¡ç»å½æé® |
| | | â â 微信ä¸é®ç»å½â â |
| | | â ââââââââââââââ â |
| | | â â |
| | | â ç»å½å³ä»£è¡¨åæãç¨æ·åè®®ãâ |
| | | â åãéç§åè®®ã â |
| | | ââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ### ä¿®æ¹å |
| | | |
| | | ``` |
| | | ââââââââââââââââââââââââââââ |
| | | â [Logo] æ°èªè°åº¦ç³»ç» â |
| | | â â |
| | | â [ç¨æ·å¾æ ] 请è¾å
¥è´¦å· â |
| | | â [å¯ç 徿 ] 请è¾å
¥å¯ç â |
| | | â [éªè¯ç ] [å¾çéªè¯ç ] â |
| | | â â |
| | | â ââââââââââââââ â |
| | | â â ç»å½ â â |
| | | â ââââââââââââââ â |
| | | â â â â
æ´ç®æ´ |
| | | â â |
| | | â ç»å½å³ä»£è¡¨åæãç¨æ·åè®®ãâ |
| | | â åãéç§åè®®ã â |
| | | ââââââââââââââââââââââââââââ |
| | | ``` |
| | | |
| | | ## 代ç åæ´ç»è®¡ |
| | | |
| | | | åæ´ç±»å | è¡æ° | |
| | | |---------|------| |
| | | | å 餿¨¡æ¿ä»£ç | -6 è¡ | |
| | | | å é¤JSæ¹æ³ | -37 è¡ | |
| | | | å 餿 ·å¼ä»£ç | -21 è¡ | |
| | | | **æ»è®¡** | **-64 è¡** | |
| | | |
| | | ## ä¿®æ¹å½±å |
| | | |
| | | ### â
æ£é¢å½±å |
| | | |
| | | 1. **ç颿´ç®æ´** |
| | | - ç§»é¤äºç»¿è²ç微信ç»å½æé® |
| | | - 页é¢è§è§æ´ç»ä¸ |
| | | |
| | | 2. **åå°ä»£ç å¤æåº¦** |
| | | - å é¤äºå¾®ä¿¡ç»å½ç¸å
³é»è¾ |
| | | - åå°äºå¹³å°å
¼å®¹æ§å¤ç代ç |
| | | |
| | | 3. **ç»ä¸ç»å½æ¹å¼** |
| | | - åªä¿çè´¦å·å¯ç ç»å½ |
| | | - 便äºç»ä¸ç®¡çåç»´æ¤ |
| | | |
| | | ### â ï¸ æ³¨æäºé¡¹ |
| | | |
| | | 1. **ç¨æ·ç»å½æ¹å¼** |
| | | - ç°å¨åªè½ä½¿ç¨è´¦å·å¯ç ç»å½ |
| | | - éè¦ç¡®ä¿ææç¨æ·é½æè´¦å· |
| | | |
| | | 2. **ç§»å¨ç«¯ä½éª** |
| | | - è´¦å·å¯ç è¾å
¥ç¸å¯¹ç¹ç |
| | | - 建议å¢å¼º"è®°ä½å¯ç "åè½ |
| | | |
| | | ## ä¿ççç»å½åè½ |
| | | |
| | | ### è´¦å·å¯ç ç»å½ |
| | | |
| | | **åè½ç»ä»¶**ï¼ |
| | | - â
ç¨æ·åè¾å
¥æ¡ |
| | | - â
å¯ç è¾å
¥æ¡ |
| | | - â
å¾å½¢éªè¯ç ï¼å¯é
ç½®ï¼ |
| | | - â
ç»å½æé® |
| | | |
| | | **å®å
¨æªæ½**ï¼ |
| | | - â
å¾å½¢éªè¯ç 鲿´åç ´è§£ |
| | | - â
å¯ç å å¯ä¼ è¾ |
| | | - â
Tokenè®¤è¯æºå¶ |
| | | |
| | | **ç¨æ·ä½éª**ï¼ |
| | | - â
ç¨æ·åè®®åéç§åè®®é¾æ¥ |
| | | - â
é误æç¤º |
| | | - â
å è½½ç¶ææ¾ç¤º |
| | | |
| | | ## ç»å½æµç¨ |
| | | |
| | | ``` |
| | | ç¨æ·æå¼ç»å½é¡µé¢ |
| | | â |
| | | è¾å
¥è´¦å·ãå¯ç ãéªè¯ç |
| | | â |
| | | ç¹å»"ç»å½"æé® |
| | | â |
| | | éªè¯è¡¨åè¾å
¥ |
| | | â |
| | | è°ç¨å¯ç ç»å½æ¥å£ |
| | | â |
| | | è·åTokenå¹¶åå¨ |
| | | â |
| | | è·åç¨æ·ä¿¡æ¯ |
| | | â |
| | | 跳转å°é¦é¡µ |
| | | ``` |
| | | |
| | | ## ç¸å
³æä»¶ |
| | | |
| | | - **ç»å½é¡µé¢**: `app/pages/login.vue` |
| | | - **ç»å½API**: `app/api/login.js` |
| | | - **ç¨æ·Store**: `app/store/modules/user.js` |
| | | |
| | | ## åç»ä¼å建议 |
| | | |
| | | 1. **å¢å¼ºå¯ç ç»å½ä½éª** |
| | | ```javascript |
| | | // 建议添å è®°ä½å¯ç åè½ |
| | | data() { |
| | | return { |
| | | rememberPassword: true, // è®°ä½å¯ç é项 |
| | | savedUsername: '', |
| | | savedPassword: '' |
| | | } |
| | | } |
| | | ``` |
| | | |
| | | 2. **æ·»å å¿«æ·ç»å½é项** |
| | | - å¯èèæ·»å ææºå·+éªè¯ç ç»å½ |
| | | - æ¯ææçº¹/é¢å®¹è¯å«ï¼ç§»å¨ç«¯ï¼ |
| | | |
| | | 3. **ä¼å表åéªè¯** |
| | | ```javascript |
| | | // 宿¶éªè¯è¾å
¥ |
| | | validateUsername() { |
| | | if (!/^[a-zA-Z0-9_]{4,16}$/.test(this.loginForm.username)) { |
| | | this.$modal.msgError('ç¨æ·åæ ¼å¼ä¸æ£ç¡®') |
| | | return false |
| | | } |
| | | return true |
| | | } |
| | | ``` |
| | | |
| | | ## æµè¯æ£æ¥æ¸
å |
| | | |
| | | - [ ] è´¦å·å¯ç ç»å½åè½æ£å¸¸ |
| | | - [ ] éªè¯ç æ¾ç¤ºåå·æ°æ£å¸¸ |
| | | - [ ] ç»å½æå跳转å°é¦é¡µ |
| | | - [ ] ç»å½å¤±è´¥æ¾ç¤ºé误æç¤º |
| | | - [ ] ç¨æ·åè®®åéç§åè®®é¾æ¥å¯ç¹å» |
| | | - [ ] 微信ç»å½æé®å·²å®å
¨ç§»é¤ |
| | | - [ ] çé¢å¸å±æ å¼å¸¸ |
| | | - [ ] æ ·å¼æ¾ç¤ºæ£å¸¸ |
| | | |
| | | ## é¨ç½²è¯´æ |
| | | |
| | | ### H5çæ¬ |
| | | ```bash |
| | | npm run build:h5 |
| | | ``` |
| | | |
| | | ### 微信å°ç¨åºçæ¬ |
| | | ```bash |
| | | npm run build:mp-weixin |
| | | ``` |
| | | |
| | | ### 注æäºé¡¹ |
| | | - æ¸
çæµè§å¨/å°ç¨åºç¼ååæµè¯ |
| | | - 确认微信ç»å½é¡µé¢è·¯ç±æ¯å¦éè¦æ¸
çï¼`/pages/login/wechat`ï¼ |
| | | |
| | | --- |
| | | |
| | | **ä¿®æ¹æ¶é´**: 2025-10-26 |
| | | **ä¿®æ¹äºº**: AI Assistant |
| | | **å½±åèå´**: ç»å½é¡µé¢ |
| | | **ç¶æ**: â
已宿 |
| | |
| | | min: |
| | | apiUrl: https://api.966120.com.cn/v1/ #æµè¯ç¯å¢ï¼localhost:8011 |
| | | qrcode: |
| | | defaultUrl: https://gzgj.966120.com.cn/evaluation?vehicle={vehicleNo} |
| | | defaultUrl: https://gzgj.966120.com.cn/evaluation?vehicle={vehicleNo} |
| | | wechat: |
| | | appId: wx70f6a7346ee842c0 |
| | | appSecret: 2d6c59de85e876b7eadebeba62e5417a |
| | | # è
¾è®¯å°å¾é
ç½® |
| | | tencent: |
| | | map: |
| | | key: 6YVBZ-ZJDLQ-JMY5F-BR7XG-H3TAV-C3FXC |
| | | # æ§ç³»ç»é
ç½® |
| | | legacy: |
| | | system: |
| | | # æ§ç³»ç»åºç¡URL (å¿
é¡»é
ç½®) |
| | | # 示ä¾: http://192.168.1.100:8080 æ http://legacy.yourdomain.com |
| | | base-url: https://sys.966120.com.cn |
| | | |
| | | # æ¥æè½¬è¿å建æ¥å£è·¯å¾ (å¯éï¼é»è®¤å¼å¦ä¸) |
| | | emergency-create-path: /admin_save_19.gds |
| | | |
| | | # HTTPè¿æ¥è¶
æ¶æ¶é´(毫ç§) (å¯éï¼é»è®¤30ç§) |
| | | connect-timeout: 30000 |
| | | |
| | | # HTTP读åè¶
æ¶æ¶é´(毫ç§) (å¯éï¼é»è®¤30ç§) |
| | | read-timeout: 30000 |
| | | |
| | | # æ¯å¦å¯ç¨åæ¥åè½ (å¯éï¼é»è®¤true) |
| | | # true: å¯ç¨åæ¥ false: ç¦ç¨åæ¥ |
| | | enabled: true |
| | | |
| | | # å符ç¼ç (å¯éï¼é»è®¤UTF-8) |
| | | charset: UTF-8 |
| | |
| | | appId: wx70f6a7346ee842c0 |
| | | appSecret: 2d6c59de85e876b7eadebeba62e5417a |
| | | redirectUri: http://yourdomain.com/evaluation |
| | | # å¼åç¯å¢é
ç½® |
| | | dev: |
| | | enabled: true # æ¯å¦å¯ç¨å¼åæ¨¡å¼ |
| | | mockUserInfo: true # æ¯å¦æ¨¡æç¨æ·ä¿¡æ¯ |
| | | ngrokUrl: http://your-ngrok-url.ngrok.io # å
ç½ç©¿éå°å |
| | | |
| | | # è
¾è®¯å°å¾é
ç½® |
| | | tencent: |
| | | map: |
| | |
| | | public SysUser selectUserByUserName(String userName); |
| | | |
| | | /** |
| | | * éè¿ææºå·ç æ¥è¯¢ç¨æ· |
| | | * @param phonenumber |
| | | * @return |
| | | */ |
| | | public SysUser selectUserByPhonenumber(String phonenumber); |
| | | |
| | | /** |
| | | * éè¿ç¨æ·IDæ¥è¯¢ç¨æ· |
| | | * |
| | | * @param userId ç¨æ·ID |
| | |
| | | @Override |
| | | public SysUser selectUserByPhonenumber(String phonenumber) |
| | | { |
| | | return userMapper.checkPhoneUnique(phonenumber); |
| | | return userMapper.selectUserByPhonenumber(phonenumber); |
| | | } |
| | | |
| | | /** |
| | |
| | | </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.oa_user_id, u.create_by, u.create_time, u.remark, |
| | | select u.user_id, u.dept_id, u.user_name,u.oa_user_id, 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.oa_user_id, 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 |
| | |
| | | <include refid="selectUserVo"/> |
| | | where u.user_name = #{userName} and u.del_flag = '0' |
| | | </select> |
| | | |
| | | <select id="selectUserByPhonenumber" parameterType="String" resultMap="SysUserResult"> |
| | | <include refid="selectUserVo"/> |
| | | where u.phonenumber = #{phonenumber} and u.del_flag = '0' |
| | | </select> |
| | | |
| | | <select id="selectUserById" parameterType="Long" resultMap="SysUserResult"> |
| | | <include refid="selectUserVo"/> |
| | | where u.user_id = #{userId} |
| | |
| | | v-model="loginForm.username" |
| | | type="text" |
| | | auto-complete="off" |
| | | placeholder="è´¦å·" |
| | | placeholder="请è¾å
¥ç¨æ·åæææºå·" |
| | | > |
| | | <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" /> |
| | | </el-input> |
| | |
| | | }, |
| | | loginRules: { |
| | | username: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çè´¦å·" } |
| | | { required: true, trigger: "blur", message: "请è¾å
¥ç¨æ·åæææºå·" } |
| | | ], |
| | | password: [ |
| | | { required: true, trigger: "blur", message: "请è¾å
¥æ¨çå¯ç " } |
| | |
| | | <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="50" align="center" /> |
| | | <el-table-column label="ç¨æ·ç¼å·" align="center" key="userId" prop="userId" v-if="columns[0].visible" /> |
| | | <el-table-column label="OAç¨æ·ID" align="center" key="oaUserId" prop="oaUserId" v-if="columns[1].visible" width="120"> |
| | | <template slot-scope="scope"> |
| | | <span v-if="scope.row.oaUserId">{{ scope.row.oaUserId }}</span> |
| | | <span v-else style="color: #909399;">-</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" v-if="columns[2].visible" :show-overflow-tooltip="true" /> |
| | | <!-- OAç¨æ·IDåå·²éèï¼åªå¨ç¼è¾è¡¨å䏿¾ç¤º --> |
| | | <el-table-column label="ç¨æ·åç§°" align="center" key="userName" prop="userName" v-if="columns[2].visible" width="150" /> |
| | | <el-table-column label="ç¨æ·æµç§°" align="center" key="nickName" prop="nickName" v-if="columns[3].visible" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="é¨é¨" align="center" key="deptName" prop="dept.deptName" v-if="columns[4].visible" :show-overflow-tooltip="true" /> |
| | | <el-table-column label="ææºå·ç " align="center" key="phonenumber" prop="phonenumber" v-if="columns[5].visible" width="120" /> |
| | |
| | | status: undefined, |
| | | deptId: undefined |
| | | }, |
| | | // åä¿¡æ¯ |
| | | // åä¿¡æ¯ï¼OAç¨æ·IDåé»è®¤éèï¼ |
| | | columns: [ |
| | | { key: 0, label: `ç¨æ·ç¼å·`, visible: true }, |
| | | { key: 1, label: `OAç¨æ·ID`, visible: true }, |
| | | { key: 1, label: `OAç¨æ·ID`, visible: false }, |
| | | { key: 2, label: `ç¨æ·åç§°`, visible: true }, |
| | | { key: 3, label: `ç¨æ·æµç§°`, visible: true }, |
| | | { key: 4, label: `é¨é¨`, visible: true }, |
| | |
| | | -- ---------------------------- |
| | | INSERT INTO sys_dict_type(dict_name, dict_type, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES('ä»»å¡ç±»å', 'sys_task_type', '0', 'admin', SYSDATE(), '', NULL, 'ä»»å¡ç±»åå表'); |
| | | INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES(1, '转è¿ä»»å¡', 'EMERGENCY_TRANSFER', 'sys_task_type', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, 'ç»´ä¿®ä¿å
»ä»»å¡'); |
| | | |
| | | INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES(1, 'ç»´ä¿®ä¿å
»', 'MAINTENANCE', 'sys_task_type', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, 'ç»´ä¿®ä¿å
»ä»»å¡'); |
| | | VALUES(2, 'ç»´ä¿®ä¿å
»', 'MAINTENANCE', 'sys_task_type', '', 'primary', 'N', '0', 'admin', SYSDATE(), '', NULL, 'ç»´ä¿®ä¿å
»ä»»å¡'); |
| | | |
| | | INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES(2, 'å æ²¹ä»»å¡', 'FUEL', 'sys_task_type', '', 'success', 'N', '0', 'admin', SYSDATE(), '', NULL, 'å æ²¹ä»»å¡'); |
| | | VALUES(3, 'å æ²¹ä»»å¡', 'FUEL', 'sys_task_type', '', 'success', 'N', '0', 'admin', SYSDATE(), '', NULL, 'å æ²¹ä»»å¡'); |
| | | |
| | | INSERT INTO sys_dict_data(dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, update_by, update_time, remark) |
| | | VALUES(3, 'å
¶ä»', 'OTHER', 'sys_task_type', '', 'info', 'N', '0', 'admin', SYSDATE(), '', NULL, 'å
¶ä»ç±»åä»»å¡'); |
| | | VALUES(4, 'å
¶ä»', 'OTHER', 'sys_task_type', '', 'info', 'N', '0', 'admin', SYSDATE(), '', NULL, 'å
¶ä»ç±»åä»»å¡'); |
| | | |
| | | -- 2. ä»»å¡ç¶æåå
¸ |
| | | -- ---------------------------- |