1. 现在可以自定义了!
2. 修改了右侧边栏的样式
This commit is contained in:
Fang_Zhijian 2024-05-18 15:32:04 +08:00
parent ced8fd7874
commit 2daf0d43a4
31 changed files with 400 additions and 41 deletions

83
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "poros-demo-client",
"version": "0.0.0",
"name": "blive-coyote-demo-client",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "poros-demo-client",
"version": "0.0.0",
"name": "blive-coyote-demo-client",
"version": "0.0.1",
"dependencies": {
"vue": "^3.2.25"
},
@ -15,6 +15,7 @@
"@types/node": "17.0.25",
"@vitejs/plugin-vue": "2.3.0",
"axios": "0.26.1",
"node-localstorage": "3.0.5",
"notyf": "3.0.0",
"qrcode": "1.5.3",
"typescript": "4.5.4",
@ -1003,6 +1004,15 @@
"entities": "^3.0.1"
}
},
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true,
"engines": {
"node": ">=0.8.19"
}
},
"node_modules/is-core-module": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.8.1.tgz",
@ -1115,6 +1125,18 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/node-localstorage": {
"version": "3.0.5",
"resolved": "https://registry.npmmirror.com/node-localstorage/-/node-localstorage-3.0.5.tgz",
"integrity": "sha512-GCwtK33iwVXboZWYcqQHu3aRvXEBwmPkAMRBLeaX86ufhqslyUkLGsi4aW3INEfdQYpUB5M9qtYf3eHvAk2VBg==",
"dev": true,
"dependencies": {
"write-file-atomic": "^5.0.1"
},
"engines": {
"node": ">=0.12"
}
},
"node_modules/notyf": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/notyf/-/notyf-3.0.0.tgz",
@ -1427,6 +1449,15 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@ -1791,6 +1822,19 @@
"node": ">=8"
}
},
"node_modules/write-file-atomic": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"dependencies": {
"imurmurhash": "^0.1.4",
"signal-exit": "^4.0.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/ws": {
"version": "8.17.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.0.tgz",
@ -2579,6 +2623,12 @@
"entities": "^3.0.1"
}
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
"dev": true
},
"is-core-module": {
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.8.1.tgz",
@ -2673,6 +2723,15 @@
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.2.tgz",
"integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA=="
},
"node-localstorage": {
"version": "3.0.5",
"resolved": "https://registry.npmmirror.com/node-localstorage/-/node-localstorage-3.0.5.tgz",
"integrity": "sha512-GCwtK33iwVXboZWYcqQHu3aRvXEBwmPkAMRBLeaX86ufhqslyUkLGsi4aW3INEfdQYpUB5M9qtYf3eHvAk2VBg==",
"dev": true,
"requires": {
"write-file-atomic": "^5.0.1"
}
},
"notyf": {
"version": "3.0.0",
"resolved": "https://registry.npmmirror.com/notyf/-/notyf-3.0.0.tgz",
@ -2940,6 +2999,12 @@
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true
},
"signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
@ -3231,6 +3296,16 @@
"strip-ansi": "^6.0.0"
}
},
"write-file-atomic": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"requires": {
"imurmurhash": "^0.1.4",
"signal-exit": "^4.0.1"
}
},
"ws": {
"version": "8.17.0",
"resolved": "https://registry.npmmirror.com/ws/-/ws-8.17.0.tgz",

View File

@ -20,6 +20,7 @@
"vue-tsc": "0.29.8",
"ws": "8.17.0",
"qrcode": "1.5.3",
"notyf": "3.0.0"
"notyf": "3.0.0",
"node-localstorage": "3.0.5"
}
}

View File

