pref: 小程序添加静默登录

This commit is contained in:
2026-04-28 10:31:54 +08:00
parent f07facd98b
commit e1a9d97596
3 changed files with 416 additions and 354 deletions

View File

@@ -38,7 +38,7 @@ function request(method, url, data = {}) {
timeout: 10000, timeout: 10000,
success: (res) => { success: (res) => {
if (res.data) { if (res.data) {
const { code, data, message } = res.data; const {code, data, message} = res.data;
if (code === 0) resolve(data); if (code === 0) resolve(data);
else if (message) { else if (message) {
if (message.indexOf("登录身份已失效") !== -1) { if (message.indexOf("登录身份已失效") !== -1) {
@@ -48,11 +48,11 @@ function request(method, url, data = {}) {
uni.$emit("update-user"); uni.$emit("update-user");
} }
if (message === "ROOM_FULL") { if (message === "ROOM_FULL") {
resolve({ full: true }); resolve({full: true});
return; return;
} }
if (message === "ERROR_ROOM_GAME_START") { if (message === "ERROR_ROOM_GAME_START") {
resolve({ started: true }); resolve({started: true});
return; return;
} }
if (url.indexOf("/user/room") !== -1 && method === "GET") { if (url.indexOf("/user/room") !== -1 && method === "GET") {
@@ -64,7 +64,7 @@ function request(method, url, data = {}) {
return; return;
} }
if (message === "BIND_DEVICE") { if (message === "BIND_DEVICE") {
resolve({ binded: true }); resolve({binded: true});
return; return;
} }
if (message === "ERROR_ORDER_UNPAY") { if (message === "ERROR_ORDER_UNPAY") {
@@ -99,7 +99,7 @@ function request(method, url, data = {}) {
// 统一的错误处理函数 // 统一的错误处理函数
function handleRequestError(err, url) { function handleRequestError(err, url) {
console.log("请求失败:", { err, url }); console.log("请求失败:", {err, url});
// 根据错误类型显示不同提示 // 根据错误类型显示不同提示
if (err.errMsg) { if (err.errMsg) {
@@ -179,6 +179,27 @@ export const loginAPI = async (phone, nickName, avatarData, code) => {
return result; return result;
}; };
export const silentLoginAPI = async (code) => {
const result = await request("POST", "/index/code", {
appName: "shoot",
appId: "wxa8f5989dcd45cc23",
code,
});
uni.setStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token`,
result.token
);
return result;
};
export const checkUserBindAPI = async (code) => {
return request("POST", "/index/checkBind", {
appName: "shoot",
appId: "wxa8f5989dcd45cc23",
code,
});
};
export const bindDeviceAPI = (device) => { export const bindDeviceAPI = (device) => {
return request("POST", "/user/device/bindDevice", { return request("POST", "/user/device/bindDevice", {
device, device,
@@ -206,7 +227,7 @@ export const createPractiseAPI = (arrows, time, target) => {
return request("POST", "/user/practice/create", { return request("POST", "/user/practice/create", {
shootNumber: arrows, shootNumber: arrows,
shootTime: time, shootTime: time,
targetType: target*20, targetType: target * 20,
}); });
}; };
@@ -235,7 +256,7 @@ export const getRoomAPI = (number) => {
}; };
export const joinRoomAPI = (number) => { export const joinRoomAPI = (number) => {
return request("POST", `/user/room/join`, { number }); return request("POST", `/user/room/join`, {number});
}; };
export const destroyRoomAPI = (roomNumber) => { export const destroyRoomAPI = (roomNumber) => {
@@ -252,7 +273,7 @@ export const exitRoomAPI = (number, userId) => {
}; };
export const startRoomAPI = (number) => { export const startRoomAPI = (number) => {
return request("POST", "/user/room/start", { number }); return request("POST", "/user/room/start", {number});
}; };
export const getPractiseResultListAPI = async (page = 1, page_size = 15) => { export const getPractiseResultListAPI = async (page = 1, page_size = 15) => {
@@ -326,7 +347,7 @@ export const getOrderListAPI = async (page) => {
}; };
export const cancelOrderListAPI = async (id) => { export const cancelOrderListAPI = async (id) => {
return request("POST", "/user/order/cancelOrder", { id }); return request("POST", "/user/order/cancelOrder", {id});
}; };
export const getUserGameState = () => { export const getUserGameState = () => {
@@ -391,7 +412,7 @@ export const getBattleDataAPI = async () => {
}; };
export const chooseTeamAPI = async (number, group) => { export const chooseTeamAPI = async (number, group) => {
return request("POST", "/user/room/group", { number, group }); return request("POST", "/user/room/group", {number, group});
}; };
export const getVIPDescAPI = async () => { export const getVIPDescAPI = async () => {
@@ -425,7 +446,7 @@ export const getDeviceBatteryAPI = async () => {
}; };
export const addNoteAPI = async (id, remark) => { export const addNoteAPI = async (id, remark) => {
return request("POST", "/user/score/sheet/remark", { id, remark }); return request("POST", "/user/score/sheet/remark", {id, remark});
}; };
export const removePointRecord = async (id) => { export const removePointRecord = async (id) => {

View File

@@ -86,18 +86,17 @@ const handleLogin = async () => {
icon: "none", icon: "none",
}); });
} }
await doLogin();
};
async function doLogin() {
loading.value = true; loading.value = true;
try { try {
const wxResult = await wxLogin(); const wxResult = await wxLogin();
const fileManager = uni.getFileSystemManager(); const fileManager = uni.getFileSystemManager();
const avatarBase64 = fileManager.readFileSync(avatarUrl.value, "base64"); const avatarBase64 = fileManager.readFileSync(avatarUrl.value, "base64");
const base64Url = `data:image/png;base64,${avatarBase64}`; const base64Url = `data:image/png;base64,${avatarBase64}`;
const result = await loginAPI( await loginAPI(phone.value, nickName.value, base64Url, wxResult.code);
phone.value,
nickName.value,
base64Url,
wxResult.code
);
const data = await getHomeData(); const data = await getHomeData();
if (data.user) updateUser(data.user); if (data.user) updateUser(data.user);
const devices = await getMyDevicesAPI(); const devices = await getMyDevicesAPI();
@@ -139,6 +138,10 @@ const openPrivacyLink = () => {
onShow(() => { onShow(() => {
loading.value = false; loading.value = false;
agree.value = false;
phone.value = "";
avatarUrl.value = "";
nickName.value = "";
}); });
</script> </script>

View File

@@ -1,25 +1,26 @@
<script setup> <script setup>
import { ref, onMounted } from "vue"; import {onMounted, ref} from "vue";
import { onShow, onShareAppMessage, onShareTimeline } from "@dcloudio/uni-app"; import {onShareAppMessage, onShareTimeline, onShow} from "@dcloudio/uni-app";
import Container from "@/components/Container.vue"; import Container from "@/components/Container.vue";
import AppFooter from "@/components/AppFooter.vue"; import AppFooter from "@/components/AppFooter.vue";
import AppBackground from "@/components/AppBackground.vue";
import UserHeader from "@/components/UserHeader.vue"; import UserHeader from "@/components/UserHeader.vue";
import Signin from "@/components/Signin.vue"; import Signin from "@/components/Signin.vue";
import BubbleTip from "@/components/BubbleTip.vue"; import BubbleTip from "@/components/BubbleTip.vue";
import { import {
checkUserBindAPI,
getAppConfig, getAppConfig,
getRankListAPI, getDeviceBatteryAPI,
getHomeData, getHomeData,
getMyDevicesAPI, getMyDevicesAPI,
getDeviceBatteryAPI, getRankListAPI,
silentLoginAPI,
} from "@/apis"; } from "@/apis";
import { topThreeColors } from "@/constants"; import {topThreeColors} from "@/constants";
import { canEenter } from "@/util";
import useStore from "@/store"; import useStore from "@/store";
import { storeToRefs } from "pinia"; import {storeToRefs} from "pinia";
const store = useStore(); const store = useStore();
const { const {
updateConfig, updateConfig,
@@ -30,7 +31,7 @@ const {
getLvlNameByScore, getLvlNameByScore,
updateOnline, updateOnline,
} = store; } = store;
const { user, device, rankData, online, game } = storeToRefs(store); const {user, device, rankData, online, game} = storeToRefs(store);
const showModal = ref(false); const showModal = ref(false);
const showGuide = ref(false); const showGuide = ref(false);
@@ -45,7 +46,7 @@ const toPage = async (path) => {
// await uni.$checkAudio(); // await uni.$checkAudio();
// } // }
// } // }
uni.navigateTo({ url: path }); uni.navigateTo({url: path});
}; };
const toRankListPage = () => { const toRankListPage = () => {
@@ -55,12 +56,36 @@ const toRankListPage = () => {
}; };
onShow(async () => { onShow(async () => {
const token = uni.getStorageSync( const env = uni.getAccountInfoSync().miniProgram.envVersion;
`${uni.getAccountInfoSync().miniProgram.envVersion}_token` const token = uni.getStorageSync(`${env}_token`);
if (!user.value.id && !token) {
try {
const wxResult = await uni.login({provider: "weixin"});
const bindResult = await checkUserBindAPI(wxResult.code);
if (bindResult.binded) {
const newResult = await uni.login({provider: "weixin"});
const silentResult = await silentLoginAPI(newResult.code);
if (silentResult.user) updateUser(silentResult.user);
const devices = await getMyDevicesAPI();
if (devices.bindings && devices.bindings.length) {
updateDevice(
devices.bindings[0].deviceId,
devices.bindings[0].deviceName
); );
const data = await getDeviceBatteryAPI();
updateOnline(data.online);
}
} else {
showModal.value = true;
}
} catch (e) {
console.log("检查绑定状态失败", e);
}
}
const promises = [getRankListAPI()]; const promises = [getRankListAPI()];
if (token) { if (token || user.value.id) {
promises.push(getHomeData()); promises.push(getHomeData());
} }
@@ -131,7 +156,7 @@ onShareTimeline(() => {
mode="widthFix" mode="widthFix"
/> />
</view> </view>
<UserHeader showRank :onSignin="() => (showModal = true)" /> <UserHeader showRank :onSignin="() => (showModal = true)"/>
<view :style="{ padding: '12px 10px' }"> <view :style="{ padding: '12px 10px' }">
<view class="feature-grid"> <view class="feature-grid">
<view class="bow-card"> <view class="bow-card">
@@ -164,10 +189,10 @@ onShareTimeline(() => {
</view> </view>
<view class="play-card"> <view class="play-card">
<view @click="() => toPage('/pages/practise')"> <view @click="() => toPage('/pages/practise')">
<image src="../static/my-practise.png" mode="widthFix" /> <image src="../static/my-practise.png" mode="widthFix"/>
</view> </view>
<view @click="() => toPage('/pages/friend-battle')"> <view @click="() => toPage('/pages/friend-battle')">
<image src="../static/friend-battle.png" mode="widthFix" /> <image src="../static/friend-battle.png" mode="widthFix"/>
</view> </view>
</view> </view>
</view> </view>
@@ -182,7 +207,7 @@ onShareTimeline(() => {
hover-class="none" hover-class="none"
></button> ></button>
<view class="ranking-players" @click="toRankListPage"> <view class="ranking-players" @click="toRankListPage">
<img src="../static/juezhanbang.png" mode="widthFix" /> <img src="../static/juezhanbang.png" mode="widthFix"/>
<view class="divide-line"></view> <view class="divide-line"></view>
<view class="player-avatars"> <view class="player-avatars">
<view <view
@@ -196,9 +221,9 @@ onShareTimeline(() => {
: '#000', : '#000',
}" }"
> >
<image v-if="i === 1" src="../static/champ1.png" /> <image v-if="i === 1" src="../static/champ1.png"/>
<image v-if="i === 2" src="../static/champ2.png" /> <image v-if="i === 2" src="../static/champ2.png"/>
<image v-if="i === 3" src="../static/champ3.png" /> <image v-if="i === 3" src="../static/champ3.png"/>
<view v-if="i > 3">{{ i }}</view> <view v-if="i > 3">{{ i }}</view>
<image <image
:src=" :src="
@@ -216,14 +241,15 @@ onShareTimeline(() => {
</view> </view>
<view class="my-data"> <view class="my-data">
<view @click="() => toPage('/pages/my-growth')"> <view @click="() => toPage('/pages/my-growth')">
<image src="../static/my-growth.png" mode="widthFix" /> <image src="../static/my-growth.png" mode="widthFix"/>
</view> </view>
<view @click="() => toPage('/pages/ranking')"> <view @click="() => toPage('/pages/ranking')">
<view> <view>
<text>段位</text> <text>段位</text>
<text>{{ <text>{{
user.lvlName || "暂无" user.lvlName || "暂无"
}}</text> }}
</text>
</view> </view>
<view> <view>
<text>赛季平均环数</text> <text>赛季平均环数</text>
@@ -235,15 +261,16 @@ onShareTimeline(() => {
user.avg_win user.avg_win
? Number((user.avg_win * 100).toFixed(2)) + "%" ? Number((user.avg_win * 100).toFixed(2)) + "%"
: "暂无" : "暂无"
}}</text> }}
</text>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<Signin :show="showModal" :onClose="() => (showModal = false)" /> <Signin :show="showModal" :onClose="() => (showModal = false)"/>
</view> </view>
<AppFooter /> <AppFooter/>
</Container> </Container>
</template> </template>
@@ -364,6 +391,7 @@ onShareTimeline(() => {
width: 32rpx; width: 32rpx;
height: 32rpx; height: 32rpx;
} }
.player-avatar > view:first-child { .player-avatar > view:first-child {
border-radius: 50%; border-radius: 50%;
background: #777777; background: #777777;
@@ -374,6 +402,7 @@ onShareTimeline(() => {
height: 18px; height: 18px;
color: #fff; color: #fff;
} }
.player-avatar > image:last-child { .player-avatar > image:last-child {
width: 100%; width: 100%;
height: 100%; height: 100%;
@@ -392,18 +421,22 @@ onShareTimeline(() => {
margin-left: 2px; margin-left: 2px;
color: #fff; color: #fff;
} }
.my-data { .my-data {
display: flex; display: flex;
margin-top: 20px; margin-top: 20px;
justify-content: space-between; justify-content: space-between;
} }
.my-data > view:first-child { .my-data > view:first-child {
width: 28%; width: 28%;
} }
.my-data > view:first-child > image { .my-data > view:first-child > image {
width: 100%; width: 100%;
transform: translateX(-8px); transform: translateX(-8px);
} }
.my-data > view:nth-child(2) { .my-data > view:nth-child(2) {
width: 68%; width: 68%;
font-size: 12px; font-size: 12px;
@@ -411,9 +444,11 @@ onShareTimeline(() => {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
} }
.my-data > view:nth-child(2) > view:nth-child(2) { .my-data > view:nth-child(2) > view:nth-child(2) {
width: 38%; width: 38%;
} }
.my-data > view:nth-child(2) > view { .my-data > view:nth-child(2) > view {
width: 28%; width: 28%;
border-radius: 10px; border-radius: 10px;
@@ -423,11 +458,13 @@ onShareTimeline(() => {
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.my-data > view:nth-child(2) > view > text:last-child { .my-data > view:nth-child(2) > view > text:last-child {
color: #fff; color: #fff;
line-height: 25px; line-height: 25px;
font-weight: 500; font-weight: 500;
} }
.top-theme { .top-theme {
position: absolute; position: absolute;
display: flex; display: flex;
@@ -437,6 +474,7 @@ onShareTimeline(() => {
height: 60px; height: 60px;
z-index: -1; z-index: -1;
} }
.top-theme > image { .top-theme > image {
width: 300rpx; width: 300rpx;
transform: translate(-4%, -14%); transform: translate(-4%, -14%);