Commit e2e5221c9f8b6256a09ff5b14d93aff79e0a0bf5

Authored by 刘淇
1 parent 83673de2

验证码登录

api/user.js
... ... @@ -11,6 +11,14 @@ export const login = (params) => {
11 11 };
12 12  
13 13 /**
  14 + * 手机号验证码登录
  15 + * @returns {Promise}
  16 + */
  17 +export const smsLogin = (data) => {
  18 + return post('/admin-api/system/auth/sms-login',data)
  19 +}
  20 +
  21 +/**
14 22 * 获取用户信息
15 23 * @returns {Promise}
16 24 */
... ... @@ -68,6 +76,15 @@ export const getUnreadCount = () => {
68 76 }
69 77  
70 78  
  79 +/**
  80 + * 获取验证码
  81 + * @returns {Promise}
  82 + */
  83 +export const getSmsCode = (data) => {
  84 + return post('/admin-api/system/auth/send-sms-code',data)
  85 +}
  86 +
  87 +
71 88  
72 89  
73 90  
... ...
manifest.json
... ... @@ -54,7 +54,7 @@
54 54 },
55 55 /* 小程序特有相关 */
56 56 "mp-weixin" : {
57   - "appid" : "wxcb4cd34066b97d82",
  57 + "appid" : "wx64368a9b9e799172",
58 58 "setting" : {
59 59 "urlCheck" : false
60 60 },
... ...
pages/index/index.vue
... ... @@ -4,8 +4,8 @@
4 4 <view class="user-info-bar">
5 5 <view class="user-info">
6 6 <view class="user-text">
7   - <view class="username">你好{{ userName }},欢迎登录</view>
8   - <view class="login-desc">蓟城山水智慧园林养护平台</view>
  7 + <view class="username">你好{{ userName }}</view>
  8 + <view class="login-desc">蓟城山水全域智能运营管理平台</view>
9 9 </view>
10 10 </view>
11 11 <view class="msg-icon" @click="handleMsgClick" hover-class="msg-icon--hover">
... ...
pages/login/index.vue
... ... @@ -2,29 +2,20 @@
2 2 <view class="page-container">
3 3 <!-- 顶部标题区 -->
4 4 <view class="top-title">
5   - <text class="welcome-text">你好,欢迎光临</text>
6   -<!-- <text class="platform-name">全域智能运营管理平台</text>-->
7   - <text class="platform-name">蓟城山水智慧园林养护平台</text>
8   -
  5 + <text class="welcome-text">你好,欢迎登录</text>
  6 + <text class="platform-name">蓟城山水全域智能运营管理平台</text>
9 7 </view>
10 8  
11 9 <!-- 登录表单区域 -->
12 10 <view class="login-form">
13   - <!-- uview-plus的Tabs组件 -->
  11 + <!-- 登录方式切换 -->
14 12 <up-tabs
15 13 :list="tabList"
16 14 line-width="55"
17 15 line-height="2"
18 16 @change="handleTabChange"
19   - :activeStyle="{
20   - color: '#3c9cff',
21   - fontWeight:'500',
22   - fontSize: '14px' // 补充单位,避免样式异常
23   - }"
24   - :inactiveStyle="{
25   - color: '#606060',
26   - fontSize: '14px' // 补充单位,避免样式异常
27   - }"
  17 + :activeStyle="{ color: '#3c9cff', fontWeight:'500', fontSize: '14px' }"
  18 + :inactiveStyle="{ color: '#606060', fontSize: '14px' }"
