feat: 完成前端业务闭环与后端联调
This commit is contained in:
@@ -16,6 +16,22 @@
|
||||
><text>完成安全验证和短信校验后,即可更新你的登录手机号。</text></view
|
||||
>
|
||||
<view class="form-panel">
|
||||
<view class="field-block">
|
||||
<view class="form-row">
|
||||
<text>当前密码</text>
|
||||
<input
|
||||
v-model="currentPassword"
|
||||
password
|
||||
maxlength="32"
|
||||
aria-label="当前密码"
|
||||
:aria-invalid="Boolean(errors.currentPassword)"
|
||||
:aria-describedby="errors.currentPassword ? 'change-phone-password-error' : undefined"
|
||||
placeholder="请输入当前登录密码"
|
||||
@input="errors.currentPassword = ''"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="errors.currentPassword" id="change-phone-password-error" class="field-error" role="alert">{{ errors.currentPassword }}</text>
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="form-row">
|
||||
<text>新手机号</text>
|
||||
@@ -24,11 +40,13 @@
|
||||
type="number"
|
||||
maxlength="11"
|
||||
aria-label="新手机号"
|
||||
:aria-invalid="Boolean(errors.phone)"
|
||||
:aria-describedby="errors.phone ? 'change-phone-error' : undefined"
|
||||
placeholder="请输入新手机号"
|
||||
@input="handlePhoneInput"
|
||||
/>
|
||||
</view>
|
||||
<text v-if="errors.phone" class="field-error">{{ errors.phone }}</text>
|
||||
<text v-if="errors.phone" id="change-phone-error" class="field-error" role="alert">{{ errors.phone }}</text>
|
||||
</view>
|
||||
<view class="field-block">
|
||||
<view class="form-row form-row--code">
|
||||
@@ -38,6 +56,8 @@
|
||||
type="number"
|
||||
maxlength="4"
|
||||
aria-label="短信验证码"
|
||||
:aria-invalid="Boolean(errors.smsCode)"
|
||||
:aria-describedby="errors.smsCode ? 'change-phone-code-error' : undefined"
|
||||
placeholder="4 位验证码"
|
||||
@input="errors.smsCode = ''"
|
||||
/>
|
||||
@@ -48,7 +68,7 @@
|
||||
@click="prepareGetCode"
|
||||
>{{ cooldownSeconds > 0 ? `${cooldownSeconds}s 后重试` : '获取验证码' }}</button>
|
||||
</view>
|
||||
<text v-if="errors.smsCode" class="field-error">{{ errors.smsCode }}</text>
|
||||
<text v-if="errors.smsCode" id="change-phone-code-error" class="field-error" role="alert">{{ errors.smsCode }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<AppButton
|
||||
@@ -104,16 +124,19 @@ import {
|
||||
} from "@/utils/auth/verification.js";
|
||||
import { createDiscardConfirmation } from "@/utils/discard-confirmation.js";
|
||||
import { createNonIdempotentWriteGuard } from "@/utils/non-idempotent-write-guard.js";
|
||||
import { handleBackPress, runBackGuard } from "@/utils/navigation/gateway.js";
|
||||
import { goRoot, handleBackPress, runBackGuard } from "@/utils/navigation/gateway.js";
|
||||
import { calcMD5 } from "@/utils/md5.js";
|
||||
import { session } from "@/utils/session.js";
|
||||
|
||||
const currentPassword = ref("");
|
||||
const phone = ref("");
|
||||
const smsCode = ref("");
|
||||
const errors = reactive({ phone: "", smsCode: "" });
|
||||
const errors = reactive({ currentPassword: "", phone: "", smsCode: "" });
|
||||
const submittingPhoneChange = ref(false);
|
||||
const discardVisible = ref(false);
|
||||
const toastVisible = ref(false);
|
||||
const toastMessage = ref("");
|
||||
const formSnapshot = computed(() => JSON.stringify({ phone: phone.value, smsCode: smsCode.value }));
|
||||
const formSnapshot = computed(() => JSON.stringify({ currentPassword: currentPassword.value, phone: phone.value, smsCode: smsCode.value }));
|
||||
const baseline = ref(formSnapshot.value);
|
||||
const isDirty = computed(() => formSnapshot.value !== baseline.value);
|
||||
const phoneChangeController = createRequestController();
|
||||
@@ -185,19 +208,24 @@ const prepareGetCode = async () => {
|
||||
};
|
||||
|
||||
const validateForm = () => {
|
||||
errors.currentPassword = currentPassword.value ? "" : "请输入当前密码";
|
||||
errors.phone = isAuthPhone(phone.value) ? "" : "请输入正确手机号";
|
||||
errors.smsCode =
|
||||
sentPhone.value !== phone.value
|
||||
? "请先获取当前手机号的验证码"
|
||||
? "请先获取新手机号的验证码"
|
||||
: /^\d{4}$/.test(smsCode.value)
|
||||
? ""
|
||||
: "请输入 4 位验证码";
|
||||
return !errors.phone && !errors.smsCode;
|
||||
return !errors.currentPassword && !errors.phone && !errors.smsCode;
|
||||
};
|
||||
|
||||
const submitPhoneChange = async () => {
|
||||
if (phoneState.value !== "ready" || !validateForm()) return;
|
||||
const phoneChangePayload = { phone: phone.value, smsCode: smsCode.value };
|
||||
const phoneChangePayload = {
|
||||
phone: phone.value,
|
||||
smsCode: smsCode.value,
|
||||
currentPasswordHash: calcMD5(currentPassword.value),
|
||||
};
|
||||
const phoneChangeAttempt = phoneChangeGuard.begin(phoneChangePayload);
|
||||
if (phoneChangeAttempt === null) {
|
||||
showToast("上次换绑结果暂时无法确认,请重新登录确认手机号,不要重复提交");
|
||||
@@ -210,11 +238,14 @@ const submitPhoneChange = async () => {
|
||||
{ requestController: phoneChangeController },
|
||||
);
|
||||
if (!isPageActive) return;
|
||||
session.clear();
|
||||
await goRoot("A01");
|
||||
if (!isPageActive) return;
|
||||
currentPassword.value = "";
|
||||
phone.value = "";
|
||||
smsCode.value = "";
|
||||
sentPhone.value = "";
|
||||
baseline.value = formSnapshot.value;
|
||||
showToast("手机号换绑成功");
|
||||
} catch (error) {
|
||||
if (!isPageActive) return;
|
||||
if (phoneChangeGuard.recordFailure(phoneChangeAttempt, error)) {
|
||||
@@ -262,7 +293,7 @@ onUnload(() => {
|
||||
}
|
||||
.page-content {
|
||||
flex: 1;
|
||||
padding: 28rpx 30rpx 72rpx;
|
||||
padding: 28rpx 30rpx calc(72rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
.security-tip,
|
||||
.form-panel {
|
||||
@@ -314,7 +345,7 @@ onUnload(() => {
|
||||
.form-row input {
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
min-height: 68rpx;
|
||||
min-height: 80rpx;
|
||||
color: $ink;
|
||||
font-size: clamp(14px, 23rpx, 17px);
|
||||
}
|
||||
@@ -324,7 +355,7 @@ onUnload(() => {
|
||||
justify-content: center;
|
||||
justify-self: end;
|
||||
width: 198rpx;
|
||||
min-height: 68rpx;
|
||||
min-height: 80rpx;
|
||||
margin: 0;
|
||||
padding: 0 14rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
Reference in New Issue
Block a user