update:分包、对接个人练习

This commit is contained in:
2026-07-09 17:53:29 +08:00
parent ac4d8dfb38
commit 82eedc3ab8
49 changed files with 911 additions and 181 deletions
+234 -1
View File
@@ -3,7 +3,240 @@
"compileType": "miniprogram",
"libVersion": "3.7.7",
"packOptions": {
"ignore": [],
"ignore": [
{
"type": "file",
"value": "static/common/dialog-light.png"
},
{
"type": "file",
"value": "static/common/dialog-bg.png"
},
{
"type": "file",
"value": "static/common/dialog-icon.png"
},
{
"type": "file",
"value": "static/prompt-bg-square.png"
},
{
"type": "file",
"value": "static/coach-comment.png"
},
{
"type": "file",
"value": "static/screen-hint-bg.png"
},
{
"type": "file",
"value": "static/red-team-win.png"
},
{
"type": "file",
"value": "static/blue-team-win.png"
},
{
"type": "file",
"value": "static/my-grow.png"
},
{
"type": "file",
"value": "static/gold-shining.png"
},
{
"type": "file",
"value": "static/bow-target.png"
},
{
"type": "file",
"value": "static/matching-bg.png"
},
{
"type": "file",
"value": "static/versus.png"
},
{
"type": "file",
"value": "static/point-champion.png"
},
{
"type": "file",
"value": "static/my-practise.png"
},
{
"type": "file",
"value": "static/shining-bg.png"
},
{
"type": "file",
"value": "static/donate.png"
},
{
"type": "file",
"value": "static/friend-battle.png"
},
{
"type": "file",
"value": "static/user-upgrade.png"
},
{
"type": "file",
"value": "static/finish-frame.png"
},
{
"type": "file",
"value": "static/vip/svip-jian.png"
},
{
"type": "file",
"value": "static/battle-header.png"
},
{
"type": "file",
"value": "static/battle-header-melee.png"
},
{
"type": "file",
"value": "static/player-bg.png"
},
{
"type": "file",
"value": "static/mvp-blue.png"
},
{
"type": "file",
"value": "static/finish-tip.png"
},
{
"type": "file",
"value": "static/2unfinish-tip.png"
},
{
"type": "file",
"value": "static/have-no-device.png"
},
{
"type": "file",
"value": "static/device-icon.png"
},
{
"type": "file",
"value": "static/unfinish-tip.png"
},
{
"type": "file",
"value": "static/test-tip.png"
},
{
"type": "file",
"value": "static/mvp-red.png"
},
{
"type": "file",
"value": "static/vip/svip-lie.png"
},
{
"type": "file",
"value": "static/mvp-tip.png"
},
{
"type": "file",
"value": "static/rank/battle-choose.png"
},
{
"type": "file",
"value": "static/back-to-game-bg.png"
},
{
"type": "file",
"value": "static/complete-light1.png"
},
{
"type": "file",
"value": "static/complete-light2.png"
},
{
"type": "file",
"value": "static/title-2v2.png"
},
{
"type": "file",
"value": "static/tab-bg.png"
},
{
"type": "file",
"value": "static/scan.png"
},
{
"type": "file",
"value": "static/choose-battle-mode.png"
},
{
"type": "file",
"value": "static/shooter.png"
},
{
"type": "file",
"value": "static/my-growth.png"
},
{
"type": "file",
"value": "static/juezhanbang.png"
},
{
"type": "file",
"value": "static/title-3v3.png"
},
{
"type": "file",
"value": "static/point-book-tip-bg.png"
},
{
"type": "file",
"value": "static/reward-us.png"
},
{
"type": "file",
"value": "static/rank/star.png"
},
{
"type": "file",
"value": "static/tab-point-book.png"
},
{
"type": "file",
"value": "static/pk-icon.png"
},
{
"type": "file",
"value": "static/first-try.png"
},
{
"type": "file",
"value": "static/row-yellow-bg.png"
},
{
"type": "file",
"value": "static/room-notfound-title.png"
},
{
"type": "file",
"value": "static/title-mvp.png"
},
{
"type": "file",
"value": "static/long-bubble-tall.png"
},
{
"type": "file",
"value": "static/battle-result.png"
},
{
"type": "file",
"value": "static/tab-mall.png"
}
],
"include": []
},
"setting": {
+12 -2
View File
@@ -8,8 +8,8 @@ try {
switch (envVersion) {
case "develop": // 开发版
// BASE_URL = "http://192.168.1.2:8000/api/shoot";
BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
BASE_URL = "http://192.168.1.2:8000/api/shoot";
// BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
break;
case "trial": // 体验版
BASE_URL = "https://apitest.shelingxingqiu.com/api/shoot";
@@ -26,6 +26,7 @@ try {
}
const ADDONS_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api/shoot");
const PRACTICE_BASE_URL = BASE_URL.replace(/\/api\/shoot$/, "/api");
// 统一处理业务接口请求,包含登录态、业务错误和 WiFi 连接空响应兼容。
function request(method, url, data = {}, baseUrl = BASE_URL) {
@@ -263,6 +264,15 @@ export const createPractiseAPI = (arrows, time, target) => {
});
};
export const createPractiseV2API = (arrows, time, target, deviceId) => {
return request("POST", "/practice/create-v2", {
shootNumber: arrows,
shootTime: time,
targetType: Number(target || 1) * 20,
deviceId,
}, PRACTICE_BASE_URL);
};
export const startPractiseAPI = () => {
return request("POST", "/user/practice/begin");
};
+3 -3
View File
@@ -1,8 +1,8 @@
<script setup>
const tabs = [
{ image: "../static/tab-vip.png" },
{ image: "../static/tab-point-book.png" },
{ image: "../static/tab-mall.png" },
{ image: "https://static.shelingxingqiu.com/shootmini/static/tab-point-book.png" },
{ image: "https://static.shelingxingqiu.com/shootmini/static/tab-mall.png" },
];
function handleTabClick(index) {
@@ -26,7 +26,7 @@ function handleTabClick(index) {
<template>
<view class="footer">
<image class="footer-bg" src="../static/tab-bg.png" mode="widthFix" />
<image class="footer-bg" src="https://static.shelingxingqiu.com/shootmini/static/tab-bg.png" mode="widthFix" />
<view
v-for="(tab, index) in tabs"
:key="index"
+2 -2
View File
@@ -97,9 +97,9 @@ onBeforeUnmount(() => {
class="back-to-game"
@click="onClick"
>
<image src="../static/back-to-game-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/back-to-game-bg.png" mode="widthFix" />
<block v-if="game.inBattle">
<image src="../static/pk-icon.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/pk-icon.png" mode="widthFix" />
<text>返回进行中的对局</text>
</block>
<block v-else-if="game.roomID">
+2 -2
View File
@@ -31,7 +31,7 @@ const normalRounds = computed(() => {
<template>
<view class="container">
<view class="guide-row">
<image src="../static/shooter.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shooter.png" mode="widthFix" />
<view
:style="{
marginBottom: '10px',
@@ -42,7 +42,7 @@ const normalRounds = computed(() => {
</view>
</view>
<view>
<image src="../static/battle-header-melee.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/battle-header-melee.png" mode="widthFix" />
<text>蓝队({{ bluePoints }})</text>
<text>红队({{ redPoints }})</text>
</view>
+1 -1
View File
@@ -41,7 +41,7 @@ const isMember = (player = {}) => player.vip === true || player.sVip === true;
<view class="container" :style="{ paddingTop: showHeader ? '5px' : '0' }">
<image
v-if="showHeader"
:src="`../static/battle-header${players.length ? '-melee' : ''}.png`"
:src="`https://static.shelingxingqiu.com/shootmini/static/battle-header${players.length ? '-melee' : ''}.png`"
mode="widthFix"
/>
<view
+2 -2
View File
@@ -246,7 +246,7 @@ onBeforeUnmount(() => {
>
<image
class="shot-arrow"
src="../static/vip/svip-jian.png"
src="https://static.shelingxingqiu.com/shootmini/static/vip/svip-jian.png"
mode="heightFix"
/>
</view>
@@ -263,7 +263,7 @@ onBeforeUnmount(() => {
<image
:key="`crack-${animationKey}`"
class="shot-crack"
src="../static/vip/svip-lie.png"
src="https://static.shelingxingqiu.com/shootmini/static/vip/svip-lie.png"
mode="aspectFit"
@animationend="handleCrackAnimationEnd"
/>
+1 -1
View File
@@ -505,7 +505,7 @@ onBeforeUnmount(() => {
@impact="shakeTarget"
@complete="completeShotEffect"
/>
<image src="../static/bow-target.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/bow-target.png" mode="widthFix" />
</view>
<view class="footer">
<PointSwitcher
+1 -1
View File
@@ -69,7 +69,7 @@ const createRoom = debounce(async () => {
<view class="container">
<view class="target-options-header">
<view class="target-options-header-line-left"></view>
<image class="target-options-header-title-img" src="../static/choose-battle-mode.png" mode="widthFix" />
<image class="target-options-header-title-img" src="https://static.shelingxingqiu.com/shootmini/static/choose-battle-mode.png" mode="widthFix" />
<view class="target-options-header-line-right"></view>
</view>
<view class="create-options">
+2 -2
View File
@@ -12,13 +12,13 @@ defineProps({
const bubbleTypes = [
"../static/long-bubble.png",
"../static/long-bubble-middle.png",
"../static/long-bubble-tall.png",
"https://static.shelingxingqiu.com/shootmini/static/long-bubble-tall.png",
];
</script>
<template>
<view class="container">
<image src="../static/shooter.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shooter.png" mode="widthFix" />
<view>
<image
v-if="!noBg"
+1 -1
View File
@@ -105,7 +105,7 @@ onBeforeUnmount(() => {
<template>
<view class="matching">
<image
src="../static/matching-bg.png"
src="https://static.shelingxingqiu.com/shootmini/static/matching-bg.png"
mode="widthFix"
class="matching-bg"
/>
+3 -3
View File
@@ -52,19 +52,19 @@ const handleConfirm = () => {
<view class="modal-wrap scale-in">
<image
class="dialog-light"
src="../static/common/dialog-light.png"
src="https://static.shelingxingqiu.com/shootmini/static/common/dialog-light.png"
mode="widthFix"
/>
<image
class="dialog-icon"
src="../static/common/dialog-icon.png"
src="https://static.shelingxingqiu.com/shootmini/static/common/dialog-icon.png"
mode="widthFix"
/>
<view class="dialog-panel">
<image
class="dialog-bg"
src="../static/common/dialog-bg.png"
src="https://static.shelingxingqiu.com/shootmini/static/common/dialog-bg.png"
mode="scaleToFill"
/>
<view class="dialog-content">
+1 -1
View File
@@ -26,7 +26,7 @@ const seats = new Array(props.total).fill(1);
<template>
<view class="players">
<view v-for="(_, index) in seats" :key="index">
<image src="../static/player-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/player-bg.png" mode="widthFix" />
<view v-if="players[index] && players[index].name" class="avatar">
<Avatar
:src="players[index].avatar || '../static/user-icon.png'"
+1 -1
View File
@@ -65,7 +65,7 @@ onMounted(() => {
</view>
</view>
<view class="right-part">
<image src="../static/bow-target.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/bow-target.png" mode="widthFix" />
<view class="arrow-amount">
<text>{{ data.actualTotalRing }}</text>
<text>/</text>
+1 -1
View File
@@ -93,7 +93,7 @@ onMounted(async () => {
<template>
<view class="container">
<image src="../static/donate.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/donate.png" mode="widthFix" />
<text>感谢您对我们公益项目的支持</text>
<view class="amounts">
<button
+2 -2
View File
@@ -26,8 +26,8 @@ const items = ref(new Array(props.total).fill(9));
const width = ref(92);
const itemWidth = ref(0);
const bgImages = [
"../static/complete-light1.png",
"../static/complete-light2.png",
"https://static.shelingxingqiu.com/shootmini/static/complete-light1.png",
"https://static.shelingxingqiu.com/shootmini/static/complete-light2.png",
];
const bgIndex = ref(0);
watch(
+1 -1
View File
@@ -81,7 +81,7 @@ const openCoachComment = () => {
<view class="container">
<view :class="['container-header', showPanel ? 'scale-in' : 'scale-out']">
<image :src="tipSrc" mode="widthFix" />
<image src="../static/finish-frame.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/finish-frame.png" mode="widthFix" />
<text
>完成<text class="gold-text">{{ validArrows }}</text
>获得<text class="gold-text">{{ validArrows }}</text
+4 -4
View File
@@ -27,22 +27,22 @@ const getContentHeight = () => {
<view class="scale-in" :style="{ height: getContentHeight() }">
<image
v-if="mode === 'normal'"
src="../static/screen-hint-bg.png"
src="https://static.shelingxingqiu.com/shootmini/static/screen-hint-bg.png"
mode="widthFix"
/>
<image
v-if="mode === 'tall'"
src="../static/coach-comment.png"
src="https://static.shelingxingqiu.com/shootmini/static/coach-comment.png"
mode="widthFix"
/>
<image
v-if="mode === 'square'"
src="../static/prompt-bg-square.png"
src="https://static.shelingxingqiu.com/shootmini/static/prompt-bg-square.png"
mode="widthFix"
/>
<image
v-if="mode === 'small'"
src="../static/finish-frame.png"
src="https://static.shelingxingqiu.com/shootmini/static/finish-frame.png"
mode="widthFix"
/>
<slot />
+1 -1
View File
@@ -20,7 +20,7 @@ const props = defineProps({
<template>
<view class="container" :style="{ display: show ? 'flex' : 'none' }">
<view class="scale-in">
<image src="../static/point-book-tip-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/point-book-tip-bg.png" mode="widthFix" />
<slot />
</view>
<IconButton
+1 -1
View File
@@ -191,7 +191,7 @@ onBeforeUnmount(() => {
<template>
<view class="container" :style="{ display: show ? 'block' : 'none' }">
<view>
<image src="../static/shooter.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shooter.png" mode="widthFix" />
<text>{{ tipContent }}</text>
<button hover-class="none" @click="updateSound">
<image
+1 -1
View File
@@ -111,7 +111,7 @@ onBeforeUnmount(() => {
</view>
</view>
<view v-if="isBattle" class="ready-timer">
<image src="../static/test-tip.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/test-tip.png" mode="widthFix" />
<view v-if="count >= 0">
<text>具体正式比赛还有</text>
<text>{{ count }}</text>
+5 -5
View File
@@ -54,23 +54,23 @@ onBeforeUnmount(() => {
<view v-if="showRank" class="up-rank">
<image :src="user.avatar || '../static/user-icon.png'" mode="widthFix" />
<image :src="nextRankImage" mode="widthFix" />
<image class="bg-effect" src="../static/shining-bg.png" mode="widthFix" />
<image class="bg-effect" src="https://static.shelingxingqiu.com/shootmini/static/shining-bg.png" mode="widthFix" />
<image
class="bg-effect"
src="../static/gold-shining.png"
src="https://static.shelingxingqiu.com/shootmini/static/gold-shining.png"
mode="widthFix"
/>
</view>
<view v-if="showGrade" class="up-grade">
<image
class="scale-in"
src="../static/user-upgrade.png"
src="https://static.shelingxingqiu.com/shootmini/static/user-upgrade.png"
mode="widthFix"
/>
<image class="bg-effect" src="../static/shining-bg.png" mode="widthFix" />
<image class="bg-effect" src="https://static.shelingxingqiu.com/shootmini/static/shining-bg.png" mode="widthFix" />
<image
class="bg-effect"
src="../static/gold-shining.png"
src="https://static.shelingxingqiu.com/shootmini/static/gold-shining.png"
mode="widthFix"
/>
</view>
+236
View File
@@ -53,6 +53,242 @@
"quickapp" : {},
"mp-weixin" : {
"appid" : "wxa8f5989dcd45cc23",
"packOptions" : {
"ignore" : [
{
"type" : "file",
"value" : "static/common/dialog-light.png"
},
{
"type" : "file",
"value" : "static/common/dialog-bg.png"
},
{
"type" : "file",
"value" : "static/common/dialog-icon.png"
},
{
"type" : "file",
"value" : "static/prompt-bg-square.png"
},
{
"type" : "file",
"value" : "static/coach-comment.png"
},
{
"type" : "file",
"value" : "static/screen-hint-bg.png"
},
{
"type" : "file",
"value" : "static/red-team-win.png"
},
{
"type" : "file",
"value" : "static/blue-team-win.png"
},
{
"type" : "file",
"value" : "static/my-grow.png"
},
{
"type" : "file",
"value" : "static/gold-shining.png"
},
{
"type" : "file",
"value" : "static/bow-target.png"
},
{
"type" : "file",
"value" : "static/matching-bg.png"
},
{
"type" : "file",
"value" : "static/versus.png"
},
{
"type" : "file",
"value" : "static/point-champion.png"
},
{
"type" : "file",
"value" : "static/my-practise.png"
},
{
"type" : "file",
"value" : "static/shining-bg.png"
},
{
"type" : "file",
"value" : "static/donate.png"
},
{
"type" : "file",
"value" : "static/friend-battle.png"
},
{
"type" : "file",
"value" : "static/user-upgrade.png"
},
{
"type" : "file",
"value" : "static/finish-frame.png"
},
{
"type" : "file",
"value" : "static/vip/svip-jian.png"
},
{
"type" : "file",
"value" : "static/battle-header.png"
},
{
"type" : "file",
"value" : "static/battle-header-melee.png"
},
{
"type" : "file",
"value" : "static/player-bg.png"
},
{
"type" : "file",
"value" : "static/mvp-blue.png"
},
{
"type" : "file",
"value" : "static/finish-tip.png"
},
{
"type" : "file",
"value" : "static/2unfinish-tip.png"
},
{
"type" : "file",
"value" : "static/have-no-device.png"
},
{
"type" : "file",
"value" : "static/device-icon.png"
},
{
"type" : "file",
"value" : "static/unfinish-tip.png"
},
{
"type" : "file",
"value" : "static/test-tip.png"
},
{
"type" : "file",
"value" : "static/mvp-red.png"
},
{
"type" : "file",
"value" : "static/vip/svip-lie.png"
},
{
"type" : "file",
"value" : "static/mvp-tip.png"
},
{
"type" : "file",
"value" : "static/rank/battle-choose.png"
},
{
"type" : "file",
"value" : "static/back-to-game-bg.png"
},
{
"type" : "file",
"value" : "static/complete-light1.png"
},
{
"type" : "file",
"value" : "static/complete-light2.png"
},
{
"type" : "file",
"value" : "static/title-2v2.png"
},
{
"type" : "file",
"value" : "static/tab-bg.png"
},
{
"type" : "file",
"value" : "static/scan.png"
},
{
"type" : "file",
"value" : "static/choose-battle-mode.png"
},
{
"type" : "file",
"value" : "static/shooter.png"
},
{
"type" : "file",
"value" : "static/my-growth.png"
},
{
"type" : "file",
"value" : "static/juezhanbang.png"
},
{
"type" : "file",
"value" : "static/title-3v3.png"
},
{
"type" : "file",
"value" : "static/point-book-tip-bg.png"
},
{
"type" : "file",
"value" : "static/reward-us.png"
},
{
"type" : "file",
"value" : "static/rank/star.png"
},
{
"type" : "file",
"value" : "static/tab-point-book.png"
},
{
"type" : "file",
"value" : "static/pk-icon.png"
},
{
"type" : "file",
"value" : "static/first-try.png"
},
{
"type" : "file",
"value" : "static/row-yellow-bg.png"
},
{
"type" : "file",
"value" : "static/room-notfound-title.png"
},
{
"type" : "file",
"value" : "static/title-mvp.png"
},
{
"type" : "file",
"value" : "static/long-bubble-tall.png"
},
{
"type" : "file",
"value" : "static/battle-result.png"
},
{
"type" : "file",
"value" : "static/tab-mall.png"
}
]
},
"setting" : {
"urlCheck" : false,
"minified" : true,
+30 -1
View File
@@ -42,6 +42,7 @@ const BUSINESS_TYPE_BY_SERVER_TYPE = {
[ServerMessageType.SERVER_MSG_TIMEOUT]: MESSAGETYPESV2.BattleEnd,
[ServerMessageType.SERVER_MSG_CHECK]: MESSAGETYPESV2.TestDistance,
[ServerMessageType.SERVER_MSG_NOT_ENOUGH_DISTANCE]: MESSAGETYPESV2.InvalidShot,
[ServerMessageType.SERVER_MSG_PRACTICE_END]: MESSAGETYPESV2.BattleEnd,
};
const MATCH_READY_SNAPSHOT_PREFIX = "match-ready-snapshot:";
@@ -57,27 +58,53 @@ function normalizeShootData(shootData) {
}
// 兼容普通接口通知的 camelCase 和 protobuf 解码后的 snake_case。
function normalizePracticeInfo(practiceInfo = {}) {
if (!practiceInfo || typeof practiceInfo !== "object") return {};
const normalized = normalizePlainObject(practiceInfo);
if (practiceInfo.shoot_data || normalized.shootData) {
normalized.shootData = normalizeShootData(
normalizePlainObject(practiceInfo.shoot_data || normalized.shootData)
);
}
if (Array.isArray(practiceInfo.details || normalized.details)) {
normalized.details = (practiceInfo.details || normalized.details)
.map(normalizePlainObject)
.map(normalizeShootData);
}
return normalized;
}
function buildBusinessMessage(message) {
const businessType = BUSINESS_TYPE_BY_SERVER_TYPE[message.type];
if (!businessType) return null;
const matchInfo = normalizeMatchInfo(message.match_info);
const practiceInfo = normalizePracticeInfo(message.practice_info);
const matchId = normalizeId(
pickField(message, "matchId", "match_id") ||
matchInfo.matchId ||
practiceInfo.id ||
currentContext?.matchId
);
const shootData = normalizeShootData(
matchInfo.shootData ||
practiceInfo.shootData ||
(message.shoot_data ? normalizePlainObject(message.shoot_data) : undefined)
);
const details = Array.isArray(practiceInfo.details)
? practiceInfo.details
: matchInfo.details;
return {
...matchInfo,
...practiceInfo,
type: businessType,
id: matchId,
matchId,
shootData,
details,
sequence: message.sequence,
timestamp: message.timestamp,
matchWsType: message.type,
@@ -230,6 +257,7 @@ function getAckAudioKeys(message, businessMessage) {
return getShootResultAudioKeys(businessMessage?.shootData);
case ServerMessageType.SERVER_MSG_MATCH_END:
case ServerMessageType.SERVER_MSG_TIMEOUT:
case ServerMessageType.SERVER_MSG_PRACTICE_END:
return ["比赛结束"];
case ServerMessageType.SERVER_MSG_CHECK:
return getTestDistanceAudioKeys(businessMessage?.shootData);
@@ -243,7 +271,8 @@ function getAckAudioKeys(message, businessMessage) {
function shouldCloseAfterAck(message) {
return (
message.type === ServerMessageType.SERVER_MSG_MATCH_END ||
message.type === ServerMessageType.SERVER_MSG_TIMEOUT
message.type === ServerMessageType.SERVER_MSG_TIMEOUT ||
message.type === ServerMessageType.SERVER_MSG_PRACTICE_END
);
}
+38 -27
View File
@@ -30,12 +30,9 @@
"navigationBarTitleText": ""
}
},
{
"path": "pages/team-battle/index"
},
{
"path": "pages/melee-battle"
},
{
"path": "pages/melee-battle"
},
{
"path": "pages/battle-result"
},
@@ -69,21 +66,6 @@
{
"path": "pages/user"
},
{
"path": "pages/member/orders"
},
{
"path": "pages/member/order-detail"
},
{
"path": "pages/member/be-vip"
},
{
"path": "pages/member/vip-intro"
},
{
"path": "pages/member/agreement"
},
{
"path": "pages/grade-intro"
},
@@ -118,11 +100,8 @@
"path": "pages/match-detail"
},
{
"path": "pages/team-battle/team-bow-data"
"path": "pages/melee-bow-data"
},
{
"path": "pages/melee-bow-data"
},
{
"path": "pages/mine-bow-data"
},
@@ -150,5 +129,37 @@
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
}
},
"subPackages": []
}
"subPackages": [
{
"root": "pages/member",
"pages": [
{
"path": "orders"
},
{
"path": "order-detail"
},
{
"path": "be-vip"
},
{
"path": "vip-intro"
},
{
"path": "agreement"
}
]
},
{
"root": "pages/team-battle",
"pages": [
{
"path": "index"
},
{
"path": "team-bow-data"
}
]
}
]
}
+6 -6
View File
@@ -82,7 +82,7 @@ const checkBowData = () => {
<view class="container">
<block v-if="data.mode <= 3">
<view class="header-team" :style="{ marginTop: '25%' }">
<image src="../static/battle-result.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/battle-result.png" mode="widthFix" />
<view class="header-solo" v-if="data.mode === 1">
<text
:style="{
@@ -107,7 +107,7 @@ const checkBowData = () => {
</view>
<view class="header-mvp" v-if="data.mode === 2 || data.mode === 3">
<image
:src="`../static/${data.winTeam === 1 ? 'blue' : 'red'}-team-win.png`"
:src="`https://static.shelingxingqiu.com/shootmini/static/${data.winTeam === 1 ? 'blue' : 'red'}-team-win.png`"
mode="widthFix"
/>
<view
@@ -118,7 +118,7 @@ const checkBowData = () => {
}"
>
<view v-if="data.mvp && data.mvp.totalRings">
<image src="../static/title-mvp.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/title-mvp.png" mode="widthFix" />
<text
>斩获<text
:style="{
@@ -153,7 +153,7 @@ const checkBowData = () => {
</view>
</view>
<view class="battle-winner">
<image src="../static/shining-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shining-bg.png" mode="widthFix" />
<image
:src="ifWin ? '../static/you-win.png' : '../static/you-lost.png'"
mode="widthFix"
@@ -173,7 +173,7 @@ const checkBowData = () => {
<block v-else>
<view class="header-melee">
<view />
<image src="../static/battle-result.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/battle-result.png" mode="widthFix" />
<view />
</view>
<view
@@ -248,7 +248,7 @@ const checkBowData = () => {
class="battle-e"
:style="{ marginTop: data.mode > 3 ? '20px' : '20vw' }"
>
<image src="../static/row-yellow-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/row-yellow-bg.png" mode="widthFix" />
<view class="team-avatar">
<Avatar
:src="user.avatar"
+3 -3
View File
@@ -400,7 +400,7 @@ onBeforeUnmount(() => {
<view v-else class="no-player" :style="{ transform: 'translateY(-60px)' }">
<image src="../static/question-mark.png" mode="widthFix" />
</view>
<image src="../static/versus.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/versus.png" mode="widthFix" />
<view v-if="opponent.id" class="player" :style="{ transform: 'translateY(60px)' }">
<Avatar :src="opponent.avatar" :size="60" />
<text class="ready" :style="{ opacity: opponent.ready ? 1 : 0 }">
@@ -420,8 +420,8 @@ onBeforeUnmount(() => {
<block v-if="room.battleType === 1 && room.count >= 4">
<view class="all-players">
<image src="https://static.shelingxingqiu.com/attachment/2025-08-13/dc0x1p59iab6cvbhqc.png" mode="widthFix" />
<image v-if="room.count === 4" src="../static/title-2v2.png" mode="widthFix" />
<image v-if="room.count === 6" src="../static/title-3v3.png" mode="widthFix" />
<image v-if="room.count === 4" src="https://static.shelingxingqiu.com/shootmini/static/title-2v2.png" mode="widthFix" />
<image v-if="room.count === 6" src="https://static.shelingxingqiu.com/shootmini/static/title-3v3.png" mode="widthFix" />
<view>
<view v-for="(item, index) in players" :key="index">
<Avatar v-if="item.id" :src="item.avatar" :size="36" />
+45 -21
View File
@@ -15,19 +15,18 @@ import BubbleTip from "@/components/BubbleTip.vue";
import audioManager from "@/audioManager";
import {
createPractiseAPI,
startPractiseAPI,
endPractiseAPI,
getPractiseAPI,
laserAimAPI,
laserCloseAPI,
} from "@/apis";
import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket";
import { sharePractiseData } from "@/canvas";
import { wxShare, debounce } from "@/util";
import { MESSAGETYPESV2 } from "@/constants";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
const { user, device } = storeToRefs(store);
const scores = ref([]);
const isSvip = ref(false);
const step = ref(0);
@@ -50,6 +49,7 @@ const showGuide = ref(false);
const laserActive = ref(false);
const guideSwiperIndex = ref(0);
const sharing = ref(false);
const RESULT_TIP_CDN = "https://static.shelingxingqiu.com/shootmini/static";
const guideImages = [
"https://static.shelingxingqiu.com/shootmini/static/target.png",
@@ -104,21 +104,42 @@ const closeCalibrationLaser = async () => {
};
const createPractise = async (arrows) => {
const result = await createPractiseAPI(arrows, 1);
closeMatchWebSocket({ reason: "practice-recreate" });
const result = await createPractiseAPI(
arrows,
120,
1,
device.value.deviceId
);
if (result) practiseId.value = result.id;
if (!result?.serverAddr) {
uni.showToast({
title: "练习连接信息异常,请重试",
icon: "none",
});
return null;
}
connectMatchWebSocket({
serverAddr: result.serverAddr,
matchId: result.id,
userId: user.value.id,
});
return result;
};
const onOver = async () => {
practiseResult.value = await getPractiseAPI(practiseId.value);
const onOver = async (message) => {
practiseResult.value = Array.isArray(message?.details)
? message
: await getPractiseAPI(practiseId.value);
start.value = false;
};
async function onReceiveMessage(msg) {
if (msg.type === MESSAGETYPESV2.ShootResult) {
isSvip.value = msg.sVip === true;
scores.value = msg.details;
scores.value = Array.isArray(msg.details) ? msg.details : scores.value;
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
setTimeout(onOver, 1500);
setTimeout(() => onOver(msg), 1500);
} else if (msg.type === MESSAGETYPESV2.TestDistance && step.value === 3) {
if (msg.shootData.distance / 100 >= 5) {
audioManager.play("距离合格");
@@ -173,7 +194,7 @@ onBeforeUnmount(async () => {
uni.$off("share-image", onClickShare);
await closeCalibrationLaser();
audioManager.stopAll();
endPractiseAPI();
closeMatchWebSocket({ reason: "practice-leave" });
});
const nextStep = async () => {
@@ -196,15 +217,18 @@ const nextStep = async () => {
btnDisabled.value = true;
step.value = 3;
title.value = "-感知距离";
const result = await createPractiseAPI(total, 120);
if (result) practiseId.value = result.id;
const result = await createPractise(total);
if (!result) {
btnDisabled.value = false;
step.value = 2;
return;
}
} else if (step.value === 3) {
showGuide.value = false;
step.value = 4;
title.value = "-小试牛刀";
} else if (step.value === 4) {
title.value = "小试牛刀";
await startPractiseAPI();
scores.value = [];
isSvip.value = false;
step.value = 5;
@@ -235,10 +259,16 @@ const onClose = async () => {
scores.value = [];
isSvip.value = false;
step.value = 4;
const result = await createPractiseAPI(total, 120);
if (result) practiseId.value = result.id;
await createPractise(total);
}
};
const getResultTipSrc = (result = {}) => {
const validCount = (result.details || []).filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length;
return `${RESULT_TIP_CDN}/${validCount < total ? "un" : ""}finish-tip.png`;
};
</script>
<template>
@@ -361,13 +391,7 @@ const onClose = async () => {
:total="total"
:onClose="onClose"
:result="practiseResult"
:tipSrc="`../static/${
practiseResult.details.filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length < total
? 'un'
: ''
}finish-tip.png`"
:tipSrc="getResultTipSrc(practiseResult)"
/>
<canvas class="share-canvas" id="shareCanvas" type="2d"></canvas>
</view>
+3 -3
View File
@@ -404,12 +404,12 @@ function goBack() {
<!-- 背景图蓝队用 mvp-blue.png红队用 mvp-red.png平行四边形渐变切图 -->
<image
class="mvp-bg"
:src="mvpTeam === 1 ? '../static/mvp-blue.png' : '../static/mvp-red.png'"
:src="mvpTeam === 1 ? 'https://static.shelingxingqiu.com/shootmini/static/mvp-blue.png' : 'https://static.shelingxingqiu.com/shootmini/static/mvp-red.png'"
mode="scaleToFill"
/>
<!-- MVP 标题图 + 斩获环数 -->
<view class="mvp-info">
<image class="mvp-badge" src="../static/mvp-tip.png" mode="widthFix" />
<image class="mvp-badge" src="https://static.shelingxingqiu.com/shootmini/static/mvp-tip.png" mode="widthFix" />
<view class="mvp-rings">
斩获<text class="mvp-rings-num">{{ mvpPlayer.totalRing }}</text>
</view>
@@ -439,7 +439,7 @@ function goBack() {
<!-- 本场战绩标题装饰横线 + 标题图 + 装饰横线 -->
<view class="melee-title">
<view class="melee-title-line" />
<image class="melee-title-img" src="../static/battle-result.png" mode="scaleToFill" />
<image class="melee-title-img" src="https://static.shelingxingqiu.com/shootmini/static/battle-result.png" mode="scaleToFill" />
<view class="melee-title-line" />
</view>
+2 -2
View File
@@ -209,10 +209,10 @@ onLoad(async (options) => {
</view>
<view class="create-room">
<image src="https://static.shelingxingqiu.com/attachment/2025-07-15/dbcejys872iyun92h6.png" mode="widthFix" />
<image src="../static/room-notfound-title.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/room-notfound-title.png" mode="widthFix" />
<view>
<image :src="user.avatar" mode="widthFix" />
<image src="../static/versus.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/versus.png" mode="widthFix" />
<view>
<image src="../static/question-mark.png" mode="widthFix" />
</view>
+5 -5
View File
@@ -423,7 +423,7 @@ onShareTimeline(() => {
<text v-else-if="online">设备在线</text>
</block>
<image
src="../static/first-try.png"
src="https://static.shelingxingqiu.com/shootmini/static/first-try.png"
mode="widthFix"
@click="() => toPage('/pages/first-try')"
/>
@@ -434,10 +434,10 @@ onShareTimeline(() => {
</view>
<view class="play-card">
<view @click="$clickSound(() => toPage('/pages/practise'))">
<image src="../static/my-practise.png" mode="widthFix"/>
<image src="https://static.shelingxingqiu.com/shootmini/static/my-practise.png" mode="widthFix"/>
</view>
<view @click="$clickSound(() => toPage('/pages/friend-battle'))">
<image src="../static/friend-battle.png" mode="widthFix"/>
<image src="https://static.shelingxingqiu.com/shootmini/static/friend-battle.png" mode="widthFix"/>
</view>
</view>
</view>
@@ -452,7 +452,7 @@ onShareTimeline(() => {
hover-class="none"
></button>
<view class="ranking-players" @click="toRankListPage">
<img src="../static/juezhanbang.png" mode="widthFix"/>
<img src="https://static.shelingxingqiu.com/shootmini/static/juezhanbang.png" mode="widthFix"/>
<view class="divide-line"></view>
<view class="player-avatars">
<view
@@ -486,7 +486,7 @@ onShareTimeline(() => {
</view>
<view class="my-data">
<view @click="() => toPage('/pages/my-growth')">
<image src="../static/my-growth.png" mode="widthFix"/>
<image src="https://static.shelingxingqiu.com/shootmini/static/my-growth.png" mode="widthFix"/>
</view>
<view @click="() => toPage('/pages/ranking')">
<view>
+1 -1
View File
@@ -65,7 +65,7 @@ onLoad(async (options) => {
<Container title="靶纸">
<view class="container">
<image
src="../static/battle-header-melee.png"
src="https://static.shelingxingqiu.com/shootmini/static/battle-header-melee.png"
mode="widthFix"
:style="{ top: '-50rpx' }"
/>
+4 -4
View File
@@ -161,7 +161,7 @@ onShow(async () => {
<Container title="弓箭绑定">
<view v-if="!device.deviceId" class="scan-code">
<button hover-class="none" @click="$clickSound(handleScan)">
<image src="../static/scan.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/scan.png" mode="widthFix" />
</button>
<button hover-class="none" @click="showTip = true">
<text></text>
@@ -172,7 +172,7 @@ onShow(async () => {
<text>射灵智能弓箭三模传感系统与独创靶环算法</text>
<text>毫秒级在线实时对战让你拥有全球约战的乐趣</text>
<button hover-class="none" @click="toDeviceIntroPage">
<image src="../static/have-no-device.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/have-no-device.png" mode="widthFix" />
</button>
<ScreenHint
mode="square"
@@ -219,7 +219,7 @@ onShow(async () => {
:style="{ marginBottom: calibration ? '250rpx' : '100rpx' }"
>
<view>
<image src="../static/device-icon.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/device-icon.png" mode="widthFix" />
<text>{{ device.deviceName }}</text>
<view class="calibration" v-if="calibration">
<button hover-class="none" @click="goCalibration">
@@ -286,7 +286,7 @@ onShow(async () => {
<view v-if="device.deviceId && !justBind" class="has-device">
<view class="device-binded">
<view>
<image src="../static/device-icon.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/device-icon.png" mode="widthFix" />
<text>{{ device.deviceName }}</text>
<view class="calibration">
<button hover-class="none" @click="goCalibration">
+1 -1
View File
@@ -44,7 +44,7 @@ onMounted(async () => {
<Container :bgType="5" bgColor="#F5F5F5" :whiteBackArrow="false">
<view class="top-part">
<view>
<image src="../static/point-champion.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/point-champion.png" mode="widthFix" />
<image
:src="list[0] && list[0].avatar ? list[0].avatar : ''"
mode="widthFix"
+2 -2
View File
@@ -348,7 +348,7 @@ onShareTimeline(() => {
/>
<view class="heat-map">
<image
:src="bowTargetSrc || '../static/bow-target.png'"
:src="bowTargetSrc || 'https://static.shelingxingqiu.com/shootmini/static/bow-target.png'"
mode="widthFix"
/>
<image
@@ -374,7 +374,7 @@ onShareTimeline(() => {
</view>
<view class="reward" v-if="data.totalArrow">
<button hover-class="none" @click="showTip = true">
<image src="../static/reward-us.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/reward-us.png" mode="widthFix" />
</button>
</view>
<RingBarChart :data="data.ringRate" v-if="user.id" />
+44 -28
View File
@@ -15,10 +15,9 @@ import audioManager from "@/audioManager";
import {
createPractiseAPI,
startPractiseAPI,
endPractiseAPI,
getPractiseAPI,
} from "@/apis";
import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket";
import { sharePractiseData } from "@/canvas";
import { wxShare, debounce } from "@/util";
import { MESSAGETYPESV2, roundsName } from "@/constants";
@@ -26,7 +25,7 @@ import { MESSAGETYPESV2, roundsName } from "@/constants";
import useStore from "@/store";
import { storeToRefs } from "pinia";
const store = useStore();
const { user } = storeToRefs(store);
const { user, device } = storeToRefs(store);
const start = ref(false);
const scores = ref([]);
@@ -40,6 +39,7 @@ const showGuide = ref(false);
const tips = ref("");
const targetType = ref(1);
const sharing = ref(false);
const RESULT_TIP_CDN = "https://static.shelingxingqiu.com/shootmini/static";
onLoad((options) => {
if (options.target) {
@@ -47,8 +47,31 @@ onLoad((options) => {
}
});
const createPractise = async () => {
closeMatchWebSocket({ reason: "practice-recreate" });
const result = await createPractiseAPI(
total,
120,
targetType.value,
device.value.deviceId
);
if (result?.id) practiseId.value = result.id;
if (!result?.serverAddr) {
uni.showToast({
title: "练习连接信息异常,请重试",
icon: "none",
});
return null;
}
connectMatchWebSocket({
serverAddr: result.serverAddr,
matchId: result.id,
userId: user.value.id,
});
return result;
};
const onReady = async () => {
await startPractiseAPI();
scores.value = [];
isSvip.value = false;
xRingStreak.value = 0; // 新一局开始,重置 X 环连续计数
@@ -56,8 +79,10 @@ const onReady = async () => {
audioManager.play("练习开始");
};
const onOver = async () => {
practiseResult.value = await getPractiseAPI(practiseId.value);
const onOver = async (message) => {
practiseResult.value = Array.isArray(message?.details)
? message
: await getPractiseAPI(practiseId.value);
start.value = false;
};
@@ -87,14 +112,14 @@ async function onReceiveMessage(msg) {
if (msg.type === MESSAGETYPESV2.ShootResult) {
const prevLen = scores.value.length;
isSvip.value = msg.sVip === true;
scores.value = msg.details;
scores.value = Array.isArray(msg.details) ? msg.details : scores.value;
// 有新箭时取最后一箭判断是否 10 环及以上并检测连续计数
if (scores.value.length > prevLen) {
const latestArrow = scores.value[scores.value.length - 1];
checkAndPlayTententen(isTenPlusRing(latestArrow));
}
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
// setTimeout(onOver, 1500);
setTimeout(() => onOver(msg), 1500);
}
}
@@ -111,11 +136,17 @@ async function onComplete() {
scores.value = [];
isSvip.value = false;
xRingStreak.value = 0; // 重新开始练习,重置 X 环连续计数
const result = await createPractiseAPI(total, 120);
if (result) practiseId.value = result.id;
await createPractise();
}
}
const getResultTipSrc = (result = {}) => {
const validCount = (result.details || []).filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length;
return `${RESULT_TIP_CDN}/${validCount < total ? "un" : ""}finish-tip.png`;
};
const onClickShare = debounce(async () => {
if (sharing.value) return;
sharing.value = true;
@@ -132,12 +163,6 @@ const onClickShare = debounce(async () => {
}
});
function onAudioEnded(s) {
if (s.indexOf("比赛结束") >= 0) {
onOver()
}
}
onMounted(async () => {
// audioManager.play("第一轮");
uni.setKeepScreenOn({
@@ -145,9 +170,7 @@ onMounted(async () => {
});
uni.$on("socket-inbox", onReceiveMessage);
uni.$on("share-image", onClickShare);
uni.$on("audioEnded", onAudioEnded);
const result = await createPractiseAPI(total, 120, targetType.value);
if (result) practiseId.value = result.id;
await createPractise();
});
onBeforeUnmount(() => {
@@ -156,9 +179,8 @@ onBeforeUnmount(() => {
});
uni.$off("socket-inbox", onReceiveMessage);
uni.$off("share-image", onClickShare);
uni.$off("audioEnded", onAudioEnded);
audioManager.stopAll();
endPractiseAPI();
closeMatchWebSocket({ reason: "practice-leave" });
});
</script>
@@ -203,13 +225,7 @@ onBeforeUnmount(() => {
:total="total"
:onClose="onComplete"
:result="practiseResult"
:tipSrc="`../static/${
practiseResult.details.filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length < total
? 'un'
: ''
}finish-tip.png`"
:tipSrc="getResultTipSrc(practiseResult)"
/>
<canvas class="share-canvas" id="shareCanvas" type="2d"></canvas>
</block>
+44 -20
View File
@@ -14,10 +14,9 @@ import audioManager from "@/audioManager";
import {
createPractiseAPI,
startPractiseAPI,
endPractiseAPI,
getPractiseAPI,
} from "@/apis";
import { connectMatchWebSocket, closeMatchWebSocket } from "@/matchWebsocket";
import { sharePractiseData } from "@/canvas";
import { wxShare, debounce } from "@/util";
import { MESSAGETYPESV2 } from "@/constants";
@@ -26,7 +25,7 @@ import useStore from "@/store";
import { storeToRefs } from "pinia";
import {onLoad} from "@dcloudio/uni-app";
const store = useStore();
const { user } = storeToRefs(store);
const { user, device } = storeToRefs(store);
const start = ref(false);
const scores = ref([]);
@@ -39,6 +38,7 @@ const practiseId = ref("");
const showGuide = ref(false);
const targetType = ref(1);
const sharing = ref(false);
const RESULT_TIP_CDN = "https://static.shelingxingqiu.com/shootmini/static";
onLoad((options) => {
if (options.target) {
@@ -46,8 +46,31 @@ onLoad((options) => {
}
});
const createPractise = async () => {
closeMatchWebSocket({ reason: "practice-recreate" });
const result = await createPractiseAPI(
total,
3600,
targetType.value,
device.value.deviceId
);
if (result?.id) practiseId.value = result.id;
if (!result?.serverAddr) {
uni.showToast({
title: "练习连接信息异常,请重试",
icon: "none",
});
return null;
}
connectMatchWebSocket({
serverAddr: result.serverAddr,
matchId: result.id,
userId: user.value.id,
});
return result;
};
const onReady = async () => {
await startPractiseAPI();
scores.value = [];
isSvip.value = false;
xRingStreak.value = 0; // 新一局开始,重置 X 环连续计数
@@ -55,8 +78,10 @@ const onReady = async () => {
audioManager.play("练习开始");
};
const onOver = async () => {
practiseResult.value = await getPractiseAPI(practiseId.value);
const onOver = async (message) => {
practiseResult.value = Array.isArray(message?.details)
? message
: await getPractiseAPI(practiseId.value);
start.value = false;
};
@@ -86,14 +111,14 @@ async function onReceiveMessage(msg) {
if (msg.type === MESSAGETYPESV2.ShootResult) {
const prevLen = scores.value.length;
isSvip.value = msg.sVip === true;
scores.value = msg.details;
scores.value = Array.isArray(msg.details) ? msg.details : scores.value;
// 有新箭时取最后一箭判断是否 10 环及以上并检测连续计数
if (scores.value.length > prevLen) {
const latestArrow = scores.value[scores.value.length - 1];
checkAndPlayTententen(isTenPlusRing(latestArrow));
}
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
setTimeout(onOver, 1500);
setTimeout(() => onOver(msg), 1500);
}
// messages.forEach((msg) => {
// if (msg.constructor === MESSAGETYPES.ShootSyncMeArrowID) {
@@ -126,11 +151,17 @@ async function onComplete() {
scores.value = [];
isSvip.value = false;
xRingStreak.value = 0; // 重新开始练习,重置 X 环连续计数
const result = await createPractiseAPI(total, 3600);
if (result) practiseId.value = result.id;
await createPractise();
}
}
const getResultTipSrc = (result = {}) => {
const validCount = (result.details || []).filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length;
return `${RESULT_TIP_CDN}/${validCount < total ? "2un" : ""}finish-tip.png`;
};
const onClickShare = debounce(async () => {
if (sharing.value) return;
sharing.value = true;
@@ -153,8 +184,7 @@ onMounted(async () => {
});
uni.$on("socket-inbox", onReceiveMessage);
uni.$on("share-image", onClickShare);
const result = await createPractiseAPI(total, 3600, targetType.value);
if (result) practiseId.value = result.id;
await createPractise();
});
onBeforeUnmount(() => {
@@ -164,7 +194,7 @@ onBeforeUnmount(() => {
uni.$off("socket-inbox", onReceiveMessage);
uni.$off("share-image", onClickShare);
audioManager.stopAll();
endPractiseAPI();
closeMatchWebSocket({ reason: "practice-leave" });
});
</script>
@@ -211,13 +241,7 @@ onBeforeUnmount(() => {
:rowCount="9"
:onClose="onComplete"
:result="practiseResult"
:tipSrc="`../static/${
practiseResult.details.filter(
(arrow) => arrow.x !== -30 && arrow.y !== -30
).length < total
? '2un'
: ''
}finish-tip.png`"
:tipSrc="getResultTipSrc(practiseResult)"
/>
<canvas class="share-canvas" id="shareCanvas" type="2d"></canvas>
</block>
+2 -2
View File
@@ -328,8 +328,8 @@ onShow(async () => {
<view class="battle-types-box">
<view class="battle-types">
<view class="first">
<image src="../static/rank/battle-choose.png" mode="widthFix" />
<image class="star" src="../static/rank/star.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/rank/battle-choose.png" mode="widthFix" />
<image class="star" src="https://static.shelingxingqiu.com/shootmini/static/rank/star.png" mode="widthFix" />
</view>
<image
src="../static/rank/battle1v1.svg"
@@ -97,9 +97,9 @@ onBeforeUnmount(() => {
class="back-to-game"
@click="onClick"
>
<image src="../../../static/back-to-game-bg.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/back-to-game-bg.png" mode="widthFix" />
<block v-if="game.inBattle">
<image src="../../../static/pk-icon.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/pk-icon.png" mode="widthFix" />
<text>返回进行中的对局</text>
</block>
<block v-else-if="game.roomID">
@@ -31,7 +31,7 @@ const normalRounds = computed(() => {
<template>
<view class="container">
<view class="guide-row">
<image src="../../../static/shooter.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shooter.png" mode="widthFix" />
<view
:style="{
marginBottom: '10px',
@@ -42,7 +42,7 @@ const normalRounds = computed(() => {
</view>
</view>
<view>
<image src="../../../static/battle-header-melee.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/battle-header-melee.png" mode="widthFix" />
<text>蓝队({{ bluePoints }})</text>
<text>红队({{ redPoints }})</text>
</view>
@@ -41,7 +41,7 @@ const isMember = (player = {}) => player.vip === true || player.sVip === true;
<view class="container" :style="{ paddingTop: showHeader ? '5px' : '0' }">
<image
v-if="showHeader"
:src="`../../../static/battle-header${players.length ? '-melee' : ''}.png`"
:src="`https://static.shelingxingqiu.com/shootmini/static/battle-header${players.length ? '-melee' : ''}.png`"
mode="widthFix"
/>
<view
@@ -531,7 +531,7 @@ onBeforeUnmount(() => {
@impact="shakeTarget"
@complete="completeShotEffect"
/>
<image src="../../../static/bow-target.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/bow-target.png" mode="widthFix" />
</view>
<view class="footer">
<PointSwitcher
+2 -2
View File
@@ -12,13 +12,13 @@ defineProps({
const bubbleTypes = [
"../../../static/long-bubble.png",
"../../../static/long-bubble-middle.png",
"../../../static/long-bubble-tall.png",
"https://static.shelingxingqiu.com/shootmini/static/long-bubble-tall.png",
];
</script>
<template>
<view class="container">
<image src="../../../static/shooter.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/shooter.png" mode="widthFix" />
<view>
<image
v-if="!noBg"
@@ -27,22 +27,22 @@ const getContentHeight = () => {
<view class="scale-in" :style="{ height: getContentHeight() }">
<image
v-if="mode === 'normal'"
src="../../../static/screen-hint-bg.png"
src="https://static.shelingxingqiu.com/shootmini/static/screen-hint-bg.png"
mode="widthFix"
/>
<image
v-if="mode === 'tall'"
src="../../../static/coach-comment.png"
src="https://static.shelingxingqiu.com/shootmini/static/coach-comment.png"
mode="widthFix"
/>
<image
v-if="mode === 'square'"
src="../../../static/prompt-bg-square.png"
src="https://static.shelingxingqiu.com/shootmini/static/prompt-bg-square.png"
mode="widthFix"
/>
<image
v-if="mode === 'small'"
src="../../../static/finish-frame.png"
src="https://static.shelingxingqiu.com/shootmini/static/finish-frame.png"
mode="widthFix"
/>
<slot />
@@ -111,7 +111,7 @@ onBeforeUnmount(() => {
</view>
</view>
<view v-if="isBattle" class="ready-timer">
<image src="../../../static/test-tip.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/test-tip.png" mode="widthFix" />
<view v-if="count >= 0">
<text>具体正式比赛还有</text>
<text>{{ count }}</text>
+1 -1
View File
@@ -136,7 +136,7 @@ const buildVersion = typeof __BUILD_TIME__ !== 'undefined' ? __BUILD_TIME__ : ''
<text></text>
</UserItem>
<view class="my-grow" @click="toMyGrowthPage">
<image src="../static/my-grow.png" mode="widthFix" />
<image src="https://static.shelingxingqiu.com/shootmini/static/my-grow.png" mode="widthFix" />
</view>
<UserItem title="关于我们" :onClick="toAboutUsPage" />
<UserItem
+131
View File
@@ -0,0 +1,131 @@
"use strict";
var utf8 = exports;
var replacementChar = "\ufffd";
function utf8Read(buffer, start, end, fatal) {
var str = "";
for (var i = start; i < end;) {
var first = buffer[i++];
if (first <= 0x7F) {
str += String.fromCharCode(first);
continue;
}
var needed = 0;
var codePoint = 0;
var minCodePoint = 0;
if (first >= 0xC2 && first <= 0xDF) {
needed = 1;
codePoint = first & 0x1F;
minCodePoint = 0x80;
} else if (first >= 0xE0 && first <= 0xEF) {
needed = 2;
codePoint = first & 0x0F;
minCodePoint = 0x800;
} else if (first >= 0xF0 && first <= 0xF4) {
needed = 3;
codePoint = first & 0x07;
minCodePoint = 0x10000;
} else {
if (fatal) throw Error("invalid UTF-8 encoding");
str += replacementChar;
continue;
}
if (i + needed > end) {
if (fatal) throw Error("invalid UTF-8 encoding");
str += replacementChar;
break;
}
var valid = true;
for (var j = 0; j < needed; ++j) {
var next = buffer[i + j];
if ((next & 0xC0) !== 0x80) {
valid = false;
break;
}
codePoint = codePoint << 6 | next & 0x3F;
}
if (
!valid ||
codePoint < minCodePoint ||
codePoint > 0x10FFFF ||
codePoint >= 0xD800 && codePoint <= 0xDFFF
) {
if (fatal) throw Error("invalid UTF-8 encoding");
str += replacementChar;
continue;
}
i += needed;
if (codePoint <= 0xFFFF) {
str += String.fromCharCode(codePoint);
} else {
codePoint -= 0x10000;
str += String.fromCharCode(0xD800 + (codePoint >> 10));
str += String.fromCharCode(0xDC00 + (codePoint & 0x3FF));
}
}
return str;
}
utf8.length = function utf8_length(string) {
var len = 0,
c = 0;
for (var i = 0; i < string.length; ++i) {
c = string.charCodeAt(i);
if (c < 128)
len += 1;
else if (c < 2048)
len += 2;
else if ((c & 0xFC00) === 0xD800 && (string.charCodeAt(i + 1) & 0xFC00) === 0xDC00) {
++i;
len += 4;
} else
len += 3;
}
return len;
};
utf8.read = function utf8_read(buffer, start, end) {
if (end - start < 1)
return "";
return utf8Read(buffer, start, end, false);
};
utf8.readStrict = function utf8_read_strict(buffer, start, end) {
if (end - start < 1)
return "";
return utf8Read(buffer, start, end, true);
};
utf8.write = function utf8_write(string, buffer, offset) {
var start = offset,
c1,
c2;
for (var i = 0; i < string.length; ++i) {
c1 = string.charCodeAt(i);
if (c1 < 128) {
buffer[offset++] = c1;
} else if (c1 < 2048) {
buffer[offset++] = c1 >> 6 | 192;
buffer[offset++] = c1 & 63 | 128;
} else if ((c1 & 0xFC00) === 0xD800 && ((c2 = string.charCodeAt(i + 1)) & 0xFC00) === 0xDC00) {
c1 = 0x10000 + ((c1 & 0x03FF) << 10) + (c2 & 0x03FF);
++i;
buffer[offset++] = c1 >> 18 | 240;
buffer[offset++] = c1 >> 12 & 63 | 128;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
} else {
buffer[offset++] = c1 >> 12 | 224;
buffer[offset++] = c1 >> 6 & 63 | 128;
buffer[offset++] = c1 & 63 | 128;
}
}
return offset - start;
};
+2 -2
View File
@@ -24,8 +24,8 @@ function createWebSocket(token, onMessage) {
switch (envVersion) {
case "develop": // 开发版
// url = "ws://192.168.1.2:8000/socket";
url = "wss://apitest.shelingxingqiu.com/socket";
url = "ws://192.168.1.2:8000/socket";
// url = "wss://apitest.shelingxingqiu.com/socket";
break;
case "trial": // 体验版
url = "wss://apitest.shelingxingqiu.com/socket";
+16
View File
@@ -1,8 +1,23 @@
import { fileURLToPath, URL } from 'node:url'
import { readFileSync } from 'node:fs'
import { defineConfig } from 'vite'
import uni from '@dcloudio/vite-plugin-uni'
const protobufUtf8CompatPath = fileURLToPath(new URL('./src/utils/protobufUtf8Compat.js', import.meta.url))
function protobufUtf8CompatPlugin() {
return {
name: 'protobufjs-utf8-miniprogram-compat',
load(id) {
const normalizedId = id.replace(/\\/g, '/')
if (normalizedId.endsWith('/node_modules/protobufjs/src/util/utf8.js')) {
return readFileSync(protobufUtf8CompatPath, 'utf8')
}
}
}
}
export default defineConfig({
resolve: {
alias: {
@@ -10,6 +25,7 @@ export default defineConfig({
}
},
plugins: [
protobufUtf8CompatPlugin(),
uni(),
],
/** 构建时常量注入:__BUILD_TIME__ 在源码中展开为精确的打包时刻字符串 */