28 19 ></up-tabs>
29 20  
30 21 <!-- 表单校验容器 -->
... ... @@ -34,71 +25,100 @@
34 25 ref="loginFormRef"
35 26 labelWidth="0"
36 27 >
37   - <!-- 手机号输入框 -->
38   - <up-form-item v-if="loginType === '手机号登录'" prop="mobile">
39   - <up-input
40   - v-model="form.mobile"
41   - border="surround"
42   - clearable
43   - maxlength="11"
44   - input-align="left"
45   - fontSize="14px"
46   - :disabled="isLoading"
47   - shape="circle"
48   - placeholder="请输入手机号"
49   - @blur="() => loginFormRef.validateField('mobile')"
50   - />
51   - </up-form-item>
52   -
53   - <!-- 账号输入框 -->
54   - <up-form-item v-else prop="account">
55   - <up-input
56   - v-model="form.account"
57   - border="surround"
58   - clearable
59   - maxlength="30"
60   - input-align="left"
61   - fontSize="14px"
62   - :disabled="isLoading"
63   - shape="circle"
64   - placeholder="请输入账户"
65   - @blur="() => loginFormRef.validateField('account')"
66   - />
67   - </up-form-item>
68   -
69   - <!-- 密码输入框 -->
70   - <up-form-item
71   - prop="password"
72   - class="password-item"
73   - >
74   - <up-input
75   - v-model="form.password"
76   - placeholder="请输入密码"
77   - maxlength="20"
78   - border="surround"
79   - clearable
80   - input-align="left"
81   - type="password"
82   - :disabled="isLoading"
83   - shape="circle"
84   - @blur="() => loginFormRef.validateField('password')"
85   - />
86   - </up-form-item>
87   -
88   - <!-- 记住密码单独一行,居右显示 -->
89   - <view class="remember-wrap">
90   - <up-checkbox
91   - :customStyle="{marginBottom: '8px'}"
92   - label="记住密码"
93   - name="agree"
94   - size="14"
95   - iconSize="14"
96   - labelSize="14"
97   - labelColor="'#3F3F3F'"
98   - usedAlone
99   - v-model:checked="rememberPwd"
100   - >
101   - </up-checkbox>
  28 + <!-- ========== 手机号登录区域 ========== -->
  29 + <view v-if="loginType === '手机号登录'">
  30 + <!-- 手机号输入框 -->
  31 + <up-form-item prop="mobile">
  32 + <up-input
  33 + v-model="form.mobile"
  34 + border="surround"
  35 + maxlength="11"
  36 + input-align="left"
  37 + fontSize="14px"
  38 + :disabled="isLoading"
  39 + shape="circle"
  40 + placeholder="请输入手机号"
  41 + @blur="() => loginFormRef.validateField('mobile')"
  42 + />
  43 + </up-form-item>
  44 +
  45 + <!-- 验证码输入框 + 自定义倒计时按钮 -->
  46 + <up-form-item prop="code">
  47 + <up-input
  48 + v-model="form.code"
  49 + border="surround"
  50 + maxlength="4"
  51 + type="number"
  52 + input-align="left"
  53 + fontSize="14px"
  54 + :disabled="isLoading"
  55 + shape="circle"
  56 + placeholder="请输入验证码"
  57 + @blur="() => loginFormRef.validateField('code')"
  58 + >
  59 + <template #suffix>
  60 + <up-button
  61 + size="mini"
  62 + type="primary"
  63 + :disabled="isCodeBtnDisabled"
  64 + :loading="isCodeLoading"
  65 + @tap="getVerificationCode"
  66 + shape="circle"
  67 + >
  68 + {{ countdown > 0 ? `${countdown}秒后重新获取` : '获取验证码' }}
  69 + </up-button>
  70 + </template>
  71 + </up-input>
  72 + </up-form-item>
  73 + </view>
  74 +
  75 + <!-- ========== 账号登录区域 ========== -->
  76 + <view v-else>
  77 + <!-- 账号输入框 -->
  78 + <up-form-item prop="account">
  79 + <up-input
  80 + v-model="form.account"
  81 + border="surround"
  82 + maxlength="30"
  83 + input-align="left"
  84 + fontSize="14px"
  85 + :disabled="isLoading"
  86 + shape="circle"
  87 + placeholder="请输入账户"
  88 + @blur="() => loginFormRef.validateField('account')"
  89 + />
  90 + </up-form-item>
  91 +
  92 + <!-- 密码输入框 -->
  93 + <up-form-item prop="password" class="password-item">
  94 + <up-input
  95 + v-model="form.password"
  96 + placeholder="请输入密码"
  97 + maxlength="20"
  98 + border="surround"
  99 + input-align="left"
  100 + type="password"
  101 + :disabled="isLoading"
  102 + shape="circle"
  103 + @blur="() => loginFormRef.validateField('password')"
  104 + />
  105 + </up-form-item>
  106 +
  107 + <!-- 记住密码 -->
  108 + <view class="remember-wrap">
  109 + <up-checkbox
  110 + :customStyle="{marginBottom: '8px'}"
  111 + label="记住密码"
  112 + name="agree"
  113 + size="14"
  114 + iconSize="14"
  115 + labelSize="14"
  116 + labelColor="#3F3F3F"
  117 + usedAlone
  118 + v-model:checked="rememberPwd"
  119 + >
  120 + </up-checkbox>
  121 + </view>
