Compare commits
4 Commits
main
...
new-race-m
| Author | SHA1 | Date | |
|---|---|---|---|
| d8a94c8ff6 | |||
| 29c6b174d8 | |||
| bb43de3a62 | |||
| d2dc6c51cf |
116
doc.md
116
doc.md
@@ -1,116 +0,0 @@
|
|||||||
# 微信小程序多人协作分支管理规范
|
|
||||||
|
|
||||||
## 一、分支结构
|
|
||||||
|
|
||||||
```
|
|
||||||
main (主分支/生产环境)
|
|
||||||
└── test (测试分支)
|
|
||||||
└── feature/xxx (个人开发分支)
|
|
||||||
```
|
|
||||||
|
|
||||||
| 分支 | 用途 | 稳定性 |
|
|
||||||
|------|------|--------|
|
|
||||||
| main | 生产环境代码 | 最高,仅接受测试通过的代码合并 |
|
|
||||||
| test | 测试环境,用于体验版发布 | 中,需验证后合并到 main |
|
|
||||||
| feature/xxx | 个人开发分支 | 低,按需命名,如 `feature/user-center` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 二、开发流程
|
|
||||||
|
|
||||||
### 1. 开始开发
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 确保本地 main 最新
|
|
||||||
git checkout main
|
|
||||||
git pull origin main
|
|
||||||
|
|
||||||
# 从 main 创建自己的开发分支
|
|
||||||
git checkout -b feature/your-name-work
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. 开发阶段
|
|
||||||
|
|
||||||
- 在个人分支上开发功能
|
|
||||||
- 频繁提交,保持原子性提交
|
|
||||||
- 定期 `git pull origin main` 同步主线变更,避免合并冲突累积
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git add .
|
|
||||||
git commit -m "feat: 完成xxx功能"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 合并到 test 分支
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 切换到 test
|
|
||||||
git checkout test
|
|
||||||
git pull origin test
|
|
||||||
|
|
||||||
# 合并个人分支
|
|
||||||
git merge feature/your-name-work
|
|
||||||
|
|
||||||
# 推送 test 分支
|
|
||||||
git push origin test
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. 打包上传体验版
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 执行打包
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
|
|
||||||
打包完成后:
|
|
||||||
|
|
||||||
1. 打开 **微信开发者工具**
|
|
||||||
2. 导入项目,选择 `dist/build/mp-weixin` 目录
|
|
||||||
3. 在开发者工具中点击 **上传**
|
|
||||||
4. 登录 [微信公众平台](https://mp.weixin.qq.com)
|
|
||||||
5. 进入 **管理->版本管理**
|
|
||||||
6. 找到刚上传的版本,点击 **选为体验版**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 三、合并到 main 分支
|
|
||||||
|
|
||||||
当 test 分支验证通过后,将其合并到 main:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout main
|
|
||||||
git pull origin main
|
|
||||||
|
|
||||||
git merge origin/test
|
|
||||||
|
|
||||||
git push origin main
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 四、冲突处理
|
|
||||||
|
|
||||||
合并时如有冲突,在个人分支解决后再合并:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git checkout feature/your-name-work
|
|
||||||
git merge main
|
|
||||||
# 解决冲突后
|
|
||||||
git add .
|
|
||||||
git commit -m "merge: 解决与main的冲突"
|
|
||||||
git push origin feature/your-name-work
|
|
||||||
|
|
||||||
# 重新合并到 test
|
|
||||||
git checkout test
|
|
||||||
git merge feature/your-name-work
|
|
||||||
git push origin test
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 五、注意事项
|
|
||||||
|
|
||||||
1. **禁止直接向 main 和 test 分支提交代码**,必须通过合并
|
|
||||||
2. **每次合并前先拉取最新代码**,避免覆盖他人改动
|
|
||||||
3. **体验版发布前确认代码已提交**,避免遗漏
|
|
||||||
4. **开发分支命名建议**:`feature/姓名-功能名`,如 `feature/zhangsan-login`
|
|
||||||
5. **删除已合并的开发分支**:`git branch -d feature/your-name-work`
|
|
||||||
@@ -6,8 +6,7 @@ try {
|
|||||||
|
|
||||||
switch (envVersion) {
|
switch (envVersion) {
|
||||||
case "develop": // 开发版
|
case "develop": // 开发版
|
||||||
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";
|
||||||
|
|||||||
@@ -26,20 +26,21 @@ defineProps({
|
|||||||
.container {
|
.container {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 0 15px;
|
padding: 0 26rpx 0 28rpx;
|
||||||
margin-bottom: 14rpx;
|
margin-bottom: 14rpx;
|
||||||
width: clac(100% - 30px);
|
width: clac(100% - 54rpx);
|
||||||
}
|
}
|
||||||
.container .shooter2 {
|
.container .shooter2 {
|
||||||
width: 150rpx;
|
display: block;
|
||||||
height: 162rpx;
|
width: 133rpx;
|
||||||
|
height: 144rpx;
|
||||||
}
|
}
|
||||||
.container .bg-box {
|
.container .bg-box {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
position: relative;
|
position: relative;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 55px;
|
height: 128rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ onBeforeUnmount(() => {
|
|||||||
/* 对战房间:整个胶囊作为分享按钮,靠右对齐 */
|
/* 对战房间:整个胶囊作为分享按钮,靠右对齐 */
|
||||||
.battle-room-number {
|
.battle-room-number {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: 10rpx;
|
margin-right: 20rpx;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ async function onReceiveMessage(msg) {
|
|||||||
halfTime.value = false;
|
halfTime.value = false;
|
||||||
audioManager.play("比赛开始");
|
audioManager.play("比赛开始");
|
||||||
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
||||||
audioManager.play("比赛结束", false);
|
audioManager.play("比赛结束");
|
||||||
} else if (msg.type === MESSAGETYPESV2.ShootResult) {
|
} else if (msg.type === MESSAGETYPESV2.ShootResult) {
|
||||||
let arrow = {};
|
let arrow = {};
|
||||||
if (msg.details && Array.isArray(msg.details)) {
|
if (msg.details && Array.isArray(msg.details)) {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ const checkBowData = () => {
|
|||||||
}deg)`,
|
}deg)`,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<view v-if="data.mvp && data.mvp[0].totalRings">
|
<view v-if="data.mvp && data.mvp.totalRings">
|
||||||
<image src="../static/title-mvp.png" mode="widthFix" />
|
<image src="../static/title-mvp.png" mode="widthFix" />
|
||||||
<text
|
<text
|
||||||
>斩获<text
|
>斩获<text
|
||||||
@@ -127,7 +127,7 @@ const checkBowData = () => {
|
|||||||
margin: '0 3px',
|
margin: '0 3px',
|
||||||
fontWeight: '600',
|
fontWeight: '600',
|
||||||
}"
|
}"
|
||||||
>{{ data.mvp[0].totalRings }}</text
|
>{{ data.mvp.totalRings }}</text
|
||||||
>环</text
|
>环</text
|
||||||
>
|
>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -42,6 +42,17 @@ const battleTitle = computed(() => {
|
|||||||
return `${half}v${half}对抗赛`;
|
return `${half}v${half}对抗赛`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** 靶纸尺寸(cm),由 URL 参数或 API 返回的 targetType 字段填充 */
|
||||||
|
const targetSize = ref(0);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 targetSize 动态生成靶纸尺寸文本,如"40cm"
|
||||||
|
* 数据未就绪时显示 "--";数据来源:创建者取 URL 参数 target,加入者取 API 返回的 targetType
|
||||||
|
*/
|
||||||
|
const targetSizeLabel = computed(() =>
|
||||||
|
targetSize.value ? `${targetSize.value}cm` : '--'
|
||||||
|
);
|
||||||
|
|
||||||
const ready = ref(false);
|
const ready = ref(false);
|
||||||
const allReady = ref(false);
|
const allReady = ref(false);
|
||||||
const timer = ref(null);
|
const timer = ref(null);
|
||||||
@@ -56,6 +67,15 @@ async function refreshRoomData() {
|
|||||||
const result = await getRoomAPI(roomNumber.value);
|
const result = await getRoomAPI(roomNumber.value);
|
||||||
if (result.started) return;
|
if (result.started) return;
|
||||||
room.value = result;
|
room.value = result;
|
||||||
|
// 加入者通过 API 返回的 targetType 字段同步靶纸尺寸,并持久化到本地缓存
|
||||||
|
if (result.targetType) {
|
||||||
|
targetSize.value = result.targetType;
|
||||||
|
uni.setStorageSync(`targetSize_${roomNumber.value}`, result.targetType);
|
||||||
|
} else if (targetSize.value === 0) {
|
||||||
|
// API 无该字段时,从本地缓存兜底(如"返回房间"场景)
|
||||||
|
const stored = uni.getStorageSync(`targetSize_${roomNumber.value}`);
|
||||||
|
if (stored) targetSize.value = stored;
|
||||||
|
}
|
||||||
owner.value = {};
|
owner.value = {};
|
||||||
opponent.value = {};
|
opponent.value = {};
|
||||||
const members = result.members || [];
|
const members = result.members || [];
|
||||||
@@ -241,9 +261,24 @@ const canClick = computed(() => {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据对战类型和人数动态生成分享文案
|
||||||
|
* 1v1 / 默认 → "星球论箭,来一决高下敢否?"
|
||||||
|
* 2v2 → "2v2对抗赛,是兄弟来助我一把!"
|
||||||
|
* 3v3 → "3v3对抗赛,来了马上发车!"
|
||||||
|
* 乱斗 → "热血乱斗赛,敢来争锋?"
|
||||||
|
*/
|
||||||
|
const shareTitle = computed(() => {
|
||||||
|
const { battleType, count } = room.value;
|
||||||
|
if (battleType === 2) return '热血乱斗赛,敢来争锋?';
|
||||||
|
if (battleType === 1 && count === 4) return '2v2对抗赛,是兄弟来助我一把!';
|
||||||
|
if (battleType === 1 && count === 6) return '3v3对抗赛,来了马上发车!';
|
||||||
|
return '星球论箭,来一决高下敢否?';
|
||||||
|
});
|
||||||
|
|
||||||
onShareAppMessage(() => {
|
onShareAppMessage(() => {
|
||||||
return {
|
return {
|
||||||
title: "邀请您进入房间对战",
|
title: shareTitle.value,
|
||||||
path: "/pages/friend-battle?roomID=" + roomNumber.value,
|
path: "/pages/friend-battle?roomID=" + roomNumber.value,
|
||||||
imageUrl: "",
|
imageUrl: "",
|
||||||
};
|
};
|
||||||
@@ -269,6 +304,15 @@ onLoad(async (options) => {
|
|||||||
roomNumber.value = options.roomNumber;
|
roomNumber.value = options.roomNumber;
|
||||||
store.updateRoomNumber(options.roomNumber);
|
store.updateRoomNumber(options.roomNumber);
|
||||||
}
|
}
|
||||||
|
// 创建者通过 URL 参数 target(1→20cm,2→40cm)初始化靶纸尺寸,并持久化到本地缓存
|
||||||
|
if (options.target) {
|
||||||
|
targetSize.value = parseInt(options.target) * 20;
|
||||||
|
uni.setStorageSync(`targetSize_${roomNumber.value}`, targetSize.value);
|
||||||
|
} else if (roomNumber.value) {
|
||||||
|
// "返回房间"等无 target 参数的场景:从本地缓存恢复(待 refreshRoomData 进一步覆盖)
|
||||||
|
const stored = uni.getStorageSync(`targetSize_${roomNumber.value}`);
|
||||||
|
if (stored) targetSize.value = stored;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,11 +343,8 @@ onBeforeUnmount(() => {
|
|||||||
<GuideTwo>
|
<GuideTwo>
|
||||||
<view class="battle-guide">
|
<view class="battle-guide">
|
||||||
<view class="guide-tips">
|
<view class="guide-tips">
|
||||||
<text>弓箭手们,人都到齐了吗?</text>
|
<text class="guide-tips__target">请使用{{ targetSizeLabel }}全环靶</text>
|
||||||
<text v-if="room.battleType === 1">{{
|
<text class="guide-tips__warn">如果实际靶纸与选择靶纸不同,将导致射箭无效</text>
|
||||||
`${room.count / 2}v${room.count / 2}比赛即将开始!`
|
|
||||||
}}</text>
|
|
||||||
<text v-if="room.battleType === 2">大乱斗即将开始! </text>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</GuideTwo>
|
</GuideTwo>
|
||||||
@@ -818,4 +859,23 @@ onBeforeUnmount(() => {
|
|||||||
border: 1rpx solid #a3793f66;
|
border: 1rpx solid #a3793f66;
|
||||||
color: #fed847;
|
color: #fed847;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.guide-tips__target {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: rgba(255, 217, 71, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-tips__warn {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
margin-top: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.guide-tips {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 20rpx;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ async function onReceiveMessage(msg) {
|
|||||||
if (msg.type === MESSAGETYPESV2.ShootResult) {
|
if (msg.type === MESSAGETYPESV2.ShootResult) {
|
||||||
scores.value = msg.details;
|
scores.value = msg.details;
|
||||||
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
} else if (msg.type === MESSAGETYPESV2.BattleEnd) {
|
||||||
// setTimeout(onOver, 1500);
|
setTimeout(onOver, 1500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,12 +84,6 @@ const onClickShare = debounce(async () => {
|
|||||||
await wxShare("shareCanvas");
|
await wxShare("shareCanvas");
|
||||||
});
|
});
|
||||||
|
|
||||||
function onAudioEnded(s) {
|
|
||||||
if (s.indexOf("比赛结束") >= 0) {
|
|
||||||
onOver()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
// audioManager.play("第一轮");
|
// audioManager.play("第一轮");
|
||||||
uni.setKeepScreenOn({
|
uni.setKeepScreenOn({
|
||||||
@@ -97,7 +91,6 @@ onMounted(async () => {
|
|||||||
});
|
});
|
||||||
uni.$on("socket-inbox", onReceiveMessage);
|
uni.$on("socket-inbox", onReceiveMessage);
|
||||||
uni.$on("share-image", onClickShare);
|
uni.$on("share-image", onClickShare);
|
||||||
uni.$on("audioEnded", onAudioEnded);
|
|
||||||
const result = await createPractiseAPI(total, 120, targetType.value);
|
const result = await createPractiseAPI(total, 120, targetType.value);
|
||||||
if (result) practiseId.value = result.id;
|
if (result) practiseId.value = result.id;
|
||||||
});
|
});
|
||||||
@@ -108,7 +101,6 @@ onBeforeUnmount(() => {
|
|||||||
});
|
});
|
||||||
uni.$off("socket-inbox", onReceiveMessage);
|
uni.$off("socket-inbox", onReceiveMessage);
|
||||||
uni.$off("share-image", onClickShare);
|
uni.$off("share-image", onClickShare);
|
||||||
uni.$off("audioEnded", onAudioEnded);
|
|
||||||
audioManager.stopAll();
|
audioManager.stopAll();
|
||||||
endPractiseAPI();
|
endPractiseAPI();
|
||||||
});
|
});
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 25 KiB |
@@ -14,8 +14,7 @@ function createWebSocket(token, onMessage) {
|
|||||||
|
|
||||||
switch (envVersion) {
|
switch (envVersion) {
|
||||||
case "develop": // 开发版
|
case "develop": // 开发版
|
||||||
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";
|
||||||
|
|||||||
Reference in New Issue
Block a user