feat(admin-web/auth): support phone-or-email login and dim shell on expiry

Login form takes a phone-or-email identifier; user info now exposes phone
so the shell can fall back through name → phone → email. When membership
expires, the app stays on the current route but renders a minimal blocked
state in the shell instead of redirecting to a dedicated page; an Axios
interceptor flips the local session into the blocked state when the API
returns trial/subscription errors.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-29 00:01:47 +08:00
parent ee21f512a9
commit 62b824520c
10 changed files with 170 additions and 33 deletions
+3 -3
View File
@@ -33,8 +33,8 @@
</div>
<form @submit.prevent="handleSubmit" class="form">
<div class="field">
<label for="login-email">{{ t('auth.email') }}</label>
<input id="login-email" type="email" placeholder="admin@geo.local" v-model="formState.email"
<label for="login-identifier">{{ t('auth.loginIdentifier') }}</label>
<input id="login-identifier" type="text" placeholder="admin@geo.local / 13800138000" v-model="formState.identifier"
autocomplete="off" @focus="isTyping = true" @blur="isTyping = false" required />
</div>
<div class="field">
@@ -98,7 +98,7 @@ const isTyping = ref(false);
const remember = ref(false);
const formState = reactive({
email: "admin@geo.local",
identifier: "admin@geo.local",
password: "Admin@123",
});
@@ -41,8 +41,6 @@ const expiryText = computed(() => {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
}).format(date);
});