102 122 </view>
103 123 </up-form>
104 124  
... ... @@ -121,10 +141,12 @@
121 141 </template>
122 142  
123 143 <script setup>
124   -import { ref, reactive, onMounted, nextTick } from 'vue';
  144 +import { ref, reactive, onMounted, nextTick, computed, onUnmounted} from 'vue';
  145 +import {onShow} from '@dcloudio/uni-app'
125 146 import { useUserStore } from '@/pinia/user';
126 147 import globalConfig from '@/common/config/global';
127 148 import CryptoJS from 'crypto-js';
  149 +import { getSmsCode } from "@/api/user";
128 150  
129 151 // ========== 加密工具函数 ==========
130 152 const CRYPTO_CONFIG = {
... ... @@ -163,26 +185,101 @@ const aesDecrypt = (encryptedText) =&gt; {
163 185 }
164 186 };
165 187  
166   -// ========== 业务逻辑 ==========
  188 +// ========== 核心业务逻辑 ==========
167 189 const userStore = useUserStore();
168 190 const loginFormRef = ref(null);
169 191 const isLoading = ref(false);
  192 +const isCodeLoading = ref(false); // 验证码按钮独立loading状态
170 193  
171   -// Tabs配置
172   -const tabList = ref([
173   - { name: '手机号登录' },
174   - { name: '账号登录' }
175   -]);
  194 +// 登录方式切换
  195 +const tabList = ref([{ name: '手机号登录' }, { name: '账号登录' }]);
176 196 const loginType = ref('手机号登录');
177 197  
178   -// 记住密码
  198 +// 记住密码(仅账号登录生效)
179 199 const rememberPwd = ref(true);
180 200  
181 201 // 表单数据
182 202 const form = reactive({
183 203 account: '', // 账号
184 204 mobile: '', // 手机号
185   - password: '' // 密码
  205 + password: '', // 密码
  206 + code: '' // 验证码
  207 +});
  208 +
  209 +// 验证码倒计时相关
  210 +const countdown = ref(0);
  211 +let countdownTimer = null; // 倒计时定时器
  212 +
  213 +// 临时缓存KEY
  214 +const TEMP_FORM_KEY = 'login_temp_form_data';
  215 +
  216 +// ========== 方案二核心:保存/恢复表单数据 ==========
  217 +// 保存表单数据到本地缓存
  218 +const saveFormData = () => {
  219 + try {
  220 + const tempData = {
  221 + form: { ...form },
  222 + loginType: loginType.value,
  223 + countdown: countdown.value,
  224 + rememberPwd: rememberPwd.value
  225 + };
  226 + // 加密存储,提升安全性
  227 + const encryptData = aesEncrypt(JSON.stringify(tempData));
  228 + uni.setStorageSync(TEMP_FORM_KEY, encryptData);
  229 + } catch (err) {
  230 + console.warn('保存表单数据失败:', err);
  231 + }
  232 +};
  233 +
  234 +// 从本地缓存恢复表单数据
  235 +const restoreFormData = () => {
  236 + try {
  237 + const encryptData = uni.getStorageSync(TEMP_FORM_KEY);
  238 + if (!encryptData) return;
  239 +
  240 + const tempData = JSON.parse(aesDecrypt(encryptData));
  241 + // 恢复表单数据
  242 + if (tempData.form) {
  243 + Object.assign(form, tempData.form);
  244 + }
  245 + // 恢复登录类型
  246 + // if (tempData.loginType) {
  247 + // loginType.value = tempData.loginType;
  248 + // }
  249 + // 恢复记住密码状态
  250 + if (tempData.rememberPwd !== undefined) {
  251 + rememberPwd.value = tempData.rememberPwd;
  252 + }
  253 + // 恢复倒计时
  254 + if (tempData.countdown && tempData.countdown > 0) {
  255 + countdown.value = tempData.countdown;
  256 + // 重启倒计时定时器
  257 + startCountdown(countdown.value);
  258 + }
  259 +
  260 + // 恢复记住密码的缓存数据(原有逻辑)
  261 + if (rememberPwd.value && loginType.value === '账号登录') {
  262 + const savedAccount = aesDecrypt(uni.getStorageSync('login_account') || '');
  263 + const savedPwd = aesDecrypt(uni.getStorageSync('login_password') || '');
  264 + if (savedAccount) {
  265 + form.account = savedAccount;
  266 + form.password = savedPwd;
  267 + }
  268 + }
  269 + } catch (err) {
  270 + console.warn('恢复表单数据失败:', err);
  271 + }
  272 +};
  273 +
  274 +// 校验手机号格式
  275 +const isMobileValid = computed(() => {
  276 + const mobileReg = /^1[3-9]\d{9}$/;
  277 + return mobileReg.test(form.mobile);
  278 +});
  279 +
  280 +// 统一计算验证码按钮禁用状态
  281 +const isCodeBtnDisabled = computed(() => {
  282 + return countdown.value > 0 || isLoading.value || isCodeLoading.value || !isMobileValid.value;
186 283 });
187 284  
188 285 // 表单校验规则
... ... @@ -198,20 +295,81 @@ const loginFormRules = reactive({
198 295 password: [
199 296 { type: 'string', required: true, message: '请输入登录密码', trigger: ['change', 'blur'] },
200 297 { type: 'string', min: 3, max: 20, message: '密码长度为3-20个字符', trigger: ['change', 'blur'] }
  298 + ],
  299 + code: [
  300 + { type: 'string', required: true, message: '请输入验证码', trigger: ['change', 'blur'] },
  301 + { type: 'string', len: 4, message: '验证码长度4位', trigger: ['change', 'blur'] }
201 302 ]
202 303 });
203 304  
204   -// Tabs切换事件:移除清空输入框的逻辑
  305 +// 切换登录方式
