4 Commits

Author SHA1 Message Date
8c48216a75 feat: 好友约战选择20、40厘米靶 2026-04-20 17:43:38 +08:00
c1ff0cedad feat:选择20cm、40cm全环靶 2026-04-20 16:00:10 +08:00
56650793e8 pref: 更新音频 2026-04-20 11:13:59 +08:00
e8568ee6a8 feat: 添加射箭声音 2026-04-16 18:06:59 +08:00
11 changed files with 593 additions and 254 deletions

View File

@@ -1,45 +1,68 @@
<script setup> <script setup>
import { watch } from "vue"; import {
import { onShow, onHide } from "@dcloudio/uni-app"; watch
import websocket from "@/websocket"; } from "vue";
import { getDeviceBatteryAPI } from "@/apis"; import {
import useStore from "@/store"; onShow,
import { storeToRefs } from "pinia"; onHide
const store = useStore(); } from "@dcloudio/uni-app";
const { user } = storeToRefs(store); import websocket from "@/websocket";
const { updateUser, updateOnline } = store; import {
getDeviceBatteryAPI
} from "@/apis";
import useStore from "@/store";
import {
storeToRefs
} from "pinia";
import audioManager from "./audioManager";
const store = useStore();
const {
user
} = storeToRefs(store);
const {
updateUser,
updateOnline
} = store;
watch( watch(
() => user.value.id, () => user.value.id,
(newVal) => { (newVal) => {
const token = uni.getStorageSync( const token = uni.getStorageSync(
`${uni.getAccountInfoSync().miniProgram.envVersion}_token` `${uni.getAccountInfoSync().miniProgram.envVersion}_token`
); );
if (newVal && token) { if (newVal && token) {
websocket.createWebSocket(token, (content) => { websocket.createWebSocket(token, onShootWsMsg);
uni.$emit("socket-inbox", content);
});
} }
if (!newVal) { if (!newVal) {
websocket.closeWebSocket(); websocket.closeWebSocket();
} }
}, }, {
{
deep: false, // 如果 user 是一个对象或数组,建议开启 deep: false, // 如果 user 是一个对象或数组,建议开启
immediate: false, // 若想在初始化时立即执行一次回调,可开启。 immediate: false, // 若想在初始化时立即执行一次回调,可开启。
} }
); );
function emitUpdateUser(value) { function emitUpdateUser(value) {
updateUser(value); updateUser(value);
} }
async function emitUpdateOnline() { async function emitUpdateOnline() {
const data = await getDeviceBatteryAPI(); const data = await getDeviceBatteryAPI();
updateOnline(data.online); updateOnline(data.online);
} }
onShow(() => { function onDeviceShoot() {
audioManager.play("射箭声音")
}
function onShootWsMsg(content) {
if(content.type === 'shoot-trigger'){
onDeviceShoot()
}
uni.$emit("socket-inbox", content);
}
onShow(() => {
uni.$on("update-user", emitUpdateUser); uni.$on("update-user", emitUpdateUser);
uni.$on("update-online", emitUpdateOnline); uni.$on("update-online", emitUpdateOnline);
const token = uni.getStorageSync( const token = uni.getStorageSync(
@@ -47,28 +70,26 @@ onShow(() => {
); );
if (user.value.id && token) { if (user.value.id && token) {
console.log("回到前台,重新连接 websocket"); console.log("回到前台,重新连接 websocket");
websocket.createWebSocket(token, (content) => { websocket.createWebSocket(token, onShootWsMsg);
uni.$emit("socket-inbox", content);
});
} }
}); });
onHide(() => { onHide(() => {
uni.$off("update-user", emitUpdateUser); uni.$off("update-user", emitUpdateUser);
uni.$off("update-online", emitUpdateOnline); uni.$off("update-online", emitUpdateOnline);
websocket.closeWebSocket(); websocket.closeWebSocket();
}); });
</script> </script>
<style> <style>
page { page {
-webkit-touch-callout: none; -webkit-touch-callout: none;
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
background-color: #000; background-color: #000;
} }
button { button {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: none; border: none;
@@ -76,181 +97,196 @@ button {
line-height: 1; line-height: 1;
outline: none; outline: none;
box-sizing: border-box; box-sizing: border-box;
} }
view::-webkit-scrollbar { view::-webkit-scrollbar {
width: 0; width: 0;
height: 0; height: 0;
color: transparent; color: transparent;
} }
button::after { button::after {
border: none; border: none;
} }
.guide-tips { .guide-tips {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
font-size: 28rpx; font-size: 28rpx;
} }
.guide-tips > text:first-child {
color: #fed847;
}
.guide-tips > text:nth-child(2) {
font-size: 24rpx;
}
@keyframes fadeInOut { .guide-tips>text:first-child {
color: #fed847;
}
.guide-tips>text:nth-child(2) {
font-size: 24rpx;
}
@keyframes fadeInOut {
0% { 0% {
transform: translateY(20px); transform: translateY(20px);
opacity: 0; opacity: 0;
} }
30% { 30% {
transform: translateY(0); transform: translateY(0);
opacity: 1; opacity: 1;
} }
80% { 80% {
opacity: 1; opacity: 1;
} }
100% { 100% {
opacity: 0; opacity: 0;
} }
} }
.fade-in-out { .fade-in-out {
animation: fadeInOut 1.2s ease forwards; animation: fadeInOut 1.2s ease forwards;
} }
@keyframes fadeOut { @keyframes fadeOut {
from { from {
transform: translateY(0); transform: translateY(0);
opacity: 1; opacity: 1;
} }
to { to {
transform: translateY(20px); transform: translateY(20px);
opacity: 0; opacity: 0;
} }
} }
.fade-out { .fade-out {
animation: fadeOut 0.3s ease forwards; animation: fadeOut 0.3s ease forwards;
} }
@keyframes scaleIn { @keyframes scaleIn {
from { from {
transform: scale(0); transform: scale(0);
opacity: 0; opacity: 0;
} }
to { to {
transform: scale(1); transform: scale(1);
opacity: 1; opacity: 1;
} }
} }
.scale-in { .scale-in {
animation: scaleIn 0.3s ease-out forwards; animation: scaleIn 0.3s ease-out forwards;
transform-origin: center center; transform-origin: center center;
} }
@keyframes scaleOut { @keyframes scaleOut {
from { from {
transform: scale(1); transform: scale(1);
opacity: 1; opacity: 1;
} }
to { to {
transform: scale(0); transform: scale(0);
opacity: 0; opacity: 0;
} }
} }
.scale-out { .scale-out {
animation: scaleOut 0.3s ease-out forwards; animation: scaleOut 0.3s ease-out forwards;
transform-origin: center center; transform-origin: center center;
} }
@keyframes rotate { @keyframes rotate {
from { from {
transform: rotate(0deg); transform: rotate(0deg);
} }
to { to {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
@keyframes pumpIn { @keyframes pumpIn {
from { from {
transform: scale(2); transform: scale(2);
} }
to { to {
transform: scale(1); transform: scale(1);
} }
} }
.pump-in { .pump-in {
animation: pumpIn 0.3s ease-out forwards; animation: pumpIn 0.3s ease-out forwards;
transform-origin: center center; transform-origin: center center;
} }
.share-canvas { .share-canvas {
width: 300px; width: 300px;
height: 530px; height: 530px;
position: absolute; position: absolute;
top: -1000px; top: -1000px;
left: 0; left: 0;
} }
.truncate { .truncate {
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.modal { .modal {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.user-row {
.user-row {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 0 15px; padding: 0 15px;
padding-top: 7px; padding-top: 7px;
position: relative; position: relative;
} }
.half-time-tip {
.half-time-tip {
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
} }
.half-time-tip > text:last-child {
.half-time-tip>text:last-child {
margin-top: 20px; margin-top: 20px;
color: #fff9; color: #fff9;
} }
.see-more {
.see-more {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-top: 20rpx; margin-top: 20rpx;
} }
.see-more > text {
.see-more>text {
color: #39a8ff; color: #39a8ff;
font-size: 13px; font-size: 13px;
} }
.see-more > image {
width: 15px;
}
@font-face { .see-more>image {
width: 15px;
}
@font-face {
font-family: "DINCondensed"; font-family: "DINCondensed";
src: url("https://static.shelingxingqiu.com/font/DIN-Condensed-Bold-2.ttf") src: url("https://static.shelingxingqiu.com/font/DIN-Condensed-Bold-2.ttf") format("truetype");
format("truetype");
font-weight: 700; font-weight: 700;
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
</style> </style>

View File

@@ -6,8 +6,8 @@ try {
switch (envVersion) { switch (envVersion) {
case "develop": // 开发版 case "develop": // 开发版
// BASE_URL = "http://192.168.1.30: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";
@@ -196,10 +196,11 @@ export const getMyDevicesAPI = () => {
return request("GET", "/user/device/getBindings"); return request("GET", "/user/device/getBindings");
}; };
export const createPractiseAPI = (arrows, time) => { 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,
}); });
}; };
@@ -215,10 +216,11 @@ 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) => { export const createRoomAPI = (gameType, teamSize, targetType) => {
return request("POST", "/user/createroom", { return request("POST", "/user/createroom", {
gameType, gameType,
teamSize, teamSize,
targetType,
}); });
}; };

View File

@@ -40,26 +40,26 @@ export const audioFils = {
未上靶: 未上靶:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6n45o3tsm1v4unam.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-12/de6n45o3tsm1v4unam.mp3",
"1环": "1环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin1aq7gxjih5l.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/1.mp3",
"2环": "2环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin64tdgx2s4at.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/2.mp3",
"3环": "3环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinlmf87vt8z65.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/3.mp3",
"4环": "4环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinniv97sx0q9u.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/4.mp3",
"5环": "5环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin7j01kknpb7k.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/5.mp3",
"6环": "6环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin4syy1015rtq.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/6.mp3",
"7环": "7环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin3iz3dvmjdai.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/7.mp3",
"8环": "8环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinnjd42lhpfiw.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/8.mp3",
"9环": "9环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxin69nj1xh7yfz.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/9.mp3",
"10环": "10环":
"https://static.shelingxingqiu.com/attachment/2025-09-17/dcutxinnvsx0tt7ksa.mp3", "https://static.shelingxingqiu.com/shootaudio/v3/10.mp3",
X环: "https://static.shelingxingqiu.com/attachment/2026-02-09/dga8puwekpe2gmtbu4.mp3", X环: "https://static.shelingxingqiu.com/shootaudio/v4/v4/X%E7%8E%AF.mp3",
向上调整: 向上调整:
"https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf5pfvu3l8dhr.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-12/de6ellf5pfvu3l8dhr.mp3",
向右上调整: 向右上调整:
@@ -80,6 +80,10 @@ export const audioFils = {
"https://static.shelingxingqiu.com/attachment/2025-11-13/de7kzzllq0futwynso.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-13/de7kzzllq0futwynso.mp3",
练习开始: 练习开始:
"https://static.shelingxingqiu.com/attachment/2025-11-14/de88w0lmmt43nnfmoi.mp3", "https://static.shelingxingqiu.com/attachment/2025-11-14/de88w0lmmt43nnfmoi.mp3",
射箭声音:
"https://static.shelingxingqiu.com/shootaudio/v4/v4/%E7%AE%AD%E9%A3%9E%E8%A1%8C.mp3",
命中:
"https://static.shelingxingqiu.com/shootaudio/%E5%91%BD%E4%B8%AD.mp3"
}; };
// 版本控制日志函数 // 版本控制日志函数

View File

@@ -18,6 +18,7 @@ const props = defineProps({
}); });
const battleMode = ref(1); const battleMode = ref(1);
const targetMode = ref(1);
const loading = ref(false); const loading = ref(false);
const roomNumber = ref(""); const roomNumber = ref("");
@@ -35,13 +36,14 @@ const createRoom = debounce(async () => {
try { try {
const result = await createRoomAPI( const result = await createRoomAPI(
battleMode.value === 2 ? 2 : 1, battleMode.value === 2 ? 2 : 1,
battleMode.value === 2 ? 10 : size battleMode.value === 2 ? 10 : size,
targetMode.value*20,
); );
if (result.number) { if (result.number) {
props.onConfirm(); props.onConfirm();
await joinRoomAPI(result.number); await joinRoomAPI(result.number);
uni.navigateTo({ uni.navigateTo({
url: "/pages/battle-room?roomNumber=" + result.number, url: "/pages/battle-room?roomNumber=" + result.number + "&target=" + targetMode.value,
}); });
} }
} catch (error) { } catch (error) {
@@ -53,7 +55,11 @@ const createRoom = debounce(async () => {
</script> </script>
<template> <template>
<view class="container"> <view class="container">
<image src="../static/choose-battle-mode.png" mode="widthFix" /> <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" />
<view class="target-options-header-line-right"></view>
</view>
<view class="create-options"> <view class="create-options">
<view <view
:class="{ 'battle-btn': true, 'battle-choosen': battleMode === 1 }" :class="{ 'battle-btn': true, 'battle-choosen': battleMode === 1 }"
@@ -80,6 +86,25 @@ const createRoom = debounce(async () => {
<text>乱斗模式3-10</text> <text>乱斗模式3-10</text>
</view> </view>
</view> </view>
<view class="target-options-header">
<view class="target-options-header-line-left"></view>
<view class="target-options-header-title">选择靶纸</view>
<view class="target-options-header-line-right"></view>
</view>
<view class="target-options">
<view
:class="{ 'battle-btn': true, 'battle-choosen': targetMode === 1 }"
@click="() => (targetMode = 1)"
>
<text>20厘米全环靶</text>
</view>
<view
:class="{ 'battle-btn': true, 'battle-choosen': targetMode === 2 }"
@click="() => (targetMode = 2)"
>
<text>40厘米全环靶</text>
</view>
</view>
<SButton :onClick="createRoom">创建房间</SButton> <SButton :onClick="createRoom">创建房间</SButton>
</view> </view>
</template> </template>
@@ -91,6 +116,7 @@ const createRoom = debounce(async () => {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
padding-top: 44rpx;
} }
.container > image:first-child { .container > image:first-child {
width: 45%; width: 45%;
@@ -105,6 +131,50 @@ const createRoom = debounce(async () => {
justify-content: center; justify-content: center;
margin-bottom: 15px; margin-bottom: 15px;
} }
.target-options-header{
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 24rpx;
}
.target-options-header-title-img{
width: 196rpx;
height: 40rpx;
}
.target-options-header-title{
width: 112rpx;
height: 40rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
text-align: center;
font-style: normal;
text-transform: none;
color: #FFEFBA;
margin: 0 18rpx;
}
.target-options-header-line-left{
width: 214rpx;
height: 0rpx;
border-radius: 0rpx 0rpx 0rpx 0rpx;
border: 1rpx solid;
border-image: linear-gradient(90deg, rgba(133, 119, 96, 0), rgba(133, 119, 96, 1)) 1 1;
}
.target-options-header-line-right{
width: 214rpx;
height: 0rpx;
border-radius: 0rpx 0rpx 0rpx 0rpx;
border: 1rpx solid;
border-image: linear-gradient(90deg, rgba(133, 119, 96, 1), rgba(133, 119, 96, 0)) 1 1;
}
.target-options {
width: 100%;
padding: 0 10px;
display: flex;
gap: 12px;
justify-content: center;
margin-bottom: 15px;
}
.battle-btn { .battle-btn {
width: 45%; width: 45%;
height: 55px; height: 55px;

View File

@@ -88,6 +88,7 @@ watch(
transform: translateY(100%); transform: translateY(100%);
transition: all 0.3s ease; transition: all 0.3s ease;
position: relative; position: relative;
background-color: #372E1D;
} }
.modal-content > image:first-child { .modal-content > image:first-child {
width: 100%; width: 100%;

View File

@@ -0,0 +1,197 @@
<script setup>
import { ref, watch } from "vue";
import SButton from "@/components/SButton.vue";
const props = defineProps({
show: {
type: Boolean,
default: false,
},
onClose: {
type: Function,
default: () => {},
},
onConfirm: {
type: Function,
default: () => {},
},
});
const selectedTarget = ref(2);
const showContainer = ref(false);
const showContent = ref(false);
watch(
() => props.show,
(newValue) => {
if (newValue) {
showContainer.value = true;
setTimeout(() => {
showContent.value = true;
}, 100);
} else {
showContent.value = false;
setTimeout(() => {
showContainer.value = false;
}, 100);
}
},
{}
);
const handleConfirm = () => {
props.onConfirm(selectedTarget.value);
props.onClose();
};
</script>
<template>
<view
class="container"
v-if="showContainer"
:class="{ 'container-show': showContent }"
@click="onClose"
>
<view
class="modal-content"
:class="{ 'modal-show': showContent }"
@click.stop=""
>
<view class="header">
<view class="header-title">
<view class="header-title-line-left"></view>
<text>选择靶型</text>
<view class="header-title-line-right"></view>
</view>
<view class="close-btn" @click="onClose">
<image src="../static/close-yellow.png" mode="widthFix" />
</view>
</view>
<view class="target-options">
<view
:class="{ 'target-btn': true, 'target-choosen': selectedTarget === 1 }"
@click="() => (selectedTarget = 1)"
>
<text>20厘米全环靶</text>
</view>
<view style="width: 30rpx"></view>
<view
:class="{ 'target-btn': true, 'target-choosen': selectedTarget === 2 }"
@click="() => (selectedTarget = 2)"
>
<text>40厘米全环靶</text>
</view>
</view>
<SButton width="694rpx" :onClick="handleConfirm">确定</SButton>
</view>
</view>
</template>
<style scoped>
.container {
position: fixed;
top: 0;
left: 0;
background-color: #00000099;
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
opacity: 0;
transition: all 0.3s ease;
z-index: 999;
}
.container-show {
opacity: 1;
}
.modal-content {
width: 100%;
transform: translateY(100%);
transition: all 0.3s ease;
background: url("https://static.shelingxingqiu.com/attachment/2025-12-04/dep11770wzxg6o2alo.png")
no-repeat center top;
background-size: 100% auto;
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
padding-bottom: 68rpx;
padding-top: 44rpx;
}
.modal-show {
transform: translateY(0%);
}
.header {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
margin-bottom: 44rpx;
}
.header-title{
display: flex;
align-items: center;
justify-content: center;
}
.header-title text{
width: 196rpx;
height: 40rpx;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
text-align: center;
font-style: normal;
text-transform: none;
color: #FFEFBA;
}
.header-title-line-left{
width: 214rpx;
height: 0rpx;
border-radius: 0rpx 0rpx 0rpx 0rpx;
border: 1rpx solid;
border-image: linear-gradient(90deg, rgba(133, 119, 96, 1), rgba(133, 119, 96, 0)) 1 1;
}
.header-title-line-right{
width: 214rpx;
height: 0rpx;
border-radius: 0rpx 0rpx 0rpx 0rpx;
border: 1rpx solid;
border-image: linear-gradient(90deg, rgba(133, 119, 96, 1), rgba(133, 119, 96, 0)) 1 1;
}
.close-btn {
position: absolute;
right: 0;
top: -10px;
}
.close-btn > image {
width: 40px;
height: 40px;
}
.target-options {
width: 750rpx;
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 38rpx;
}
.target-btn {
width: 332rpx;
height: 92rpx;
text-align: center;
border-radius: 10px;
border: 2rpx solid #fff3;
box-sizing: border-box;
color: #fff;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.target-choosen {
color: #fed847;
border: 4rpx solid #fed847;
}
</style>

View File

@@ -169,7 +169,7 @@ onLoad(async (options) => {
<SModal <SModal
:show="showModal" :show="showModal"
:onClose="() => (showModal = false)" :onClose="() => (showModal = false)"
height="520rpx" height="716rpx"
> >
<view v-if="warnning" class="warnning"> <view v-if="warnning" class="warnning">
{{ warnning }} {{ warnning }}

View File

@@ -1,6 +1,6 @@
<script setup> <script setup>
import { ref, onMounted, onBeforeUnmount } from "vue"; import { ref, onMounted, onBeforeUnmount } from "vue";
import { onShow } from "@dcloudio/uni-app"; import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue"; import Container from "@/components/Container.vue";
import ShootProgress from "@/components/ShootProgress.vue"; import ShootProgress from "@/components/ShootProgress.vue";
import BowTarget from "@/components/BowTarget.vue"; import BowTarget from "@/components/BowTarget.vue";
@@ -35,6 +35,13 @@ const practiseResult = ref({});
const practiseId = ref(""); const practiseId = ref("");
const showGuide = ref(false); const showGuide = ref(false);
const tips = ref(""); const tips = ref("");
const targetType = ref(1);
onLoad((options) => {
if (options.target) {
targetType.value = Number(options.target);
}
});
const onReady = async () => { const onReady = async () => {
await startPractiseAPI(); await startPractiseAPI();
@@ -84,7 +91,7 @@ onMounted(async () => {
}); });
uni.$on("socket-inbox", onReceiveMessage); uni.$on("socket-inbox", onReceiveMessage);
uni.$on("share-image", onClickShare); uni.$on("share-image", onClickShare);
const result = await createPractiseAPI(total, 120); const result = await createPractiseAPI(total, 120, targetType.value);
if (result) practiseId.value = result.id; if (result) practiseId.value = result.id;
}); });

View File

@@ -24,6 +24,7 @@ import { MESSAGETYPESV2 } from "@/constants";
import useStore from "@/store"; import useStore from "@/store";
import { storeToRefs } from "pinia"; import { storeToRefs } from "pinia";
import {onLoad} from "@dcloudio/uni-app";
const store = useStore(); const store = useStore();
const { user } = storeToRefs(store); const { user } = storeToRefs(store);
@@ -33,6 +34,13 @@ const total = 36;
const practiseResult = ref({}); const practiseResult = ref({});
const practiseId = ref(""); const practiseId = ref("");
const showGuide = ref(false); const showGuide = ref(false);
const targetType = ref(1);
onLoad((options) => {
if (options.target) {
targetType.value = Number(options.target);
}
});
const onReady = async () => { const onReady = async () => {
await startPractiseAPI(); await startPractiseAPI();
@@ -97,7 +105,7 @@ onMounted(async () => {
}); });
uni.$on("socket-inbox", onReceiveMessage); uni.$on("socket-inbox", onReceiveMessage);
uni.$on("share-image", onClickShare); uni.$on("share-image", onClickShare);
const result = await createPractiseAPI(total, 360); const result = await createPractiseAPI(total, 360, targetType.value);
if (result) practiseId.value = result.id; if (result) practiseId.value = result.id;
}); });

View File

@@ -4,6 +4,7 @@ import { onShow } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue"; import Container from "@/components/Container.vue";
import Guide from "@/components/Guide.vue"; import Guide from "@/components/Guide.vue";
import Avatar from "@/components/Avatar.vue"; import Avatar from "@/components/Avatar.vue";
import TargetPicker from "@/components/TargetPicker.vue";
import { getPractiseDataAPI } from "@/apis"; import { getPractiseDataAPI } from "@/apis";
import { canEenter } from "@/util"; import { canEenter } from "@/util";
@@ -12,12 +13,20 @@ import { storeToRefs } from "pinia";
const store = useStore(); const store = useStore();
const { user, device, online } = storeToRefs(store); const { user, device, online } = storeToRefs(store);
const data = ref({}); const data = ref({});
const showTargetPicker = ref(false);
const pendingPractiseType = ref("");
const goPractise = async (type) => { const goPractise = async (type) => {
if (!canEenter(user.value, device.value, online.value)) return; if (!canEenter(user.value, device.value, online.value)) return;
// await uni.$checkAudio(); pendingPractiseType.value = type;
showTargetPicker.value = true;
};
const handleTargetConfirm = (target) => {
showTargetPicker.value = false;
const type = pendingPractiseType.value;
uni.navigateTo({ uni.navigateTo({
url: `/pages/practise-${type}`, url: `/pages/practise-${type}?target=${target}`,
}); });
}; };
@@ -88,6 +97,11 @@ onShow(async () => {
/> />
</view> </view>
</view> </view>
<TargetPicker
:show="showTargetPicker"
:onClose="() => (showTargetPicker = false)"
:onConfirm="handleTargetConfirm"
/>
</Container> </Container>
</template> </template>

View File

@@ -14,8 +14,8 @@ function createWebSocket(token, onMessage) {
switch (envVersion) { switch (envVersion) {
case "develop": // 开发版 case "develop": // 开发版
// url = "ws://192.168.1.30:8000/socket"; url = "ws://localhost:8000/socket";
url = "wss://apitest.shelingxingqiu.com/socket"; // url = "wss://apitest.shelingxingqiu.com/socket";
break; break;
case "trial": // 体验版 case "trial": // 体验版
url = "wss://apitest.shelingxingqiu.com/socket"; url = "wss://apitest.shelingxingqiu.com/socket";