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

@@ -1,477 +1,498 @@
let BASE_URL = "https://api.shelingxingqiu.com/api/shoot"; // 默认正式版 let BASE_URL = "https://api.shelingxingqiu.com/api/shoot"; // 默认正式版
try { try {
const accountInfo = uni.getAccountInfoSync(); const accountInfo = uni.getAccountInfoSync();
const envVersion = accountInfo.miniProgram.envVersion; const envVersion = accountInfo.miniProgram.envVersion;
switch (envVersion) { switch (envVersion) {
case "develop": // 开发版 case "develop": // 开发版
BASE_URL = "http://localhost:8000/api/shoot"; BASE_URL = "http://localhost:8000/api/shoot";
// BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; // BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
break; break;
case "trial": // 体验版 case "trial": // 体验版
BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot"; BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
break; break;
case "release": // 正式版 case "release": // 正式版
BASE_URL = "https://api.shelingxingqiu.com/api/shoot"; BASE_URL = "https://api.shelingxingqiu.com/api/shoot";
break; break;
default: default:
// 保持默认值 // 保持默认值
break; break;
} }
} catch (e) { } catch (e) {
console.error("获取环境信息失败,使用默认正式环境", e); console.error("获取环境信息失败,使用默认正式环境", e);
} }
function request(method, url, data = {}) { function request(method, url, data = {}) {
const token = uni.getStorageSync( const token = uni.getStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token` `${uni.getAccountInfoSync().miniProgram.envVersion}_token`
); );
const header = {}; const header = {};
if (token) header.Authorization = `Bearer ${token || ""}`; if (token) header.Authorization = `Bearer ${token || ""}`;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.request({ uni.request({
url: `${BASE_URL}${url}`, url: `${BASE_URL}${url}`,
method, method,
header, header,
data, 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) {
uni.removeStorageSync( uni.removeStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token` `${uni.getAccountInfoSync().miniProgram.envVersion}_token`
); );
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") {
resolve({}); resolve({});
return; return;
} }
if (message === "ERROR_BATTLE_GAMING") { if (message === "ERROR_BATTLE_GAMING") {
resolve({}); resolve({});
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") {
uni.showToast({ uni.showToast({
title: "当前有未支付订单", title: "当前有未支付订单",
icon: "none", icon: "none",
}); });
resolve({}); resolve({});
return; return;
} }
if (message === "ROOM_EMPTY") { if (message === "ROOM_EMPTY") {
return uni.showToast({ return uni.showToast({
title: "房间已过期", title: "房间已过期",
icon: "none", icon: "none",
}); });
} }
uni.showToast({ uni.showToast({
title: message, title: message,
icon: "none", icon: "none",
}); });
} }
reject(""); reject("");
} }
}, },
fail: (err) => { fail: (err) => {
handleRequestError(err, url); handleRequestError(err, url);
reject(err); reject(err);
}, },
});
}); });
});
} }
// 统一的错误处理函数 // 统一的错误处理函数
function handleRequestError(err, url) { function handleRequestError(err, url) {
console.log("请求失败:", { err, url }); console.log("请求失败:", {err, url});
// 根据错误类型显示不同提示 // 根据错误类型显示不同提示
if (err.errMsg) { if (err.errMsg) {
if (err.errMsg.includes("timeout")) { if (err.errMsg.includes("timeout")) {
showCustomToast("请求超时,请稍后重试", "timeout"); showCustomToast("请求超时,请稍后重试", "timeout");
} else if (err.errMsg.includes("fail")) { } else if (err.errMsg.includes("fail")) {
// 检查网络状态 // 检查网络状态
uni.getNetworkType({ uni.getNetworkType({
success: (res) => { success: (res) => {
if (res.networkType === "none") { if (res.networkType === "none") {
showCustomToast("网络连接已断开,请检查网络设置", "network"); showCustomToast("网络连接已断开,请检查网络设置", "network");
} else { } else {
showCustomToast("服务器连接失败,请稍后重试", "server"); showCustomToast("服务器连接失败,请稍后重试", "server");
} }
}, },
fail: () => { fail: () => {
showCustomToast("网络异常,请检查网络连接", "unknown"); showCustomToast("网络异常,请检查网络连接", "unknown");
}, },
}); });
} else {
showCustomToast("请求失败,请稍后重试", "general");
}
} else { } else {
showCustomToast("请求失败,请稍后重试", "general"); showCustomToast("网络异常,请稍后重试", "unknown");
} }
} else {
showCustomToast("网络异常,请稍后重试", "unknown");
}
} }
// 自定义提示函数 // 自定义提示函数
function showCustomToast(message, type) { function showCustomToast(message, type) {
const config = { const config = {
title: message, title: message,
icon: "none", icon: "none",
duration: 3000, duration: 3000,
}; };
// 根据错误类型可以添加不同的处理逻辑 // 根据错误类型可以添加不同的处理逻辑
switch (type) { switch (type) {
case "timeout": case "timeout":
config.duration = 4000; // 超时提示显示更久 config.duration = 4000; // 超时提示显示更久
break; break;
case "network": case "network":
config.duration = 5000; // 网络问题提示显示更久 config.duration = 5000; // 网络问题提示显示更久
break; break;
default: default:
break; break;
} }
uni.showToast(config); uni.showToast(config);
} }
// 获取全局配置 // 获取全局配置
export const getAppConfig = () => { export const getAppConfig = () => {
return request("GET", "/index/appConfig"); return request("GET", "/index/appConfig");
}; };
export const getHomeData = (seasonId) => { export const getHomeData = (seasonId) => {
return request("GET", `/user/myHome?seasonId=${seasonId}`); return request("GET", `/user/myHome?seasonId=${seasonId}`);
}; };
export const getProvinceData = () => { export const getProvinceData = () => {
return request("GET", "/index/provinces/list"); return request("GET", "/index/provinces/list");
}; };
export const loginAPI = async (phone, nickName, avatarData, code) => { export const loginAPI = async (phone, nickName, avatarData, code) => {
const result = await request("POST", "/index/code", { const result = await request("POST", "/index/code", {
appName: "shoot", appName: "shoot",
appId: "wxa8f5989dcd45cc23", appId: "wxa8f5989dcd45cc23",
nickName, nickName,
avatarData, avatarData,
code, code,
phone, phone,
}); });
uni.setStorageSync( uni.setStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token`, `${uni.getAccountInfoSync().miniProgram.envVersion}_token`,
result.token result.token
); );
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,
}); });
}; };
export const bindDeviceAPIV2 = (token) => { export const bindDeviceAPIV2 = (token) => {
return request("POST", "/user/device/bindDevice/v2", { return request("POST", "/user/device/bindDevice/v2", {
token: token, token: token,
}); });
}; };
export const unbindDeviceAPI = (deviceId) => { export const unbindDeviceAPI = (deviceId) => {
return request("POST", "/user/device/unbindDevice", { return request("POST", "/user/device/unbindDevice", {
deviceId, deviceId,
}); });
}; };
export const getMyDevicesAPI = () => { export const getMyDevicesAPI = () => {
// "/user/device/getBinding?deviceId=9ZF9oVXs" // "/user/device/getBinding?deviceId=9ZF9oVXs"
return request("GET", "/user/device/getBindings"); return request("GET", "/user/device/getBindings");
}; };
export const createPractiseAPI = (arrows, time, target) => { 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,
}); });
}; };
export const startPractiseAPI = () => { export const startPractiseAPI = () => {
return request("POST", "/user/practice/begin"); return request("POST", "/user/practice/begin");
}; };
export const endPractiseAPI = () => { export const endPractiseAPI = () => {
return request("POST", "/user/practice/stop"); return request("POST", "/user/practice/stop");
}; };
export const getPractiseAPI = async (id) => { export const getPractiseAPI = async (id) => {
return request("GET", `/user/practice/get?id=${id}`); return request("GET", `/user/practice/get?id=${id}`);
}; };
export const createRoomAPI = (gameType, teamSize, targetType) => { export const createRoomAPI = (gameType, teamSize, targetType) => {
return request("POST", "/user/createroom", { return request("POST", "/user/createroom", {
gameType, gameType,
teamSize, teamSize,
targetType, targetType,
}); });
}; };
export const getRoomAPI = (number) => { export const getRoomAPI = (number) => {
return request("GET", `/user/room?number=${number}`); return request("GET", `/user/room?number=${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) => {
return request("POST", "/user/room/destroyRoom", { return request("POST", "/user/room/destroyRoom", {
roomNumber, roomNumber,
}); });
}; };
export const exitRoomAPI = (number, userId) => { export const exitRoomAPI = (number, userId) => {
return request("POST", "/user/room/exitRoom", { return request("POST", "/user/room/exitRoom", {
number, number,
userId, 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) => {
const reuslt = await request( const reuslt = await request(
"GET", "GET",
`/user/practice/list?page=${page}&page_size=${page_size}` `/user/practice/list?page=${page}&page_size=${page_size}`
); );
return reuslt.list; return reuslt.list;
}; };
export const matchGameAPI = (match, gameType, teamSize) => { export const matchGameAPI = (match, gameType, teamSize) => {
return request("POST", "/user/game/match", { return request("POST", "/user/game/match", {
match, match,
gameType, gameType,
teamSize, teamSize,
readyTime: 15, readyTime: 15,
targetType: 20, targetType: 20,
}); });
}; };
export const readyGameAPI = (battleId) => { export const readyGameAPI = (battleId) => {
return request("POST", "/user/game/prepare", { return request("POST", "/user/game/prepare", {
battleId, battleId,
}); });
}; };
export const simulShootAPI = (device_id, x, y) => { export const simulShootAPI = (device_id, x, y) => {
const data = { const data = {
device_id, device_id,
}; };
if (x !== undefined && y !== undefined) { if (x !== undefined && y !== undefined) {
data.x = x; data.x = x;
data.y = y; data.y = y;
} }
return request("POST", "/index/arrow", data); return request("POST", "/index/arrow", data);
}; };
export const getBattleListAPI = async (page, battleType) => { export const getBattleListAPI = async (page, battleType) => {
const result = await request("POST", "/user/battle/details/list", { const result = await request("POST", "/user/battle/details/list", {
page, page,
pageSize: 10, pageSize: 10,
battleType, battleType,
}); });
return result.list; return result.list;
}; };
export const getRankListAPI = () => { export const getRankListAPI = () => {
return request("GET", "/index/ranklist"); return request("GET", "/index/ranklist");
}; };
export const createOrderAPI = (vipId) => { export const createOrderAPI = (vipId) => {
return request("POST", "/user/order/create", { return request("POST", "/user/order/create", {
vipId, vipId,
quanity: 1, quanity: 1,
tradeType: "mini", tradeType: "mini",
payType: "wxpay", payType: "wxpay",
}); });
}; };
export const payOrderAPI = (id) => { export const payOrderAPI = (id) => {
return request("POST", "/user/order/pay", { return request("POST", "/user/order/pay", {
id, id,
tradeType: "mini", tradeType: "mini",
payType: "wxpay", payType: "wxpay",
}); });
}; };
export const getOrderListAPI = async (page) => { export const getOrderListAPI = async (page) => {
const reuslt = await request("GET", `/user/order/list?page=${page}`); const reuslt = await request("GET", `/user/order/list?page=${page}`);
return reuslt.items || []; return reuslt.items || [];
}; };
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 = () => {
return request("GET", "/user/state"); return request("GET", "/user/state");
}; };
export const getPointBookConfigAPI = async () => { export const getPointBookConfigAPI = async () => {
return request("GET", "/user/score/sheet/option"); return request("GET", "/user/score/sheet/option");
}; };
export const savePointBookAPI = async ( export const savePointBookAPI = async (
bowType,
distance,
targetType,
groups,
arrows,
data = []
) => {
return request("POST", "/user/score/sheet/report", {
bowType, bowType,
distance, distance,
targetType, targetType,
groups, groups,
arrows, arrows,
group_data: data.map((item) => data = []
item.map((i) => ({ ) => {
...i, return request("POST", "/user/score/sheet/report", {
ring: i.ring === "M" ? -1 : i.ring === "X" ? 0 : Number(i.ring), bowType,
})) distance,
), targetType,
}); groups,
arrows,
group_data: data.map((item) =>
item.map((i) => ({
...i,
ring: i.ring === "M" ? -1 : i.ring === "X" ? 0 : Number(i.ring),
}))
),
});
}; };
export const getPointBookListAPI = async ( export const getPointBookListAPI = async (
page = 1, page = 1,
bowType, bowType,
distance, distance,
targetType targetType
) => { ) => {
let url = `/user/score/sheet/list?pageNum=${page}&pageSize=10`; let url = `/user/score/sheet/list?pageNum=${page}&pageSize=10`;
if (bowType) url += `&bowType=${bowType}`; if (bowType) url += `&bowType=${bowType}`;
if (distance) url += `&distance=${distance}`; if (distance) url += `&distance=${distance}`;
if (targetType) url += `&targetType=${targetType}`; if (targetType) url += `&targetType=${targetType}`;
const result = await request("GET", url); const result = await request("GET", url);
return result.list || []; return result.list || [];
}; };
export const getPointBookDetailAPI = async (id) => { export const getPointBookDetailAPI = async (id) => {
return request("GET", `/user/score/sheet/detail?id=${id}`); return request("GET", `/user/score/sheet/detail?id=${id}`);
}; };
export const getPointBookDataAPI = async () => { export const getPointBookDataAPI = async () => {
return request("GET", "/user/score/sheet/statistics"); return request("GET", "/user/score/sheet/statistics");
}; };
export const getPractiseDataAPI = async () => { export const getPractiseDataAPI = async () => {
return request("GET", "/user/practice/statistics"); return request("GET", "/user/practice/statistics");
}; };
export const getBattleDataAPI = async () => { export const getBattleDataAPI = async () => {
return request("GET", "/user/fight/statistics"); return request("GET", "/user/fight/statistics");
}; };
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 () => {
return request("GET", "/index/memberVipDescribe"); return request("GET", "/index/memberVipDescribe");
}; };
export const getPointBookStatisticsAPI = async () => { export const getPointBookStatisticsAPI = async () => {
return request("GET", `/v2/user/score/sheet/statistics`); return request("GET", `/v2/user/score/sheet/statistics`);
}; };
export const donateAPI = async (amount, name, phone, organizer, advice) => { export const donateAPI = async (amount, name, phone, organizer, advice) => {
return request("POST", `/user/donate`, { return request("POST", `/user/donate`, {
amount, amount,
name, name,
phone, phone,
organizer, organizer,
advice, advice,
}); });
}; };
export const laserAimAPI = async () => { export const laserAimAPI = async () => {
return request("POST", "/user/device/laserAim"); return request("POST", "/user/device/laserAim");
}; };
export const laserCloseAPI = async () => { export const laserCloseAPI = async () => {
return request("POST", "/user/device/closeAim"); return request("POST", "/user/device/closeAim");
}; };
export const getDeviceBatteryAPI = async () => { export const getDeviceBatteryAPI = async () => {
return request("GET", "/user/device/battery"); return request("GET", "/user/device/battery");
}; };
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) => {
return request("DELETE", `/user/score/sheet/delete?id=${id}`); return request("DELETE", `/user/score/sheet/delete?id=${id}`);
}; };
export const getPhoneNumberAPI = (data) => { export const getPhoneNumberAPI = (data) => {
return request("POST", "/index/getPhone", data); return request("POST", "/index/getPhone", data);
}; };
export const getPointBookRankListAPI = (page = 1) => { export const getPointBookRankListAPI = (page = 1) => {
return request( return request(
"GET", "GET",
`/user/score/sheet/week/shoot/rank/list?pageNum=${page}&pageSize=100` `/user/score/sheet/week/shoot/rank/list?pageNum=${page}&pageSize=100`
); );
}; };
export const clickLikeAPI = (userId, ifLike) => { export const clickLikeAPI = (userId, ifLike) => {
return request("POST", "/user/score/sheet/week/shoot/rank/like", { return request("POST", "/user/score/sheet/week/shoot/rank/like", {
userId, userId,
ifLike, ifLike,
}); });
}; };
export const getMyLikeList = (page = 1, pageSize = 10) => { export const getMyLikeList = (page = 1, pageSize = 10) => {
return request( return request(
"GET", "GET",
`/user/score/sheet/week/shoot/rank/like/list?pageNum=${page}&pageSize=${pageSize}` `/user/score/sheet/week/shoot/rank/like/list?pageNum=${page}&pageSize=${pageSize}`
); );
}; };
export const getReadyAPI = (roomId) => { export const getReadyAPI = (roomId) => {
return request("POST", `/user/room/ready`, { return request("POST", `/user/room/ready`, {
roomId, roomId,
}); });
}; };
export const getBattleAPI = async (battleId) => { export const getBattleAPI = async (battleId) => {
return request("POST", "/user/match/info", { return request("POST", "/user/match/info", {
id: battleId, id: battleId,
}); });
}; };
export const kickPlayerAPI = (number, userId) => { export const kickPlayerAPI = (number, userId) => {
return request("POST", "/user/room/kicking", { return request("POST", "/user/room/kicking", {
number, number,
userId, userId,
}); });
}; };

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());
} }
@@ -88,8 +113,8 @@ onShow(async () => {
const devices = await getMyDevicesAPI(); const devices = await getMyDevicesAPI();
if (devices.bindings && devices.bindings.length) { if (devices.bindings && devices.bindings.length) {
updateDevice( updateDevice(
devices.bindings[0].deviceId, devices.bindings[0].deviceId,
devices.bindings[0].deviceName devices.bindings[0].deviceName
); );
const data = await getDeviceBatteryAPI(); const data = await getDeviceBatteryAPI();
updateOnline(data.online); updateOnline(data.online);
@@ -109,7 +134,7 @@ onShareAppMessage(() => {
title: "智能真弓:实时捕捉+毫秒级同步,弓箭选手全球竞技!", // 分享卡片的标题 title: "智能真弓:实时捕捉+毫秒级同步,弓箭选手全球竞技!", // 分享卡片的标题
path: "/pages/index", // 用户点击分享卡片后跳转的页面路径 path: "/pages/index", // 用户点击分享卡片后跳转的页面路径
imageUrl: imageUrl:
"https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png", // 分享卡片的配图,可以是本地或网络图片 "https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png", // 分享卡片的配图,可以是本地或网络图片
}; };
}); });
onShareTimeline(() => { onShareTimeline(() => {
@@ -117,7 +142,7 @@ onShareTimeline(() => {
title: "智能真弓:实时捕捉+毫秒级同步,弓箭选手全球竞技!", // 分享到朋友圈的标题 title: "智能真弓:实时捕捉+毫秒级同步,弓箭选手全球竞技!", // 分享到朋友圈的标题
query: "from=timeline", // 用户通过朋友圈点击后,在页面 onShow 的 options 中可以获取到的参数 query: "from=timeline", // 用户通过朋友圈点击后,在页面 onShow 的 options 中可以获取到的参数
imageUrl: imageUrl:
"https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png", // 分享到朋友圈的配图 "https://static.shelingxingqiu.com/attachment/2025-09-12/dcqoz26q0268wxmzjg.png", // 分享到朋友圈的配图
}; };
}); });
</script> </script>
@@ -127,25 +152,25 @@ onShareTimeline(() => {
<view class="container"> <view class="container">
<view class="top-theme"> <view class="top-theme">
<image <image
src="https://static.shelingxingqiu.com/attachment/2025-12-31/dfc9dxrq4xn7e6y2pp.png" src="https://static.shelingxingqiu.com/attachment/2025-12-31/dfc9dxrq4xn7e6y2pp.png"
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">
<image <image
v-if="online" v-if="online"
src="https://static.shelingxingqiu.com/attachment/2025-08-07/dbvt1o6dvhr2rop3kn.webp" src="https://static.shelingxingqiu.com/attachment/2025-08-07/dbvt1o6dvhr2rop3kn.webp"
mode="widthFix" mode="widthFix"
@click="() => toPage('/pages/my-device')" @click="() => toPage('/pages/my-device')"
/> />
<image <image
v-else v-else
src="https://static.shelingxingqiu.com/attachment/2026-01-04/dffohwtk1gwh0xfa6h.png" src="https://static.shelingxingqiu.com/attachment/2026-01-04/dffohwtk1gwh0xfa6h.png"
mode="widthFix" mode="widthFix"
@click="() => toPage('/pages/my-device')" @click="() => toPage('/pages/my-device')"
/> />
<block v-if="user.id"> <block v-if="user.id">
<text v-if="!device.deviceId">绑定我的智能弓</text> <text v-if="!device.deviceId">绑定我的智能弓</text>
@@ -153,9 +178,9 @@ onShareTimeline(() => {
<text v-else-if="online">设备在线</text> <text v-else-if="online">设备在线</text>
</block> </block>
<image <image
src="../static/first-try.png" src="../static/first-try.png"
mode="widthFix" mode="widthFix"
@click="() => toPage('/pages/first-try')" @click="() => toPage('/pages/first-try')"
/> />
<BubbleTip v-if="showGuide" :location="{ top: '60%', left: '47%' }"> <BubbleTip v-if="showGuide" :location="{ top: '60%', left: '47%' }">
<text>新人必刷</text> <text>新人必刷</text>
@@ -164,49 +189,49 @@ 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>
<view class="ranking-section"> <view class="ranking-section">
<image <image
src="https://static.shelingxingqiu.com/attachment/2025-09-25/dd1p9ci9v7frcrsxhj.png" src="https://static.shelingxingqiu.com/attachment/2025-09-25/dd1p9ci9v7frcrsxhj.png"
mode="widthFix" mode="widthFix"
/> />
<button <button
class="into-btn" class="into-btn"
@click="() => toPage('/pages/ranking')" @click="() => toPage('/pages/ranking')"
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
v-for="i in 6" v-for="i in 6"
:key="i" :key="i"
class="player-avatar" class="player-avatar"
:style="{ :style="{
zIndex: 8 - i, zIndex: 8 - i,
borderColor: rankData.rank[i - 1] borderColor: rankData.rank[i - 1]
? topThreeColors[i - 1] || '#000' ? topThreeColors[i - 1] || '#000'
: '#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="
rankData.rank[i - 1] rankData.rank[i - 1]
? rankData.rank[i - 1].avatar ? rankData.rank[i - 1].avatar
: '../static/user-icon-dark.png' : '../static/user-icon-dark.png'
" "
mode="aspectFill" mode="aspectFill"
/> />
</view> </view>
<view class="more-players"> <view class="more-players">
@@ -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>
@@ -232,18 +258,19 @@ onShareTimeline(() => {
<view> <view>
<text>赛季胜率</text> <text>赛季胜率</text>
<text>{{ <text>{{
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%);