Files
prop-ai-hr/mobile-uni/src/pages/auth/login/index.vue
T

160 lines
3.8 KiB
Vue

<template>
<view class="page login-page">
<view class="login-head">
<text class="page-title">银城员工端</text>
<text class="page-subtitle">使用手机号登录后,回到当前任务。</text>
</view>
<view class="panel login-card">
<text class="panel-title">手机号登录</text>
<input
v-model="phone"
class="input"
type="number"
maxlength="11"
placeholder="请输入手机号"
/>
<view class="inline-actions">
<input
v-model="smsCode"
class="input code-input"
type="number"
maxlength="6"
placeholder="验证码"
/>
<button class="secondary-button code-button" :disabled="sending" @click="sendCode">
{{ sending ? '发送中' : '发验证码' }}
</button>
</view>
<button class="primary-button" :disabled="loggingIn" @click="login">
{{ loggingIn ? '登录中' : '登录' }}
</button>
<text v-if="message" class="status-message">{{ message }}</text>
</view>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import type { LoginResult } from '@/types/api';
import { apiRequest } from '@/services/api';
import { consumeLoginRedirect, getAuth, isLoggedIn, phoneKey, saveAuth, validatePhone } from '@/services/auth';
const stored = getAuth();
const phone = ref(stored.phone || uni.getStorageSync(phoneKey) || '');
const smsCode = ref('');
const sending = ref(false);
const loggingIn = ref(false);
const message = ref('');
const tabPages = new Set([
'/pages/user/today/index',
'/pages/user/practice/index',
'/pages/user/sop/index',
'/pages/user/profile/index'
]);
const goAfterLogin = () => {
const redirect = consumeLoginRedirect() || '/pages/user/today/index';
if (tabPages.has(redirect)) {
uni.switchTab({ url: redirect });
return;
}
uni.redirectTo({ url: redirect });
};
const sendCode = async () => {
if (sending.value) return;
const value = phone.value.trim();
if (!validatePhone(value)) {
message.value = '请输入正确手机号';
return;
}
sending.value = true;
message.value = '';
try {
await apiRequest<void>({
url: `/resource/sms/code?phonenumber=${encodeURIComponent(value)}`,
method: 'GET',
auth: false
});
message.value = '验证码已发送';
} catch (error) {
message.value = error instanceof Error ? error.message : '验证码发送失败';
} finally {
sending.value = false;
}
};
const login = async () => {
if (loggingIn.value) return;
const value = phone.value.trim();
if (!validatePhone(value)) {
message.value = '请输入正确手机号';
return;
}
if (!smsCode.value.trim()) {
message.value = '请输入短信验证码';
return;
}
loggingIn.value = true;
message.value = '';
try {
const result = await apiRequest<LoginResult>({
url: '/auth/mobile/sms-login',
method: 'POST',
data: {
phonenumber: value,
smsCode: smsCode.value.trim(),
tenantId: '000000'
},
auth: false
});
if (!result.access_token || !result.client_id) {
throw new Error('登录响应缺少认证信息');
}
saveAuth(result, value);
goAfterLogin();
} catch (error) {
message.value = error instanceof Error ? error.message : '登录失败';
} finally {
loggingIn.value = false;
}
};
onShow(() => {
if (isLoggedIn()) {
goAfterLogin();
}
});
</script>
<style scoped>
.login-page {
display: flex;
min-height: 100vh;
flex-direction: column;
justify-content: center;
}
.login-head {
margin-bottom: 10px;
}
.login-card {
display: flex;
flex-direction: column;
gap: 14px;
}
.code-input {
flex: 1;
}
.code-button {
width: 112px;
flex: none;
font-size: 14px;
}
</style>