Files
shoot-miniprograms/src/components/Signin.vue

215 lines
4.7 KiB
Vue
Raw Normal View History

2025-06-15 15:53:57 +08:00
<script setup>
import { ref } from "vue";
2025-08-09 12:32:06 +08:00
import { onShow } from "@dcloudio/uni-app";
2025-06-15 15:53:57 +08:00
import Avatar from "@/components/Avatar.vue";
import SButton from "@/components/SButton.vue";
2025-07-03 11:05:31 +08:00
import { getMyDevicesAPI, loginAPI, getHomeData } from "@/apis";
2025-06-15 15:53:57 +08:00
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("");
2025-08-09 12:32:06 +08:00
const loading = ref(false);
2025-06-15 15:53:57 +08:00
const handleAgree = () => {
agree.value = !agree.value;
};
function onChooseAvatar(e) {
avatarUrl.value = e.detail.avatarUrl;
}
function onNicknameChange(e) {
nickName.value = e.detail.value;
}
const handleLogin = () => {
2025-08-09 12:32:06 +08:00
if (loading.value) return;
2025-06-15 15:53:57 +08:00
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",
});
}
2025-08-09 12:32:06 +08:00
loading.value = true;
2025-06-15 15:53:57 +08:00
uni.login({
provider: "weixin",
success: async (loginRes) => {
const { code } = loginRes;
2025-06-27 10:33:53 +08:00
const fileManager = uni.getFileSystemManager();
const avatarBase64 = fileManager.readFileSync(avatarUrl.value, "base64");
const base64Url = `data:image/png;base64,${avatarBase64}`;
const result = await loginAPI(nickName.value, base64Url, code);
2025-07-03 11:05:31 +08:00
const data = await getHomeData();
if (data.user) updateUser(data.user);
2025-06-15 15:53:57 +08:00
const devices = await getMyDevicesAPI();
2025-06-16 00:30:56 +08:00
if (devices.bindings && devices.bindings.length) {
2025-06-15 15:53:57 +08:00
updateDevice(
devices.bindings[0].deviceId,
devices.bindings[0].deviceName
);
}
props.onClose();
},
fail: (err) => {
2025-08-09 12:32:06 +08:00
loading.value = false;
2025-06-15 15:53:57 +08:00
uni.showToast({
title: "登录失败",
icon: "none",
});
console.error("登录失败:", err);
},
});
};
2025-08-09 12:32:06 +08:00
onShow(() => {
loading.value = false;
});
2025-06-15 15:53:57 +08:00
</script>
<template>
<view class="container">
<view class="avatar">
<text>头像:</text>
<button
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
class="login-btn"
hover-class="none"
>
2025-06-21 22:22:19 +08:00
<Avatar v-if="avatarUrl" :src="avatarUrl" :size="30" />
2025-06-15 15:53:57 +08:00
<text v-else>点击获取</text>
</button>
</view>
<view class="nickname">
<text>昵称:</text>
<input
type="nickname"
placeholder="请输入昵称"
2025-06-20 01:47:57 +08:00
placeholder-style="color: #fff9"
2025-06-15 15:53:57 +08:00
@change="onNicknameChange"
@blur="onNicknameBlur"
/>
</view>
<SButton :rounded="20" width="80vw" :onClick="handleLogin">
2025-08-09 12:32:06 +08:00
<block v-if="!loading">
<image
src="../static/wechat-icon.png"
mode="widthFix"
class="wechat-icon"
/>
<text :style="{ color: '#000' }">登录/注册</text>
</block>
<block v-else>
<image
src="../static/btn-loading.png"
mode="widthFix"
class="loading"
/>
</block>
2025-06-15 15:53:57 +08:00
</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;
2025-06-20 01:47:57 +08:00
margin-bottom: 20px;
border-bottom: 1px solid #fff3;
2025-06-15 15:53:57 +08:00
}
.avatar {
margin: 0;
}
.avatar > text,
.nickname > text {
width: 20%;
color: #fff9;
2025-06-20 01:47:57 +08:00
font-size: 14px;
2025-08-07 11:34:30 +08:00
line-height: 55px;
2025-06-20 01:47:57 +08:00
}
.avatar > button > text {
color: #fff9;
font-size: 14px;
2025-06-15 15:53:57 +08:00
}
.nickname > input {
flex: 1;
font-size: 14px;
2025-06-21 22:22:19 +08:00
color: #fff;
2025-08-07 11:34:30 +08:00
line-height: 55px;
2025-06-15 15:53:57 +08:00
}
.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 {
2025-06-20 01:47:57 +08:00
width: 16px;
height: 16px;
2025-06-15 15:53:57 +08:00
margin-right: 10px;
}
.protocol > view:first-child {
2025-06-20 01:47:57 +08:00
width: 14px;
height: 14px;
2025-06-15 15:53:57 +08:00
border-radius: 50%;
margin-right: 10px;
border: 1px solid #fff;
}
2025-08-07 11:34:30 +08:00
.login-btn {
line-height: 55px;
width: 80%;
display: flex;
2025-06-15 15:53:57 +08:00
}
2025-08-09 12:32:06 +08:00
.loading {
width: 25px;
height: 25px;
background-blend-mode: darken;
animation: rotate 1s linear infinite;
}
2025-06-15 15:53:57 +08:00
</style>