205 306 const handleTabChange = ({ name }) => {
206 307 if (isLoading.value) return;
207   - console.log('切换到:', name);
  308 +
208 309 loginType.value = name;
209   - // 只清空校验状态,不清除输入框内容
  310 + // 清空校验状态和无关输入框
210 311 nextTick(() => {
211 312 loginFormRef.value?.clearValidate();
212 313 });
213 314 };
214 315  
  316 +// 开始验证码倒计时
  317 +const startCountdown = (seconds = 60) => {
  318 + countdown.value = seconds;
  319 +
  320 + // 清除已有定时器,避免重复
  321 + if (countdownTimer) clearInterval(countdownTimer);
  322 +
  323 + countdownTimer = setInterval(() => {
  324 + if (countdown.value <= 0) {
  325 + clearCountdown();
  326 + return;
  327 + }
  328 + countdown.value--;
  329 + }, 1000);
  330 +};
  331 +
  332 +// 清除倒计时
  333 +const clearCountdown = () => {
  334 + countdown.value = 0;
  335 + if (countdownTimer) {
  336 + clearInterval(countdownTimer);
  337 + countdownTimer = null;
  338 + }
  339 +};
  340 +
  341 +// 获取验证码
  342 +const getVerificationCode = async () => {
  343 + // 双重校验:按钮禁用状态
  344 + if (isCodeBtnDisabled.value) {
  345 + console.warn('验证码按钮已禁用,不执行请求');
  346 + return;
  347 + }
  348 +
  349 + try {
  350 + isCodeLoading.value = true; // 按钮进入loading
  351 + uni.showLoading({ title: '发送验证码中...', mask: true }); // 遮罩防止重复点击
  352 +
  353 + const postData = {
  354 + mobile: form.mobile,
  355 + scene: 21
  356 + };
  357 + // 调用验证码接口
  358 + const res = await getSmsCode(postData);
  359 +
  360 + uni.hideLoading();
  361 + uni.$u.toast('验证码已发送,请注意查收');
  362 + startCountdown(); // 仅接口成功时开始倒计时
  363 + } catch (err) {
  364 + // 捕获接口异常
  365 + uni.hideLoading();
  366 + console.error('获取验证码失败:', err);
  367 + uni.$u.toast(err.msg || '发送验证码失败,请重试');
  368 + } finally {
  369 + isCodeLoading.value = false; // 结束loading状态
  370 + }
  371 +};
  372 +
