fix(mobile): require employee position before user flow
This commit is contained in:
@@ -41,6 +41,7 @@ import type { LoginResult } from '@/types/api';
|
||||
import { apiRequest } from '@/services/api';
|
||||
import { consumeLoginRedirect, getAuth, isLoggedIn, phoneKey, saveAuth, validatePhone } from '@/services/auth';
|
||||
import { resetPageScroll } from '@/services/navigation';
|
||||
import { goToMobileTarget, nextUserRouteAfterLogin } from '@/services/position';
|
||||
|
||||
const stored = getAuth();
|
||||
const phone = ref(stored.phone || uni.getStorageSync(phoneKey) || '');
|
||||
@@ -48,20 +49,9 @@ 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 goAfterLogin = async () => {
|
||||
const redirect = consumeLoginRedirect() || '/pages/user/today/index';
|
||||
if (tabPages.has(redirect)) {
|
||||
uni.switchTab({ url: redirect });
|
||||
return;
|
||||
}
|
||||
uni.redirectTo({ url: redirect });
|
||||
goToMobileTarget(await nextUserRouteAfterLogin(redirect));
|
||||
};
|
||||
|
||||
const sendCode = async () => {
|
||||
@@ -115,7 +105,7 @@ const login = async () => {
|
||||
throw new Error('登录响应缺少认证信息');
|
||||
}
|
||||
saveAuth(result, value);
|
||||
goAfterLogin();
|
||||
await goAfterLogin();
|
||||
} catch (error) {
|
||||
message.value = error instanceof Error ? error.message : '登录失败';
|
||||
} finally {
|
||||
@@ -126,7 +116,7 @@ const login = async () => {
|
||||
onShow(() => {
|
||||
resetPageScroll();
|
||||
if (isLoggedIn()) {
|
||||
goAfterLogin();
|
||||
void goAfterLogin();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<view class="page position-page">
|
||||
<view class="position-head">
|
||||
<text class="page-title">确认岗位</text>
|
||||
<text class="page-subtitle">{{ phone }}</text>
|
||||
</view>
|
||||
|
||||
<view v-if="message" class="status-message">{{ message }}</view>
|
||||
|
||||
<view class="panel">
|
||||
<text class="panel-title">选择当前岗位</text>
|
||||
<view class="position-list">
|
||||
<button
|
||||
v-for="item in positionCards"
|
||||
:key="item.value"
|
||||
class="position-card"
|
||||
:class="{ active: item.value === selectedPosition }"
|
||||
:disabled="saving"
|
||||
@click="selectPosition(item.value)"
|
||||
>
|
||||
<view class="position-copy">
|
||||
<text class="position-name">{{ item.value }}</text>
|
||||
<text class="position-title">{{ item.heroTitle }}</text>
|
||||
</view>
|
||||
<text class="position-mark">{{ item.value === selectedPosition ? '已选' : '选择' }}</text>
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import {
|
||||
getAuth,
|
||||
getPositionProfile,
|
||||
isLoggedIn,
|
||||
rememberLoginRedirect,
|
||||
saveSelectedPosition,
|
||||
userPositionOptions,
|
||||
type UserPosition
|
||||
} from '@/services/auth';
|
||||
import { goToMobileTarget, hydratePositionFromOrg } from '@/services/position';
|
||||
import { resetPageScroll } from '@/services/navigation';
|
||||
|
||||
const redirect = ref('/pages/user/today/index');
|
||||
const selectedPosition = ref<UserPosition | ''>('');
|
||||
const saving = ref(false);
|
||||
const message = ref('');
|
||||
const phone = computed(() => getAuth().phone || '未登录');
|
||||
const positionCards = userPositionOptions.map((item) => getPositionProfile(item));
|
||||
|
||||
const finish = () => {
|
||||
goToMobileTarget(redirect.value || '/pages/user/today/index');
|
||||
};
|
||||
|
||||
const selectPosition = (position: UserPosition) => {
|
||||
if (saving.value) return;
|
||||
saving.value = true;
|
||||
const saved = saveSelectedPosition(position);
|
||||
selectedPosition.value = saved;
|
||||
finish();
|
||||
};
|
||||
|
||||
const autoFillFromOrg = async () => {
|
||||
if (!isLoggedIn()) {
|
||||
rememberLoginRedirect(redirect.value);
|
||||
uni.redirectTo({ url: '/pages/auth/login/index' });
|
||||
return;
|
||||
}
|
||||
const officialPosition = await hydratePositionFromOrg();
|
||||
if (officialPosition) {
|
||||
selectedPosition.value = officialPosition;
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
message.value = '未从组织数据匹配到岗位,请确认当前岗位';
|
||||
};
|
||||
|
||||
onLoad((query) => {
|
||||
if (typeof query?.redirect === 'string') {
|
||||
const target = decodeURIComponent(query.redirect);
|
||||
if (target.startsWith('/pages/')) {
|
||||
redirect.value = target;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onShow(() => {
|
||||
resetPageScroll();
|
||||
void autoFillFromOrg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.position-page {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.position-head {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.position-list {
|
||||
display: flex;
|
||||
margin-top: 16px;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.position-card {
|
||||
display: flex;
|
||||
min-height: 72px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 14px 16px;
|
||||
border: 1px solid #e2e8f0;
|
||||
border-radius: 16px;
|
||||
background: #f8fafc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.position-card.active {
|
||||
border-color: #2563eb;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.position-copy {
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.position-name {
|
||||
color: #0f172a;
|
||||
font-size: 18px;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.position-title {
|
||||
margin-top: 6px;
|
||||
color: #64748b;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.position-mark {
|
||||
color: #2563eb;
|
||||
font-size: 14px;
|
||||
font-weight: 900;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user