@ -10,6 +10,19 @@ body {
background-color: #171717;
}
p, h2 {
margin: 10px 0;
}
h3 {
margin: 8px 0;
}
hr {
margin: 10px 0;
border: 1px solid #fce9a7;
}
.icon {
-webkit-user-select: none;
user-select: none;
@ -24,6 +37,10 @@ body {
display: none;
}
img {
vertical-align: middle;
}
button {
cursor: pointer;
background-color: #fce9a7;
@ -54,6 +71,18 @@ select {
}
input[type="checkbox"] {
width: 16px;
height: 16px;
-webkit-appearance: none;
border: 1px solid #fce9a7;
border-radius: 2px;
outline: none;
}
input[type="checkbox"]:checked {
background: #fce9a7;
}
/* Offline page */
.offline .interstitial-wrapper {
@ -441,6 +470,35 @@ select {
bottom: 10px;
}
.channel-circle {
width: 80px;
text-align: center;
height: 80px;
border-radius: 50%;
border: #fce9a7 2px solid;
margin: 8px;
}
.channel-tag {
line-height: 20px;
font-size: 18px;
color: #fce9a7;
background: #171717;
transform: translateY(-10px);
}
.channel-strength {
line-height: 40px;
font-size: 32px;
color: #fce9a7;
}
.soft-strength {
line-height: 20px;
font-size: 18px;
color: #fce9a7;
background: #171717;
transform: translateY(10px);
}
.game-title {
display: flex;
}

BIN
public/img/30758.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/img/30873.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
public/img/31028.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
public/img/31037.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/img/31044.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/img/31049.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/31053.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/31122.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/31164.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
public/img/31588.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/img/31883.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
public/img/32122.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/img/32201.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/img/32228.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
public/img/32575.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/img/32609.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/img/32692.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/32734.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/img/32758.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/img/32761.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/img/32768.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
public/img/33031.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
public/img/33032.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
public/img/33988.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
public/img/34065.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,7 +1,7 @@
<script setup lang="ts">
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import { ref } from "vue"
import { ref, watch } from "vue"
import axios from "axios"
import { Notyf } from 'notyf'
import { createSocket, destroySocket } from "./socket/index"
@ -19,15 +19,29 @@ import {
followAStrength,
followBStrength
} from "./socket/coyote"
import { waveData, strengthData, giftData } from "./assets/dataMap";
const notyf = new Notyf({ duration: 3000 })
// API
const api = axios.create({
baseURL: "http://localhost:3000",
baseURL: "https://blive.babyfang.cn/",
})
//
let settings = ref()
if (window.localStorage.getItem("settings")) {
settings.value = JSON.parse(window.localStorage.getItem("settings") || '{}');
// console.log(settings.value)
} else {
// 使
settings.value = {
waveData: waveData,
strengthData: strengthData
};
}
//
const codeId = ref("")
// app []
@ -42,7 +56,20 @@ const heartBeatTimer = ref<NodeJS.Timer>()
// be ready
clearInterval(heartBeatTimer.value!)
//
const waveData = ref("")
const waveTestData = ref("")
//
const showSettings = ref(false)
const selectedGift = ref('')
const selectedWave = ref('')
const relations = ref(Object.entries(giftData).map(([key, value]) => ({ gift: key, wave: settings.value.waveData[key] })))
// console.log(relations.value)
watch(selectedGift, (newGift) => {
selectedWave.value = waveData[newGift]
})
/**
* 测试请求鉴权接口
@ -167,9 +194,9 @@ const handleDestroySocket = () => {
*/
const test = () => {
try {
sendWaveData(5, 5, waveData.value, waveData.value)
sendWaveData(5, 5, waveTestData.value, waveTestData.value)
addOrIncrease(2, 1, 1)
console.log(waveData.value)
console.log(waveTestData.value)
notyf.success("波形发送成功")
}
catch (e) {
@ -191,6 +218,37 @@ const showqrcode = () => {
const hideqrcode = () => {
qrcodeShow.value = false;
}
/**
* 保存设置
*/
const saveSettings = () => {
window.localStorage.setItem('settings', JSON.stringify(settings.value));
console.log(settings.value);
}
/**
* 添加并保存 waveData
*/
const addRelationAndSave = () => {
//
const existingRelation = relations.value.find(relation => relation.gift === selectedGift.value);
if (existingRelation) {
//
existingRelation.wave = selectedWave.value;
} else {
//
relations.value.push({ gift: selectedGift.value, wave: selectedWave.value });
}
// settings.waveData
settings.value.waveData[selectedGift.value] = selectedWave.value;
console.log(settings.value.waveData)
//
saveSettings();
}
</script>
<template>
@ -206,26 +264,121 @@ const hideqrcode = () => {
<div class="close-qrcode" @click="hideqrcode">关闭</div>
</div>
</div>
<div class="settings-window" v-show="showSettings">
<button @click="showSettings = false" style="float: right"></button>
<div>
<h2>强度规则</h2>
<p>礼物规则 <u title="收到指定礼物后将更新强度">?</u></p>
<div>
赠送
<select name="addStrengthGift" id="addStrengthGift" v-model="settings.strengthData[0]">
<option v-for="(value, key) in giftData" :value="key">
{{ value }}
</option>
</select>
使强度 +1
</div>
<div>
赠送
<select name="subStrengthGift" id="subStrengthGift" v-model="settings.strengthData[1]">
<option v-for="(value, key) in giftData" :value="key">
{{ value }}
</option>
</select>
使强度 -1
</div>
<p>强度跟随 <u title="开启后对应强度将自动跟随软上限变化">?</u></p>
<div style="display: flex">
A<input type="checkbox" v-model="followAStrength" />
B<input type="checkbox" v-model="followBStrength" />
</div>
<button @click="saveSettings">保存</button>
<h2>波形规则</h2>
<div>
<div v-for="relation in relations" :key="relation.gift">
<div v-if="relation && relation.wave">
赠送
<span class="tag"> {{ giftData[relation.gift] }} </span>
输出波形
<input class="tag" v-model="relation.wave" disabled>
</div>
</div>
<div>
<div>
赠送
<select v-model="selectedGift">
<option v-for="(value, key) in giftData" :value="key">
{{ value }}
</option>
</select>
输出波形
<input v-model="selectedWave">
</div>
<a onclick="window.open('waveHelper.html', '', 'width=500,height=1000,left=700');">波形助手</a>
</div>
<button @click="addRelationAndSave">新建或保存</button>
</div>
</div>
</div>
<div class="game-tips">
! 请在连接前确保已经设置好强度上限
</div>
<div class="game-info">
<h2>主机状态</h2>
<p>A: {{ channelAStrength }} / {{ softAStrength }}</p>
<p>B: {{ channelBStrength }} / {{ softBStrength }}</p>
<hr />
<h2>游戏设置</h2>
<p>强度跟随 <u title="开启后对应强度将自动跟随软上限变化">?</u></p>
A<input type="checkbox" v-model="followAStrength" />
B<input type="checkbox" v-model="followBStrength" />
<div style="display: flex">
<div class="channel-circle">
<div class="channel-tag">A</div>
<div class="channel-strength">{{ channelAStrength }}</div>
<div class="soft-strength">{{ softAStrength }}</div>
</div>
<div class="channel-circle">
<div class="channel-tag">B</div>
<div class="channel-strength">{{ channelBStrength }}</div>
<div class="soft-strength">{{ softBStrength }}</div>
</div>
</div>
<hr />
<h2>游戏玩法</h2>
<p><img src="/img/31036.png" width="18" alt="小花花">强度 -1</p>
<p><img src="/img/31039.png" width="18" alt="牛哇牛哇">强度 +1</p>
<h3>强度控制</h3>
<p>
赠送
<img :src="'/img/' + settings.strengthData[0] + '.png'" width="24" :alt="giftData[settings.strengthData[0]]">
<input class="tag" v-model="giftData[settings.strengthData[0]]" size="6" disabled>
强度 +1
</p>
<p>
赠送
<img :src="'/img/' + settings.strengthData[1] + '.png'" width="24" :alt="giftData[settings.strengthData[1]]">
<input class="tag" v-model="giftData[settings.strengthData[1]]" size="6" disabled>
强度 -1
</p>
<h3>波形控制</h3>
<div>
<p>赠送如下礼物可输出波形</p>
<div v-for="relation in relations" :key="relation.gift">
<div v-if="relation && relation.wave">
<img :src="'/img/' + relation.gift + '.png'" width="24" :alt="giftData[relation.gift]">
<input class="tag" v-model="giftData[relation.gift]" disabled>
</div>
</div>
</div>
<button @click="showSettings = true">修改玩法</button>
</div>
<div>
<h2>系统设置</h2>
@ -246,7 +399,7 @@ const hideqrcode = () => {
<div class="form">
<button @click="getAuth">鉴权</button>
<label>波形数组 <a onclick="window.open('waveHelper.html', '', 'width=500,height=1000,left=700');">波形助手</a></label>
<input type="text" placeholder="填写欲测试的波形数组" v-model="waveData" />
<input type="text" placeholder="填写欲测试的波形数组" v-model="waveTestData" />
<button @click="test">测试</button>
</div>
</div>
@ -268,4 +421,24 @@ const hideqrcode = () => {
margin: 10px 0;
font-size: 18px;
}
.settings-window {
position: fixed;
top: 10%;
bottom: 10%;
height: 500px;
left: 10%;
right: 10%;
background-color: #171717;
border-radius: 20px;
border: #ffe99d 2px solid;
z-index: 100;
padding: 20px;
}
.tag {
background: #fce9a7;
color: #000;
border-radius: 5px;
}
</style>

View File

@ -7,13 +7,37 @@ const waveData = {
"32609": `["4A4A4A4A64646464","4545454564646464","4040404064646464","3B3B3B3B64646464","3636363664646464","3232323264646464","2D2D2D2D64646464","2828282864646464","2323232364646464","1E1E1E1E64646464","1A1A1A1A64646464"]`,
}
const strengthData = ["31039", "31036"]
// 礼物id和礼物名的对应关系
const giftData = {
"30758": "这个好欸",
"30873": "花式夸夸",
"31028": "探索者启航",
"31036": "小花花",
"31039": "牛哇牛哇",
"32609": "棒棒糖",
"31037": "打call",
"31039": "牛哇牛哇",
"31044": "情书",
"31049": "干杯",
"31053": "告白花束",
"31122": "星愿水晶球",
"31164": "粉丝团灯牌",
"31588": "星河入梦",
"31883": "璀璨烟火",
"32122": "小电视飞船",
"32201": "么么",
"32228": "爱的乐章",
"32575": "萌兔火箭",
"32609": "棒棒糖",
"32692": "落樱缤纷",
"32734": "快乐时光",
"32758": "爱心雨",
"32761": "可爱捏",
"32768": "携手同行",
"33031": "动鳗电机",
"33032": "干杯工厂",
"33988": "人气票",
"34065": "为你打call",
}
export { waveData }
export { waveData, strengthData, giftData }

View File

@ -1,11 +1,33 @@
import DanmakuWebSocket from "../assets/danmaku-websocket.min.js"
import { Notyf } from 'notyf'
import { closeCoyoteSocket, addOrIncrease, sendWaveData } from "./coyote"
import { waveData } from "../assets/dataMap";
import { waveData, strengthData } from "../assets/dataMap";
import { Ref, ref } from "vue";
let ws: DanmakuWebSocket
const notyf = new Notyf({ duration: 4000 })
interface SettingsType {
strengthData: typeof strengthData;
waveData: typeof waveData;
}
let settings: Ref<SettingsType> = ref({
waveData: waveData,
strengthData: strengthData
});
if (window.localStorage.getItem("settings")) {
settings.value = JSON.parse(window.localStorage.getItem("settings") || '{}');
console.log(settings.value)
} else {
// 如果没有,使用默认值
settings.value = {
waveData: waveData,
strengthData: strengthData
};
}
/**
* socket长连接
* @param authBody
@ -30,33 +52,39 @@ function createSocket(authBody: string, wssLinks: string[]) {
// }
// }
settings = window.localStorage.getItem("settings") ? ref(JSON.parse(window.localStorage.getItem("settings") || '{}')) : null
console.log(settings.value)
if (res.cmd == "LIVE_OPEN_PLATFORM_SEND_GIFT") {
if (res.data.gift_id == 31036) {
if (res.data.gift_id.toString() === settings.value.strengthData[0]) {
// 牛哇牛哇加强度1
try {
console.log("开始操作")
addOrIncrease(2, 1, 1)
addOrIncrease(2, 2, 1)
console.log("结束操作")
notyf.success("收到" + res.data.gift_name + ",强度+1")
}
catch (e) {
console.log(e)
notyf.error("强度操作失败!")
}
} else if (res.data.gift_id.toString() === settings.value.strengthData[1]) {
// 小花花减强度1
try {
addOrIncrease(1, 1, 1)
addOrIncrease(1, 2, 1)
notyf.success("收到花花,强度-1")
notyf.success("收到" + res.data.gift_name + ",强度-1")
}
catch (e) {
console.log(e)
notyf.error("强度操作失败!")
}
} else if (res.data.gift_id == 31039) {
// 牛哇牛哇加强度1
try {
addOrIncrease(2, 1, 1)
addOrIncrease(2, 2, 1)
notyf.success("收到牛牛,强度+1")
}
catch (e) {
console.log(e)
notyf.error("强度操作失败!")
}
} else {
} else if(settings.value.waveData[res.data.gift_id]) {
// 其他礼物,发送波形数据
try {
sendWaveData(5, 5, waveData[res.data.gift_id], waveData[res.data.gift_id])
sendWaveData(5, 5, settings.value.waveData[res.data.gift_id], settings.value.waveData[res.data.gift_id])
notyf.success("收到礼物" + res.data.gift_name)
}
catch (e) {