215 373 // 检查登录状态
216 374 const checkLoginStatus = () => {
217 375 try {
... ... @@ -226,45 +384,56 @@ const checkLoginStatus = () =&gt; {
226 384 }
227 385 };
228 386  
229   -// 登录方法
  387 +// 登录处理
230 388 const handleLogin = async () => {
231 389 try {
232   - await loginFormRef.value.validate();
  390 + // 根据登录类型校验对应字段
  391 + const validateFields = loginType.value === '手机号登录'
  392 + ? ['mobile', 'code']
  393 + : ['account', 'password'];
  394 +
  395 + // 执行表单校验
  396 + const validateRes = await loginFormRef.value.validate(validateFields);
  397 + if (!validateRes) {
  398 + return;
  399 + }
  400 +
233 401 isLoading.value = true;
234 402  
235 403 // 组装登录参数
236   - const loginParams = { password: form.password };
  404 + const loginParams = {};
237 405 if (loginType.value === '手机号登录') {
238   - loginParams.username = form.mobile;
  406 + loginParams.mobile = form.mobile;
  407 + loginParams.code = form.code;
  408 + loginParams.type = 'sms';
239 409 } else {
240 410 loginParams.username = form.account;
  411 + loginParams.password = form.password;
  412 + loginParams.type = 'password';
241 413 }
242 414  
243 415 // 执行登录
244 416 await userStore.login(loginParams);
245 417  
246   - // 保存数据:账号/密码 均用AES加密
247   - if (rememberPwd.value) {
  418 + // 保存登录信息(仅账号登录且勾选记住密码)
  419 + if (loginType.value === '账号登录' && rememberPwd.value) {
248 420 try {
249   - console.log('123+'+loginType.value)
250   - if (loginType.value === '手机号登录') {
251   - uni.setStorageSync('login_mobile', aesEncrypt(form.mobile));
252   - uni.removeStorageSync('login_account'); // 确保只存一种类型
253   - } else {
254   - uni.setStorageSync('login_account', aesEncrypt(form.account));
255   - uni.removeStorageSync('login_mobile'); // 确保只存一种类型
256   - }
  421 + uni.setStorageSync('login_account', aesEncrypt(form.account));
257 422 uni.setStorageSync('login_password', aesEncrypt(form.password));
  423 + uni.removeStorageSync('login_mobile');
258 424 } catch (err) {
259 425 console.warn('保存登录信息失败:', err);
260 426 }
261 427 } else {
262   - // 清除所有缓存
  428 + // 清除缓存
263 429 uni.removeStorageSync('login_account');
264 430 uni.removeStorageSync('login_mobile');
265 431 uni.removeStorageSync('login_password');
266 432 }
267 433  
  434 + // 登录成功后清除临时表单缓存
  435 + uni.removeStorageSync(TEMP_FORM_KEY);
  436 +
268 437 // 登录成功跳转
269 438 uni.showToast({ title: '登录成功', icon: 'success', duration: 1000 });
270 439 setTimeout(() => {
... ... @@ -274,58 +443,50 @@ const handleLogin = async () =&gt; {
274 443 });
275 444 }, 1000);
276 445 } catch (err) {
277   - if (!Array.isArray(err)) {
278   - console.error('登录失败:', err);
279   - uni.showToast({
280   - title: err.msg || '账号或密码错误,请重试',
281   - icon: 'none',
282   - duration: 1000
283   - });
284   - }
  446 + console.error('登录失败:', err);
  447 + uni.showToast({
  448 + title: err.msg || (loginType.value === '手机号登录' ? '验证码错误' : '账号或密码错误'),
  449 + icon: 'none',
  450 + duration: 1000
  451 + });
285 452 } finally {
286 453 isLoading.value = false;
287 454 }
288 455 };
289 456  
290   -// 生命周期
  457 +// ========== 小程序生命周期适配(方案二核心) ==========
  458 +// 页面显示时(切回页面)恢复数据
  459 +onShow(() => {
  460 + restoreFormData();
  461 +});
  462 +
  463 +// 页面卸载时保存数据
  464 +onUnmounted(() => {
  465 + clearCountdown();
  466 + saveFormData();
  467 +});
  468 +
  469 +// 页面挂载时初始化
291 470 onMounted(() => {
292 471 checkLoginStatus();
  472 +
293 473 // 初始化表单规则
294 474 nextTick(() => {
295 475 loginFormRef.value?.setRules(loginFormRules);
  476 + // 首次挂载也恢复一次数据
  477 + restoreFormData();
296 478 });
297   - // 读取缓存并解密填充:修复逻辑漏洞,确保只填充当前登录类型的输入框
298   - if (rememberPwd.value) {
299   - try {
300   - const savedAccount = aesDecrypt(uni.getStorageSync('login_account') || '');
301   - const savedMobile = aesDecrypt(uni.getStorageSync('login_mobile') || '');
302   - const savedPwd = aesDecrypt(uni.getStorageSync('login_password') || '');
303   -
304   - // 核心修正:只填充对应类型的输入框,另一类置空
305   - if (savedAccount) {
306   - form.account = savedAccount;
307   - form.mobile = ''; // 清空手机号输入框
308   - // loginType.value = '账号登录';
309   - } else if (savedMobile) {
310   - form.mobile = savedMobile;
311   - form.account = ''; // 清空账号输入框
312   - // loginType.value = '手机号登录';
313   - }
314   - form.password = savedPwd;
315   - } catch (err) {
316   - console.warn('读取缓存失败:', err);
317   - }
318   - }
319 479 });
320 480 </script>
321 481  
322 482 <style scoped lang="scss">
323   -.page-container{
324   - height:100vh;
  483 +.page-container {
  484 + height: 100vh;
325 485 background: url("https://img.jichengshanshui.com.cn:28207/appimg/loginbg.jpg") no-repeat;
326 486 background-position: bottom center;
327 487 background-size: 100% 240px;
328 488 }
  489 +
329 490 .top-title {
330 491 background: url("https://img.jichengshanshui.com.cn:28207/appimg/bg.jpg") no-repeat;
331 492 background-size: 100% 100%;
... ... @@ -361,9 +522,11 @@ onMounted(() =&gt; {
361 522  
362 523 :deep(.u-tabs) {
363 524 margin-bottom: 15px;
  525 +
364 526 .u-tabs__content {
365 527 height: auto !important;
366 528 }
  529 +
367 530 .u-tab-item {
368 531 padding: 0 10px;
369 532 }
... ... @@ -415,4 +578,15 @@ onMounted(() =&gt; {
415 578 position: fixed;
416 579 bottom: 60px;
417 580 }
  581 +
  582 +// 验证码按钮样式优化
  583 +:deep(.u-input__suffix) {
  584 + padding-right: 10rpx;
  585 +}
  586 +
  587 +:deep(.u-button--mini) {
  588 + height: 60rpx;
  589 + line-height: 60rpx;
  590 + padding: 0 15rpx;
  591 +}
418 592 </style>
419 593 \ No newline at end of file
... ...
pages/workbench/index.vue
... ... @@ -10,8 +10,8 @@
10 10  
11 11 <!-- 蓝色装饰块 -->
12 12 <view class="blue-decor-block" v-show="!loading">
13   - <text class="welcome-text u-line-1">你好{{ userInfo?.user?.nickname || '' }},欢迎登录</text>
14   - <text class="platform-name">蓟城山水智慧园林养护平台</text>
  13 + <text class="welcome-text u-line-1">你好{{ userInfo?.user?.nickname || '' }}</text>
  14 + <text class="platform-name">蓟城山水全域智能运营管理平台</text>
15 15 </view>
16 16  
17 17 <!-- 内容容器 -->
... ...
pinia/user.js
... ... @@ -2,7 +2,7 @@ import { defineStore } from &#39;pinia&#39;;
2 2 import cache from '@/common/utils/cache';
3 3 import globalConfig from '@/common/config/global';
4 4 // 新增:导入 refreshToken 接口
5   -import { login, getUserInfo, logout, moduleList, getSimpleDictDataList, refreshToken } from '@/api/user';
  5 +import { login,smsLogin, getUserInfo, logout, moduleList, getSimpleDictDataList, refreshToken } from '@/api/user';
6 6  
7 7 // 新增:定义刷新Token的定时器标识(避免重复创建定时器)
8 8 let refreshTokenTimer = null;
... ... @@ -41,7 +41,14 @@ export const useUserStore = defineStore(&#39;user&#39;, {
41 41 actions: {
42 42 async login(params) {
43 43 try {
44   - const res = await login(params);
  44 + // smsLogin
  45 + let res
  46 + if(params.type=='sms'){
  47 + res = await smsLogin(params);
  48 + }else{
  49 + res = await login(params);
  50 + }
  51 +
45 52 // 新增:从登录接口返回值中获取 refreshToken(若接口返回字段名不一致,可调整,如 res.refresh_token)
46 53 const { accessToken, expiresTime, userId, refreshToken } = res;
47 54  
... ...