Merge branch 'master' of https://gitee.com/mickeywaugh/youlai-app
This commit is contained in:
@@ -2,27 +2,10 @@
|
|||||||
<view class="page py-16rpx">
|
<view class="page py-16rpx">
|
||||||
<wd-card>
|
<wd-card>
|
||||||
<wd-cell-group border>
|
<wd-cell-group border>
|
||||||
<wd-cell
|
<wd-cell icon="secured" title="账户密码" value="修改" is-link @click="handleOpenDialog(DialogType.PASSWORD)" />
|
||||||
icon="secured"
|
<wd-cell icon="mobile" title="绑定手机" :value="userProfile?.mobile || '未绑定手机号'" is-link @click="handleOpenDialog(DialogType.MOBILE)" />
|
||||||
title="账户密码"
|
<wd-cell icon="mail" title="绑定邮箱" :value="userProfile?.email ? userProfile.email : '未绑定邮箱'" is-link
|
||||||
value="修改"
|
@click="handleOpenDialog(DialogType.EMAIL)" />
|
||||||
is-link
|
|
||||||
@click="handleOpenDialog(DialogType.PASSWORD)"
|
|
||||||
/>
|
|
||||||
<wd-cell
|
|
||||||
icon="mobile"
|
|
||||||
title="绑定手机"
|
|
||||||
:value="userProfile?.mobile || '未绑定手机号'"
|
|
||||||
is-link
|
|
||||||
@click="handleOpenDialog(DialogType.MOBILE)"
|
|
||||||
/>
|
|
||||||
<wd-cell
|
|
||||||
icon="mail"
|
|
||||||
title="绑定邮箱"
|
|
||||||
:value="userProfile?.email ? userProfile.email : '未绑定邮箱'"
|
|
||||||
is-link
|
|
||||||
@click="handleOpenDialog(DialogType.EMAIL)"
|
|
||||||
/>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<wd-cell icon="wechat" title="微信" value="解绑" is-link @click="handleUnbindWechat" />
|
<wd-cell icon="wechat" title="微信" value="解绑" is-link @click="handleUnbindWechat" />
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
@@ -30,84 +13,28 @@
|
|||||||
</wd-card>
|
</wd-card>
|
||||||
|
|
||||||
<!--用户信息编辑弹出框-->
|
<!--用户信息编辑弹出框-->
|
||||||
<wd-popup
|
<wd-popup v-model="dialog.visible" position="bottom" custom-style="border-top-left-radius: 24rpx; border-top-right-radius: 24rpx;">
|
||||||
v-model="dialog.visible"
|
<wd-form v-if="dialog.type === DialogType.PASSWORD" ref="passwordChangeFormRef" :model="passwordChangeForm" custom-class="edit-form">
|
||||||
position="bottom"
|
|
||||||
custom-style="border-top-left-radius: 24rpx; border-top-right-radius: 24rpx;"
|
|
||||||
>
|
|
||||||
<wd-form
|
|
||||||
v-if="dialog.type === DialogType.PASSWORD"
|
|
||||||
ref="passwordChangeFormRef"
|
|
||||||
:model="passwordChangeForm"
|
|
||||||
custom-class="edit-form"
|
|
||||||
>
|
|
||||||
<wd-cell-group border>
|
<wd-cell-group border>
|
||||||
<wd-input
|
<wd-input v-model="passwordChangeForm.oldPassword" label="原密码" label-width="160rpx" show-password clearable placeholder="请输入原密码"
|
||||||
v-model="passwordChangeForm.oldPassword"
|
prop="oldPassword" :rules="rules.oldPassword" />
|
||||||
label="原密码"
|
<wd-input v-model="passwordChangeForm.newPassword" label="新密码" label-width="160rpx" show-password clearable placeholder="请输入新密码"
|
||||||
label-width="160rpx"
|
prop="newPassword" :rules="rules.newPassword" />
|
||||||
show-password
|
<wd-input v-model="passwordChangeForm.confirmPassword" label="确认密码" label-width="160rpx" show-password clearable placeholder="请确认新密码"
|
||||||
clearable
|
prop="confirmPassword" :rules="rules.confirmPassword" />
|
||||||
placeholder="请输入原密码"
|
|
||||||
prop="oldPassword"
|
|
||||||
:rules="rules.oldPassword"
|
|
||||||
/>
|
|
||||||
<wd-input
|
|
||||||
v-model="passwordChangeForm.newPassword"
|
|
||||||
label="新密码"
|
|
||||||
label-width="160rpx"
|
|
||||||
show-password
|
|
||||||
clearable
|
|
||||||
placeholder="请输入新密码"
|
|
||||||
prop="newPassword"
|
|
||||||
:rules="rules.newPassword"
|
|
||||||
/>
|
|
||||||
<wd-input
|
|
||||||
v-model="passwordChangeForm.confirmPassword"
|
|
||||||
label="确认密码"
|
|
||||||
label-width="160rpx"
|
|
||||||
show-password
|
|
||||||
clearable
|
|
||||||
placeholder="请确认新密码"
|
|
||||||
prop="confirmPassword"
|
|
||||||
:rules="rules.confirmPassword"
|
|
||||||
/>
|
|
||||||
</wd-cell-group>
|
</wd-cell-group>
|
||||||
<view class="p-24rpx">
|
<view class="p-24rpx">
|
||||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||||
</view>
|
</view>
|
||||||
</wd-form>
|
</wd-form>
|
||||||
<wd-form
|
<wd-form v-if="dialog.type === DialogType.MOBILE" ref="mobileBindingFormRef" :model="mobileBindingForm" custom-class="edit-form">
|
||||||
v-if="dialog.type === DialogType.MOBILE"
|
|
||||||
ref="mobileBindingFormRef"
|
|
||||||
:model="mobileBindingForm"
|
|
||||||
custom-class="edit-form"
|
|
||||||
>
|
|
||||||
<wd-cell-group border>
|
<wd-cell-group border>
|
||||||
<wd-input
|
<wd-input v-model="mobileBindingForm.mobile" label="手机号码" label-width="160rpx" clearable placeholder="请输入手机号码" prop="mobile"
|
||||||
v-model="mobileBindingForm.mobile"
|
:rules="rules.mobile" />
|
||||||
label="手机号码"
|
<wd-input v-model="mobileBindingForm.code" label="验证码" label-width="160rpx" clearable placeholder="请输入验证码" prop="code"
|
||||||
label-width="160rpx"
|
:rules="rules.code">
|
||||||
clearable
|
|
||||||
placeholder="请输入手机号码"
|
|
||||||
prop="mobile"
|
|
||||||
:rules="rules.mobile"
|
|
||||||
/>
|
|
||||||
<wd-input
|
|
||||||
v-model="mobileBindingForm.code"
|
|
||||||
label="验证码"
|
|
||||||
label-width="160rpx"
|
|
||||||
clearable
|
|
||||||
placeholder="请输入验证码"
|
|
||||||
prop="code"
|
|
||||||
:rules="rules.code"
|
|
||||||
>
|
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<wd-button
|
<wd-button plain :disabled="mobileCountdown > 0" @click="handleSendVerificationCode('MOBILE')">
|
||||||
plain
|
|
||||||
:disabled="mobileCountdown > 0"
|
|
||||||
@click="handleSendVerificationCode('MOBILE')"
|
|
||||||
>
|
|
||||||
{{ mobileCountdown > 0 ? `${mobileCountdown}s后重新发送` : "发送验证码" }}
|
{{ mobileCountdown > 0 ? `${mobileCountdown}s后重新发送` : "发送验证码" }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -117,37 +44,14 @@
|
|||||||
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
<wd-button type="primary" size="large" block @click="handleSubmit">提交</wd-button>
|
||||||
</view>
|
</view>
|
||||||
</wd-form>
|
</wd-form>
|
||||||
<wd-form
|
<wd-form v-if="dialog.type === DialogType.EMAIL" ref="emailBindingFormRef" :model="emailBindingForm" custom-class="edit-form">
|
||||||
v-if="dialog.type === DialogType.EMAIL"
|
|
||||||
ref="emailBindingFormRef"
|
|
||||||
:model="emailBindingForm"
|
|
||||||
custom-class="edit-form"
|
|
||||||
>
|
|
||||||
<wd-cell-group border>
|
<wd-cell-group border>
|
||||||
<wd-input
|
<wd-input v-model="emailBindingForm.email" label="邮箱" label-width="160rpx" clearable placeholder="请输入邮箱" prop="email"
|
||||||
v-model="emailBindingForm.email"
|
:rules="rules.email" />
|
||||||
label="邮箱"
|
<wd-input v-model="emailBindingForm.code" label="验证码" label-width="160rpx" clearable placeholder="请输入验证码" prop="code"
|
||||||
label-width="160rpx"
|
:rules="rules.code">
|
||||||
clearable
|
|
||||||
placeholder="请输入邮箱"
|
|
||||||
prop="email"
|
|
||||||
:rules="rules.email"
|
|
||||||
/>
|
|
||||||
<wd-input
|
|
||||||
v-model="emailBindingForm.code"
|
|
||||||
label="验证码"
|
|
||||||
label-width="160rpx"
|
|
||||||
clearable
|
|
||||||
placeholder="请输入验证码"
|
|
||||||
prop="code"
|
|
||||||
:rules="rules.code"
|
|
||||||
>
|
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<wd-button
|
<wd-button plain :disabled="emailCountdown > 0" @click="handleSendVerificationCode('EMAIL')">
|
||||||
plain
|
|
||||||
:disabled="emailCountdown > 0"
|
|
||||||
@click="handleSendVerificationCode('EMAIL')"
|
|
||||||
>
|
|
||||||
{{ emailCountdown > 0 ? `${emailCountdown}s后重新发送` : "发送验证码" }}
|
{{ emailCountdown > 0 ? `${emailCountdown}s后重新发送` : "发送验证码" }}
|
||||||
</wd-button>
|
</wd-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -161,172 +65,172 @@
|
|||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, reactive, ref } from "vue";
|
import { onMounted, reactive, ref } from "vue";
|
||||||
import { useToast, useDialog } from "@wot-ui/ui";
|
import { useToast, useDialog } from "@wot-ui/ui";
|
||||||
import { useCountdown } from "@/composables/useCountdown";
|
import { useCountdown } from "@/composables/useCountdown";
|
||||||
import UserAPI, {
|
import UserAPI, {
|
||||||
PasswordChangeForm,
|
PasswordChangeForm,
|
||||||
MobileBindingForm,
|
MobileBindingForm,
|
||||||
EmailBindingForm,
|
EmailBindingForm,
|
||||||
UserProfile,
|
UserProfile,
|
||||||
} from "@/api/user";
|
} from "@/api/user";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { confirm } = useDialog();
|
const { confirm } = useDialog();
|
||||||
|
|
||||||
const validatorConfirmPassword = (value: string) => {
|
const validatorConfirmPassword = (value: string) => {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return Promise.reject("请确认密码");
|
return Promise.reject("请确认密码");
|
||||||
} else {
|
|
||||||
if (value !== passwordChangeForm.newPassword) {
|
|
||||||
return Promise.reject("两次输入的密码不一致");
|
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve();
|
if (value !== passwordChangeForm.newPassword) {
|
||||||
|
return Promise.reject("两次输入的密码不一致");
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 本页面中所有的校验规则
|
||||||
|
const rules = reactive({
|
||||||
|
oldPassword: [{ required: true, message: "请填写原密码" }],
|
||||||
|
newPassword: [{ required: true, message: "请填写新密码" }],
|
||||||
|
confirmPassword: [{ required: true, message: "请确认密码", validator: validatorConfirmPassword }],
|
||||||
|
mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: "请填写正确的手机号码" }],
|
||||||
|
code: [{ required: true, message: "请填写验证码" }],
|
||||||
|
email: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
||||||
|
message: "请填写正确的邮箱地址",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
enum DialogType {
|
||||||
|
PASSWORD = "password",
|
||||||
|
MOBILE = "mobile",
|
||||||
|
EMAIL = "email",
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialog = reactive({
|
||||||
|
visible: false,
|
||||||
|
type: "" as DialogType, // 修改账号资料,修改密码、绑定手机、绑定邮箱
|
||||||
|
});
|
||||||
|
|
||||||
|
const userProfile = ref<UserProfile>(); //用户信息
|
||||||
|
const passwordChangeForm = reactive<PasswordChangeForm>({});
|
||||||
|
const mobileBindingForm = reactive<MobileBindingForm>({});
|
||||||
|
const emailBindingForm = reactive<EmailBindingForm>({});
|
||||||
|
const passwordChangeFormRef = ref();
|
||||||
|
const mobileBindingFormRef = ref();
|
||||||
|
const emailBindingFormRef = ref();
|
||||||
|
|
||||||
|
const { countdown: mobileCountdown, start: startMobileCountdown } = useCountdown(60);
|
||||||
|
const { countdown: emailCountdown, start: startEmailCountdown } = useCountdown(60);
|
||||||
|
|
||||||
|
const handleUnbindWechat = async () => {
|
||||||
|
try {
|
||||||
|
await confirm({
|
||||||
|
title: "提示",
|
||||||
|
msg: "确定要解绑微信吗?解绑后将无法使用微信小程序登录",
|
||||||
|
headerImage: "warning"
|
||||||
|
});
|
||||||
|
await UserAPI.unbindSocial("WECHAT_MINI");
|
||||||
|
toast.success("解绑成功");
|
||||||
|
loadUserProfile();
|
||||||
|
} catch {
|
||||||
|
// 用户取消或解绑失败
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 加载用户信息 */
|
||||||
|
const loadUserProfile = async () => {
|
||||||
|
userProfile.value = await UserAPI.getProfile();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打开弹窗
|
||||||
|
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
|
||||||
|
*/
|
||||||
|
const handleOpenDialog = (type: DialogType) => {
|
||||||
|
dialog.type = type;
|
||||||
|
dialog.visible = true;
|
||||||
|
switch (type) {
|
||||||
|
case DialogType.PASSWORD:
|
||||||
|
passwordChangeForm.oldPassword = "";
|
||||||
|
passwordChangeForm.newPassword = "";
|
||||||
|
passwordChangeForm.confirmPassword = "";
|
||||||
|
break;
|
||||||
|
case DialogType.MOBILE:
|
||||||
|
mobileBindingForm.mobile = "";
|
||||||
|
mobileBindingForm.code = "";
|
||||||
|
break;
|
||||||
|
case DialogType.EMAIL:
|
||||||
|
emailBindingForm.email = "";
|
||||||
|
emailBindingForm.code = "";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送验证码
|
||||||
|
*
|
||||||
|
* @param contactType 联系方式类型 MOBILE: 手机号码 EMAIL: 邮箱
|
||||||
|
*/
|
||||||
|
const handleSendVerificationCode = async (contactType: string) => {
|
||||||
|
try {
|
||||||
|
if (contactType === "MOBILE") {
|
||||||
|
const { valid } = await mobileBindingFormRef.value.validate("mobile");
|
||||||
|
if (valid) {
|
||||||
|
await UserAPI.sendVerificationCode(mobileBindingForm.mobile!, "MOBILE");
|
||||||
|
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||||
|
startMobileCountdown();
|
||||||
|
}
|
||||||
|
} else if (contactType === "EMAIL") {
|
||||||
|
const { valid } = await emailBindingFormRef.value.validate("email");
|
||||||
|
if (valid) {
|
||||||
|
await UserAPI.sendVerificationCode(emailBindingForm.email!, "EMAIL");
|
||||||
|
uni.showToast({ title: "验证码已发送", icon: "none" });
|
||||||
|
startEmailCountdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("发送验证码失败:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 提交表单
|
||||||
|
async function handleSubmit() {
|
||||||
|
try {
|
||||||
|
if (dialog.type === DialogType.PASSWORD) {
|
||||||
|
const { valid } = await passwordChangeFormRef.value.validate();
|
||||||
|
if (valid) {
|
||||||
|
await UserAPI.changePassword(passwordChangeForm);
|
||||||
|
uni.showToast({ title: "密码修改成功", icon: "none" });
|
||||||
|
dialog.visible = false;
|
||||||
|
}
|
||||||
|
} else if (dialog.type === DialogType.MOBILE) {
|
||||||
|
const { valid } = await mobileBindingFormRef.value.validate();
|
||||||
|
if (valid) {
|
||||||
|
await UserAPI.bindMobile(mobileBindingForm);
|
||||||
|
uni.showToast({ title: "手机号绑定成功", icon: "none" });
|
||||||
|
dialog.visible = false;
|
||||||
|
loadUserProfile();
|
||||||
|
}
|
||||||
|
} else if (dialog.type === DialogType.EMAIL) {
|
||||||
|
const { valid } = await emailBindingFormRef.value.validate();
|
||||||
|
if (valid) {
|
||||||
|
await UserAPI.bindEmail(emailBindingForm);
|
||||||
|
uni.showToast({ title: "邮箱绑定成功", icon: "none" });
|
||||||
|
dialog.visible = false;
|
||||||
|
loadUserProfile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("提交表单失败:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
// 本页面中所有的校验规则
|
|
||||||
const rules = reactive({
|
|
||||||
oldPassword: [{ required: true, message: "请填写原密码" }],
|
|
||||||
newPassword: [{ required: true, message: "请填写新密码" }],
|
|
||||||
confirmPassword: [{ required: true, message: "请确认密码", validator: validatorConfirmPassword }],
|
|
||||||
mobile: [{ required: true, pattern: /^1[3-9]\d{9}$/, message: "请填写正确的手机号码" }],
|
|
||||||
code: [{ required: true, message: "请填写验证码" }],
|
|
||||||
email: [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
pattern: /\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}/,
|
|
||||||
message: "请填写正确的邮箱地址",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
|
|
||||||
enum DialogType {
|
onMounted(() => {
|
||||||
PASSWORD = "password",
|
|
||||||
MOBILE = "mobile",
|
|
||||||
EMAIL = "email",
|
|
||||||
}
|
|
||||||
|
|
||||||
const dialog = reactive({
|
|
||||||
visible: false,
|
|
||||||
type: "" as DialogType, // 修改账号资料,修改密码、绑定手机、绑定邮箱
|
|
||||||
});
|
|
||||||
|
|
||||||
const userProfile = ref<UserProfile>(); //用户信息
|
|
||||||
const passwordChangeForm = reactive<PasswordChangeForm>({});
|
|
||||||
const mobileBindingForm = reactive<MobileBindingForm>({});
|
|
||||||
const emailBindingForm = reactive<EmailBindingForm>({});
|
|
||||||
const passwordChangeFormRef = ref();
|
|
||||||
const mobileBindingFormRef = ref();
|
|
||||||
const emailBindingFormRef = ref();
|
|
||||||
|
|
||||||
const { countdown: mobileCountdown, start: startMobileCountdown } = useCountdown(60);
|
|
||||||
const { countdown: emailCountdown, start: startEmailCountdown } = useCountdown(60);
|
|
||||||
|
|
||||||
const handleUnbindWechat = async () => {
|
|
||||||
try {
|
|
||||||
await confirm({
|
|
||||||
title: "提示",
|
|
||||||
msg: "确定要解绑微信吗?解绑后将无法使用微信小程序登录",
|
|
||||||
headerImage: "warning",
|
|
||||||
});
|
|
||||||
await UserAPI.unbindSocial("WECHAT_MINI");
|
|
||||||
toast.success("解绑成功");
|
|
||||||
loadUserProfile();
|
loadUserProfile();
|
||||||
} catch {
|
});
|
||||||
// 用户取消或解绑失败
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/** 加载用户信息 */
|
|
||||||
const loadUserProfile = async () => {
|
|
||||||
userProfile.value = await UserAPI.getProfile();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打开弹窗
|
|
||||||
* @param type 弹窗类型 ACCOUNT: 账号资料 PASSWORD: 修改密码 MOBILE: 绑定手机 EMAIL: 绑定邮箱
|
|
||||||
*/
|
|
||||||
const handleOpenDialog = (type: DialogType) => {
|
|
||||||
dialog.type = type;
|
|
||||||
dialog.visible = true;
|
|
||||||
switch (type) {
|
|
||||||
case DialogType.PASSWORD:
|
|
||||||
passwordChangeForm.oldPassword = "";
|
|
||||||
passwordChangeForm.newPassword = "";
|
|
||||||
passwordChangeForm.confirmPassword = "";
|
|
||||||
break;
|
|
||||||
case DialogType.MOBILE:
|
|
||||||
mobileBindingForm.mobile = "";
|
|
||||||
mobileBindingForm.code = "";
|
|
||||||
break;
|
|
||||||
case DialogType.EMAIL:
|
|
||||||
emailBindingForm.email = "";
|
|
||||||
emailBindingForm.code = "";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发送验证码
|
|
||||||
*
|
|
||||||
* @param contactType 联系方式类型 MOBILE: 手机号码 EMAIL: 邮箱
|
|
||||||
*/
|
|
||||||
const handleSendVerificationCode = async (contactType: string) => {
|
|
||||||
try {
|
|
||||||
if (contactType === "MOBILE") {
|
|
||||||
const { valid } = await mobileBindingFormRef.value.validate("mobile");
|
|
||||||
if (valid) {
|
|
||||||
await UserAPI.sendVerificationCode(mobileBindingForm.mobile!, "MOBILE");
|
|
||||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
|
||||||
startMobileCountdown();
|
|
||||||
}
|
|
||||||
} else if (contactType === "EMAIL") {
|
|
||||||
const { valid } = await emailBindingFormRef.value.validate("email");
|
|
||||||
if (valid) {
|
|
||||||
await UserAPI.sendVerificationCode(emailBindingForm.email!, "EMAIL");
|
|
||||||
uni.showToast({ title: "验证码已发送", icon: "none" });
|
|
||||||
startEmailCountdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("发送验证码失败:", error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 提交表单
|
|
||||||
async function handleSubmit() {
|
|
||||||
try {
|
|
||||||
if (dialog.type === DialogType.PASSWORD) {
|
|
||||||
const { valid } = await passwordChangeFormRef.value.validate();
|
|
||||||
if (valid) {
|
|
||||||
await UserAPI.changePassword(passwordChangeForm);
|
|
||||||
uni.showToast({ title: "密码修改成功", icon: "none" });
|
|
||||||
dialog.visible = false;
|
|
||||||
}
|
|
||||||
} else if (dialog.type === DialogType.MOBILE) {
|
|
||||||
const { valid } = await mobileBindingFormRef.value.validate();
|
|
||||||
if (valid) {
|
|
||||||
await UserAPI.bindMobile(mobileBindingForm);
|
|
||||||
uni.showToast({ title: "手机号绑定成功", icon: "none" });
|
|
||||||
dialog.visible = false;
|
|
||||||
loadUserProfile();
|
|
||||||
}
|
|
||||||
} else if (dialog.type === DialogType.EMAIL) {
|
|
||||||
const { valid } = await emailBindingFormRef.value.validate();
|
|
||||||
if (valid) {
|
|
||||||
await UserAPI.bindEmail(emailBindingForm);
|
|
||||||
uni.showToast({ title: "邮箱绑定成功", icon: "none" });
|
|
||||||
dialog.visible = false;
|
|
||||||
loadUserProfile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("提交表单失败:", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
loadUserProfile();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -15,27 +15,21 @@
|
|||||||
<view class="avatar-picker">
|
<view class="avatar-picker">
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<button class="avatar-picker__trigger" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
|
<button class="avatar-picker__trigger" open-type="chooseAvatar" @chooseavatar="onChooseAvatar">
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifndef MP-WEIXIN -->
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
<view class="avatar-picker__trigger" @click="chooseAvatar">
|
<view class="avatar-picker__trigger" @click="chooseAvatar">
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<image
|
<image v-if="profileForm.avatar" :src="profileForm.avatar" class="avatar-picker__img" mode="aspectFill" />
|
||||||
v-if="profileForm.avatar"
|
<view v-else class="avatar-picker__placeholder">
|
||||||
:src="profileForm.avatar"
|
<wd-icon name="camera" size="40" color="var(--color-text-placeholder)" />
|
||||||
class="avatar-picker__img"
|
<text class="avatar-picker__hint">选择头像</text>
|
||||||
mode="aspectFill"
|
</view>
|
||||||
/>
|
</view> <!-- #ifdef MP-WEIXIN -->
|
||||||
<view v-else class="avatar-picker__placeholder">
|
|
||||||
<wd-icon name="camera" size="40" color="var(--color-text-placeholder)" />
|
|
||||||
<text class="avatar-picker__hint">选择头像</text>
|
|
||||||
</view>
|
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
|
||||||
</button>
|
</button>
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifndef MP-WEIXIN -->
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
</view>
|
|
||||||
<!-- #endif -->
|
|
||||||
</view>
|
</view>
|
||||||
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 昵称 -->
|
<!-- 昵称 -->
|
||||||
@@ -45,22 +39,11 @@
|
|||||||
<text class="profile-form__required">*</text>
|
<text class="profile-form__required">*</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- #ifdef MP-WEIXIN -->
|
<!-- #ifdef MP-WEIXIN -->
|
||||||
<input
|
<input v-model="profileForm.nickname" type="nickname" class="profile-form__nickname-input" placeholder="请输入昵称" :maxlength="20" />
|
||||||
v-model="profileForm.nickname"
|
|
||||||
type="nickname"
|
|
||||||
class="profile-form__nickname-input"
|
|
||||||
placeholder="请输入昵称"
|
|
||||||
:maxlength="20"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
<!-- #ifndef MP-WEIXIN -->
|
<!-- #ifndef MP-WEIXIN -->
|
||||||
<wd-input
|
<wd-input v-model="profileForm.nickname" placeholder="请输入昵称" prop="nickname" :rules="rules.nickname"
|
||||||
v-model="profileForm.nickname"
|
custom-class="profile-form__nickname-input" />
|
||||||
placeholder="请输入昵称"
|
|
||||||
prop="nickname"
|
|
||||||
:rules="rules.nickname"
|
|
||||||
custom-class="profile-form__nickname-input"
|
|
||||||
/>
|
|
||||||
<!-- #endif -->
|
<!-- #endif -->
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -79,27 +62,15 @@
|
|||||||
手机号
|
手机号
|
||||||
<text class="profile-form__required">*</text>
|
<text class="profile-form__required">*</text>
|
||||||
</view>
|
</view>
|
||||||
<wd-input
|
<wd-input v-model="profileForm.mobile" placeholder="请输入手机号" prop="mobile" custom-class="profile-form__nickname-input" />
|
||||||
v-model="profileForm.mobile"
|
|
||||||
placeholder="请输入手机号"
|
|
||||||
prop="mobile"
|
|
||||||
custom-class="profile-form__nickname-input"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</wd-form>
|
</wd-form>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 底部 -->
|
<!-- 底部 -->
|
||||||
<view class="profile-footer">
|
<view class="profile-footer">
|
||||||
<wd-button
|
<wd-button class="profile-footer__submit" type="primary" size="large" block :disabled="!canComplete || isLoading" :loading="isLoading"
|
||||||
class="profile-footer__submit"
|
@click="handleComplete">
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
block
|
|
||||||
:disabled="!canComplete || isLoading"
|
|
||||||
:loading="isLoading"
|
|
||||||
@click="handleComplete"
|
|
||||||
>
|
|
||||||
完成
|
完成
|
||||||
</wd-button>
|
</wd-button>
|
||||||
<view class="profile-footer__skip" @click="handleSkip">
|
<view class="profile-footer__skip" @click="handleSkip">
|
||||||
@@ -108,301 +79,297 @@
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 头像裁剪 -->
|
<!-- 头像裁剪 -->
|
||||||
<wd-img-cropper
|
<wd-img-cropper v-model="cropperVisible" :img-src="originalImageSrc" @confirm="handleAvatarConfirm" />
|
||||||
v-model="cropperVisible"
|
|
||||||
:img-src="originalImageSrc"
|
|
||||||
@confirm="handleAvatarConfirm"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<wd-toast />
|
<wd-toast />
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive, computed } from "vue";
|
import { ref, reactive, computed } from "vue";
|
||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import { useUserStore } from "@/store";
|
import { useUserStore } from "@/store";
|
||||||
import UserAPI, { type UserProfileForm } from "@/api/user";
|
import UserAPI, { type UserProfileForm } from "@/api/user";
|
||||||
import FileAPI, { type FileInfo } from "@/api/file";
|
import FileAPI, { type FileInfo } from "@/api/file";
|
||||||
|
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const { confirm } = useDialog();
|
const { confirm } = useDialog();
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
const redirect = ref("/pages/index/index");
|
const redirect = ref("/pages/index/index");
|
||||||
|
|
||||||
const profileForm = reactive<UserProfileForm & { mobile?: string }>({
|
const profileForm = reactive<UserProfileForm & { mobile?: string }>({
|
||||||
nickname: "",
|
nickname: "",
|
||||||
avatar: "",
|
avatar: "",
|
||||||
gender: 1,
|
gender: 1,
|
||||||
mobile: "",
|
mobile: "",
|
||||||
});
|
|
||||||
|
|
||||||
const rules = {
|
|
||||||
nickname: [
|
|
||||||
{ required: true, message: "请输入昵称" },
|
|
||||||
{ required: true, min: 2, max: 20, message: "昵称长度为2-20个字符" },
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
||||||
const isLoading = ref(false);
|
|
||||||
const cropperVisible = ref(false);
|
|
||||||
const originalImageSrc = ref("");
|
|
||||||
const profileFormRef = ref();
|
|
||||||
|
|
||||||
const canComplete = computed(() => {
|
|
||||||
return profileForm.nickname && profileForm.mobile;
|
|
||||||
});
|
|
||||||
|
|
||||||
onLoad((options: any) => {
|
|
||||||
if (options?.redirect) {
|
|
||||||
redirect.value = decodeURIComponent(options.redirect);
|
|
||||||
}
|
|
||||||
const userInfo = userStore.userInfo;
|
|
||||||
if (userInfo) {
|
|
||||||
profileForm.nickname = userInfo.nickname || "";
|
|
||||||
profileForm.avatar = userInfo.avatar || "";
|
|
||||||
profileForm.gender = (userInfo as any).gender || 1;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const onChooseAvatar = async (e: any) => {
|
|
||||||
try {
|
|
||||||
const { avatarUrl } = e.detail;
|
|
||||||
toast.loading("上传中...");
|
|
||||||
const fileInfo: FileInfo = await FileAPI.upload(avatarUrl);
|
|
||||||
profileForm.avatar = fileInfo.url;
|
|
||||||
toast.success("头像上传成功");
|
|
||||||
} catch {
|
|
||||||
toast.error("头像上传失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const chooseAvatar = () => {
|
|
||||||
// #ifdef MP-WEIXIN
|
|
||||||
uni.chooseMedia({
|
|
||||||
count: 1,
|
|
||||||
mediaType: ["image"],
|
|
||||||
sourceType: ["album", "camera"],
|
|
||||||
success: (res) => {
|
|
||||||
originalImageSrc.value = res.tempFiles[0].tempFilePath;
|
|
||||||
cropperVisible.value = true;
|
|
||||||
},
|
|
||||||
fail: () => {
|
|
||||||
toast.error("选择图片失败");
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
// #endif
|
|
||||||
|
|
||||||
// #ifndef MP-WEIXIN
|
const rules = {
|
||||||
uni.chooseImage({
|
nickname: [
|
||||||
count: 1,
|
{ required: true, message: "请输入昵称" },
|
||||||
sourceType: ["album", "camera"],
|
{ required: true, min: 2, max: 20, message: "昵称长度为2-20个字符" },
|
||||||
success: (res) => {
|
],
|
||||||
originalImageSrc.value = res.tempFilePaths[0];
|
};
|
||||||
cropperVisible.value = true;
|
|
||||||
},
|
const isLoading = ref(false);
|
||||||
fail: () => {
|
const cropperVisible = ref(false);
|
||||||
toast.error("选择图片失败");
|
const originalImageSrc = ref("");
|
||||||
},
|
const profileFormRef = ref();
|
||||||
|
|
||||||
|
const canComplete = computed(() => {
|
||||||
|
return profileForm.nickname && profileForm.mobile;
|
||||||
});
|
});
|
||||||
// #endif
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleAvatarConfirm = async (event: any) => {
|
onLoad((options: any) => {
|
||||||
try {
|
if (options?.redirect) {
|
||||||
const { tempFilePath } = event;
|
redirect.value = decodeURIComponent(options.redirect);
|
||||||
toast.loading("上传中...");
|
|
||||||
const fileInfo: FileInfo = await FileAPI.upload(tempFilePath);
|
|
||||||
profileForm.avatar = fileInfo.url;
|
|
||||||
toast.success("头像上传成功");
|
|
||||||
} catch {
|
|
||||||
toast.error("头像上传失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleComplete = async () => {
|
|
||||||
try {
|
|
||||||
const { valid } = await profileFormRef.value.validate();
|
|
||||||
if (!valid) return;
|
|
||||||
|
|
||||||
if (!profileForm.mobile) {
|
|
||||||
toast.error("请输入手机号");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
const userInfo = userStore.userInfo;
|
||||||
|
if (userInfo) {
|
||||||
|
profileForm.nickname = userInfo.nickname || "";
|
||||||
|
profileForm.avatar = userInfo.avatar || "";
|
||||||
|
profileForm.gender = (userInfo as any).gender || 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
isLoading.value = true;
|
const onChooseAvatar = async (e: any) => {
|
||||||
|
try {
|
||||||
|
const { avatarUrl } = e.detail;
|
||||||
|
toast.loading("上传中...");
|
||||||
|
const fileInfo: FileInfo = await FileAPI.upload(avatarUrl);
|
||||||
|
profileForm.avatar = fileInfo.url;
|
||||||
|
toast.success("头像上传成功");
|
||||||
|
} catch {
|
||||||
|
toast.error("头像上传失败");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await UserAPI.updateProfile({
|
const chooseAvatar = () => {
|
||||||
nickname: profileForm.nickname,
|
// #ifdef MP-WEIXIN
|
||||||
avatar: profileForm.avatar,
|
uni.chooseMedia({
|
||||||
gender: profileForm.gender,
|
count: 1,
|
||||||
|
mediaType: ["image"],
|
||||||
|
sourceType: ["album", "camera"],
|
||||||
|
success: (res) => {
|
||||||
|
originalImageSrc.value = res.tempFiles[0].tempFilePath;
|
||||||
|
cropperVisible.value = true;
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
toast.error("选择图片失败");
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
// #endif
|
||||||
|
|
||||||
if (profileForm.mobile) {
|
// #ifndef MP-WEIXIN
|
||||||
await UserAPI.bindMobile({ mobile: profileForm.mobile });
|
uni.chooseImage({
|
||||||
|
count: 1,
|
||||||
|
sourceType: ["album", "camera"],
|
||||||
|
success: (res) => {
|
||||||
|
originalImageSrc.value = res.tempFilePaths[0];
|
||||||
|
cropperVisible.value = true;
|
||||||
|
},
|
||||||
|
fail: () => {
|
||||||
|
toast.error("选择图片失败");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// #endif
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAvatarConfirm = async (event: any) => {
|
||||||
|
try {
|
||||||
|
const { tempFilePath } = event;
|
||||||
|
toast.loading("上传中...");
|
||||||
|
const fileInfo: FileInfo = await FileAPI.upload(tempFilePath);
|
||||||
|
profileForm.avatar = fileInfo.url;
|
||||||
|
toast.success("头像上传成功");
|
||||||
|
} catch {
|
||||||
|
toast.error("头像上传失败");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
await userStore.getInfo();
|
const handleComplete = async () => {
|
||||||
toast.success("信息完善成功");
|
try {
|
||||||
|
const { valid } = await profileFormRef.value.validate();
|
||||||
|
if (!valid) return;
|
||||||
|
|
||||||
setTimeout(() => {
|
if (!profileForm.mobile) {
|
||||||
|
toast.error("请输入手机号");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
await UserAPI.updateProfile({
|
||||||
|
nickname: profileForm.nickname,
|
||||||
|
avatar: profileForm.avatar,
|
||||||
|
gender: profileForm.gender,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (profileForm.mobile) {
|
||||||
|
await UserAPI.bindMobile({ mobile: profileForm.mobile });
|
||||||
|
}
|
||||||
|
|
||||||
|
await userStore.getInfo();
|
||||||
|
toast.success("信息完善成功");
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
uni.reLaunch({ url: redirect.value });
|
||||||
|
}, 1000);
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error?.message || "完善信息失败");
|
||||||
|
} finally {
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSkip = async () => {
|
||||||
|
try {
|
||||||
|
await confirm({ title: "提示", msg: "跳过信息完善可能会影响部分功能使用,确定要跳过吗?", headerImage: "warning" });
|
||||||
uni.reLaunch({ url: redirect.value });
|
uni.reLaunch({ url: redirect.value });
|
||||||
}, 1000);
|
} catch {
|
||||||
} catch (error: any) {
|
// 用户取消
|
||||||
toast.error(error?.message || "完善信息失败");
|
}
|
||||||
} finally {
|
};
|
||||||
isLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSkip = async () => {
|
|
||||||
try {
|
|
||||||
await confirm({ title: "提示", msg: "跳过信息完善可能会影响部分功能使用,确定要跳过吗?", headerImage: "warning" });
|
|
||||||
uni.reLaunch({ url: redirect.value });
|
|
||||||
} catch {
|
|
||||||
// 用户取消
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.complete-profile__hero {
|
.complete-profile__hero {
|
||||||
margin-bottom: 60rpx;
|
margin-bottom: 60rpx;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
|
||||||
|
|
||||||
.complete-profile__hero-title {
|
|
||||||
margin-bottom: 20rpx;
|
|
||||||
font-size: 48rpx;
|
|
||||||
font-weight: bold;
|
|
||||||
color: var(--color-text-inverse);
|
|
||||||
}
|
|
||||||
|
|
||||||
.complete-profile__hero-subtitle {
|
|
||||||
font-size: 28rpx;
|
|
||||||
line-height: 1.5;
|
|
||||||
color: rgba(255, 255, 255, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-form {
|
|
||||||
padding: 40rpx;
|
|
||||||
margin-bottom: 40rpx;
|
|
||||||
background: var(--color-bg);
|
|
||||||
border-radius: 24rpx;
|
|
||||||
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
&__section {
|
|
||||||
margin-bottom: 40rpx;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__label {
|
.complete-profile__hero-title {
|
||||||
margin-bottom: 20rpx;
|
margin-bottom: 20rpx;
|
||||||
font-size: 32rpx;
|
font-size: 48rpx;
|
||||||
font-weight: 600;
|
font-weight: bold;
|
||||||
color: var(--color-text);
|
color: var(--color-text-inverse);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__required {
|
.complete-profile__hero-subtitle {
|
||||||
color: var(--color-danger);
|
font-size: 28rpx;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__nickname-input {
|
.profile-form {
|
||||||
:deep(.wd-input__inner) {
|
padding: 40rpx;
|
||||||
padding: 24rpx 20rpx;
|
margin-bottom: 40rpx;
|
||||||
background: var(--color-bg-tertiary);
|
background: var(--color-bg);
|
||||||
border: 1rpx solid var(--color-border-light);
|
border-radius: 24rpx;
|
||||||
border-radius: 12rpx;
|
box-shadow: 0 8rpx 40rpx rgba(0, 0, 0, 0.1);
|
||||||
|
|
||||||
|
&__section {
|
||||||
|
margin-bottom: 40rpx;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-picker {
|
&__label {
|
||||||
display: flex;
|
margin-bottom: 20rpx;
|
||||||
justify-content: center;
|
|
||||||
|
|
||||||
&__trigger {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 160rpx;
|
|
||||||
height: 160rpx;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
border-radius: 50%;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__img {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
border: 4rpx solid var(--color-border-light);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__placeholder {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 160rpx;
|
|
||||||
height: 160rpx;
|
|
||||||
background: var(--color-bg-tertiary);
|
|
||||||
border: 2rpx dashed var(--color-border);
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__hint {
|
|
||||||
margin-top: 10rpx;
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: var(--color-text-placeholder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.gender-group {
|
|
||||||
display: flex;
|
|
||||||
gap: 20rpx;
|
|
||||||
|
|
||||||
.gender-radio {
|
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
:deep(.wd-radio) {
|
|
||||||
justify-content: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-footer {
|
|
||||||
&__submit {
|
|
||||||
margin-bottom: 30rpx;
|
|
||||||
|
|
||||||
:deep(.wd-button) {
|
|
||||||
height: 88rpx;
|
|
||||||
font-size: 32rpx;
|
font-size: 32rpx;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
border-radius: 44rpx;
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__required {
|
||||||
|
color: var(--color-danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
&__nickname-input {
|
||||||
|
:deep(.wd-input__inner) {
|
||||||
|
padding: 24rpx 20rpx;
|
||||||
|
background: var(--color-bg-tertiary);
|
||||||
|
border: 1rpx solid var(--color-border-light);
|
||||||
|
border-radius: 12rpx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__skip {
|
.avatar-picker {
|
||||||
text-align: center;
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
text {
|
&__trigger {
|
||||||
font-size: 28rpx;
|
display: flex;
|
||||||
color: rgba(255, 255, 255, 0.8);
|
align-items: center;
|
||||||
text-decoration: underline;
|
justify-content: center;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border: 4rpx solid var(--color-border-light);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__placeholder {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 160rpx;
|
||||||
|
height: 160rpx;
|
||||||
|
background: var(--color-bg-tertiary);
|
||||||
|
border: 2rpx dashed var(--color-border);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__hint {
|
||||||
|
margin-top: 10rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: var(--color-text-placeholder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.gender-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 20rpx;
|
||||||
|
|
||||||
|
.gender-radio {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
:deep(.wd-radio) {
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-footer {
|
||||||
|
&__submit {
|
||||||
|
margin-bottom: 30rpx;
|
||||||
|
|
||||||
|
:deep(.wd-button) {
|
||||||
|
height: 88rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
border-radius: 44rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__skip {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user