功能完善

This commit is contained in:
kron
2025-06-15 15:53:57 +08:00
parent 7ac84a6129
commit 448f88a77e
21 changed files with 424 additions and 178 deletions

185
src/components/Signin.vue Normal file
View File

@@ -0,0 +1,185 @@
<script setup>
import { ref } from "vue";
import Avatar from "@/components/Avatar.vue";
import SButton from "@/components/SButton.vue";
import { getMyDevicesAPI, loginAPI } from "@/apis";
import useStore from "@/store";
const store = useStore();
const { updateUser, updateDevice } = store;
const props = defineProps({
onClose: {
type: Function,
default: () => {},
},
});
const agree = ref(false);
const avatarUrl = ref("");
const nickName = ref("");
const handleAgree = () => {
agree.value = !agree.value;
};
function onChooseAvatar(e) {
avatarUrl.value = e.detail.avatarUrl;
}
function onNicknameChange(e) {
nickName.value = e.detail.value;
}
const handleLogin = () => {
if (!avatarUrl.value) {
return uni.showToast({
title: "请选择头像",
icon: "none",
});
}
if (!nickName.value) {
return uni.showToast({
title: "请输入昵称",
icon: "none",
});
}
if (!agree.value) {
return uni.showToast({
title: "请先同意协议",
icon: "none",
});
}
uni.login({
provider: "weixin",
success: async (loginRes) => {
const { code } = loginRes;
const result = await loginAPI(nickName.value, avatarUrl.value, code);
updateUser({
...result.user,
nickName: nickName.value,
avatarUrl: avatarUrl.value,
});
const devices = await getMyDevicesAPI();
if (devices.bindings.length) {
updateDevice(
devices.bindings[0].deviceId,
devices.bindings[0].deviceName
);
}
props.onClose();
},
fail: (err) => {
uni.showToast({
title: "登录失败",
icon: "none",
});
console.error("登录失败:", err);
},
});
};
</script>
<template>
<view class="container">
<view class="avatar">
<text>头像:</text>
<button
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
class="login-btn"
hover-class="none"
>
<Avatar v-if="avatarUrl" :src="avatarUrl" />
<text v-else>点击获取</text>
</button>
</view>
<view class="nickname">
<text>昵称:</text>
<input
type="nickname"
class="nickname-input"
placeholder="请输入昵称"
@change="onNicknameChange"
@blur="onNicknameBlur"
/>
</view>
<SButton :rounded="20" width="80vw" :onClick="handleLogin">
<image
src="../static/wechat-icon.png"
mode="widthFix"
class="wechat-icon"
/>
<text :style="{ color: '#000' }">登录/注册</text>
</SButton>
<view class="protocol" @click="handleAgree">
<view v-if="!agree" />
<image v-if="agree" src="../static/checked.png" mode="widthFix" />
<text
>已同意并阅读<text :style="{ color: '#fff' }">用户协议</text><text
:style="{ color: '#fff' }"
>隐私协议</text
>内容</text
>
</view>
</view>
</template>
<style scoped>
.container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.avatar,
.nickname {
width: 80%;
display: flex;
align-items: center;
margin: 20px 0;
}
.avatar {
margin: 0;
}
.avatar > text,
.nickname > text {
width: 20%;
margin-right: 10px;
color: #fff9;
}
.nickname > input {
flex: 1;
background-color: #fff;
border-radius: 20px;
padding: 7px 15px;
font-size: 14px;
color: #000;
}
.wechat-icon {
width: 24px;
height: 24px;
margin-right: 20px;
}
.protocol {
display: flex;
justify-content: center;
align-items: center;
font-size: 13px;
margin-top: 15px;
color: #8a8a8a;
}
.protocol > image {
width: 18px;
height: 18px;
margin-right: 10px;
}
.protocol > view:first-child {
width: 16px;
height: 16px;
border-radius: 50%;
margin-right: 10px;
border: 1px solid #fff;
}
.login-btn::after {
border: none;
}
</style>