按钮互斥

This commit is contained in:
2025-08-14 20:36:42 +08:00
parent b56ab2dfd8
commit f7c04c88d4
2 changed files with 119 additions and 64 deletions

View File

@@ -215,4 +215,16 @@ video {
flex-direction: column;
align-items: center;
// justify-content: center;
}
.left-button.active {
background-color: red;
}
/* 互斥期间的其它三枚按钮置灰禁点 */
.left-button.disabled {
pointer-events: none;
cursor: not-allowed;
opacity: 0.5;
filter: grayscale(0.4);
}

View File

@@ -3,8 +3,9 @@
<el-scrollbar class="left"> <!-- 左边栏 -->
<div class="center-line"> <!-- 左边栏按钮 -->
<div v-for="(btn, index) in buttons" :key="index" style="width: 100%;">
<div v-if="btn.show?.()" class="left-button" :style="btn.style ? btn.style() : {}" @click="btn.onClick"
@mouseenter="hoverIndex = index" @mouseleave="hoverIndex = null">
<div v-if="btn.show?.()" class="left-button" :class="[{ active: isActive(btn), disabled: isDisabled(btn) }]"
:style="btn.style ? btn.style() : {}" @click="handleBtnClick(btn)" @mouseenter="hoverIndex = index"
@mouseleave="hoverIndex = null">
<img :src="hoverIndex === index ? btn.img.hover : btn.img.normal" alt="">
{{ btn.label }}
</div>
@@ -64,7 +65,7 @@
</template>
<script setup>
import { ref, onMounted, onUnmounted, onBeforeUnmount, watch, inject, nextTick } from "vue";
import { ref, onMounted, computed, onUnmounted, onBeforeUnmount, watch, inject, nextTick } from "vue";
import VideoConverter from "h264-converter";
import { useRouter } from 'vue-router';
import {
@@ -128,7 +129,7 @@ let isMsgPop = ref(false);
//播放器列表
let instanceList = [{}, {}, {}, {}, {}, {}, {}, {}];
//是否是在关注主播
let runType = ref(['', '', '', '', '', '', '', '']);
let runType = ref('');
//屏幕尺寸系数
let isMonitor = ref(false);
let iponeCoefficient = ref([{ width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }, { width: 1, height: 1 }]);
@@ -157,7 +158,56 @@ let phoneXYinfo = ref(getphoneXYinfo() == null ? [{}, {}, {}, {}, {}, {}, {}, {}
// 当前悬浮的按钮索引
const hoverIndex = ref(null)
const isMonitorOn = ref(false) // false 表示关闭true 表示开启
// 这四个互斥模式的 key和你的 runType 对应
const EXCLUSIVE_KEYS = ['brushLive', 'like', 'follow', 'listen'];
// 映射一下中文名,仅用于提示
const KEY_LABEL = {
brushLive: '刷直播',
like: '刷视频',
follow: '一键关注并打招呼',
listen: '监测消息',
};
// 当前激活的互斥 keyrunType 里只要是这四个之一就视为锁定)
const activeKey = computed(() => EXCLUSIVE_KEYS.includes(runType.value) ? runType.value : '');
// 是否处于锁定(有激活模式)
const isLocked = computed(() => !!activeKey.value);
// 尝试激活某个模式(带拦截、可二次点击退出)
function tryActivate(key, runner) {
// 其它模式在运行,阻止切换
if (activeKey.value && activeKey.value !== key) {
ElMessage.warning(`当前正在【${KEY_LABEL[activeKey.value]}】。请先点击“全部停止”或再次点击当前红色按钮停止。`);
return;
}
// 二次点击同一按钮 => 视为停止
if (activeKey.value === key) {
stop(); // 你已有的停止方法,会把 runType 置空并清理状态
return;
}
// 设置 runType 并跑逻辑
runType.value = key;
if (typeof runner === 'function') runner();
}
// 供模板使用:是否为激活按钮
function isActive(btn) {
return !!btn.key && activeKey.value === btn.key;
}
// 供模板使用:是否应禁用
function isDisabled(btn) {
// 只禁用互斥组内的按钮;非互斥按钮(刷新/重置/登出等)不受影响
return !!btn.key && isLocked.value && activeKey.value !== btn.key && EXCLUSIVE_KEYS.includes(btn.key);
}
// 统一处理点击,拦截禁用状态
function handleBtnClick(btn) {
if (isDisabled(btn)) return;
if (typeof btn.onClick === 'function') btn.onClick();
}
// 你可以用这种方式声明按钮们
const buttons = [
{
@@ -188,72 +238,62 @@ const buttons = [
}
},
{
label: '打开直播',
onClick: () => {
runType.value[0] = 'brushLive'
brushLive()
},
label: '直播',
key: 'brushLive',
onClick: () => tryActivate('brushLive', () => {
runType.value = 'brushLive';
brushLive();
}),
show: () => true,
img: {
normal: new URL('@/assets/video/leftBtn4.png', import.meta.url).href,
hover: new URL('@/assets/video/leftBtn4-4.png', import.meta.url).href
},
style: () => ({
backgroundColor: runType.value[0] == 'brushLive' ? 'red' : ''
})
style: () => ({ backgroundColor: isActive({ key: 'brushLive' }) ? 'red' : '' })
},
{
label: '一键养号',
onClick: () => {
if (runType.value[0] == 'like') return;
runType.value[0] = 'like'
parentNum()
},
label: '刷视频',
key: 'like',
onClick: () => tryActivate('like', () => {
runType.value = 'like';
parentNum();
}),
show: () => true,
img: {
normal: new URL('@/assets/video/leftBtn5.png', import.meta.url).href,
hover: new URL('@/assets/video/leftBtn5-5.png', import.meta.url).href
},
style: () => ({
backgroundColor: runType.value[0] == 'like' ? 'red' : ''
})
style: () => ({ backgroundColor: isActive({ key: 'like' }) ? 'red' : '' })
},
{
label: '一键关注并打招呼',
onClick: () => {
if (runType.value[0] == 'follow') return;
runType.value[0] = 'follow'
showDialog.value = true
dialogTitle.value = '主播ID'
selectedDevice.value = 999
},
key: 'follow',
onClick: () => tryActivate('follow', () => {
runType.value = 'follow';
showDialog.value = true;
dialogTitle.value = '主播ID';
selectedDevice.value = 999;
}),
show: () => true,
img: {
normal: new URL('@/assets/video/leftBtn6.png', import.meta.url).href,
hover: new URL('@/assets/video/leftBtn6-6.png', import.meta.url).href
},
style: () => ({
backgroundColor: runType.value[0] == 'follow' ? 'red' : ''
})
style: () => ({ backgroundColor: isActive({ key: 'follow' }) ? 'red' : '' })
},
{
label: '监测消息',
onClick: () => {
isMonitorOn.value = !isMonitorOn.value
if (isMonitorOn.value) {
openMonitor()
} else {
cloesMonitor()
}
},
key: 'listen',
onClick: () => tryActivate('listen', () => {
isMonitorOn.value = true;
openMonitor();
}),
show: () => true,
img: {
normal: new URL('@/assets/video/leftBtn1.png', import.meta.url).href,
hover: new URL('@/assets/video/leftBtn1-1.png', import.meta.url).href
},
style: () => ({
backgroundColor: isMonitorOn.value ? 'red' : ''
})
style: () => ({ backgroundColor: isActive({ key: 'listen' }) ? 'red' : '' })
},
{
label: '全部停止',
@@ -381,7 +421,7 @@ const initVideoStream = async (udid, index) => {
} else if (resData.type == 'getmesNum') {
if (resData.message == 0) {
console.log('没有消息')
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
LikesToLikesToLikes(deviceInformation.value[index].udid, index)
}
@@ -389,7 +429,7 @@ const initVideoStream = async (udid, index) => {
} else if (resData.message == 1) {
console.log('有消息')
} else if (resData.message == '点击成功') {
console.log('双击', iponeCoefficient.value[index].width, iponeCoefficient.value[index].height)
console.log('双击', resData.x * iponeCoefficient.value[index].width, resData.y * iponeCoefficient.value[index].height, index)
setTimeout(() => {
clickxy(resData.x * iponeCoefficient.value[index].width, resData.y * iponeCoefficient.value[index].height, index)
setTimeout(() => {
@@ -406,6 +446,9 @@ const initVideoStream = async (udid, index) => {
Back('', index)
setTimeout(() => {
Back('', index)
if (runType.value == 'follow') {
LikesToLikesToLikes(deviceInformation.value[index].udid, index)
}
}, 1000)
}, 1000)
@@ -475,7 +518,7 @@ const initVideoStream = async (udid, index) => {
iponeCoefficient.value[index].width = scaledW / resData.width
iponeCoefficient.value[index].height = scaledH / resData.height
console.log(
`[getSize] raw=${RAW_W}x${RAW_H} -> scaled=${scaledW}x${scaledH} (align↓${ALIGN})`
`[getSize] raw=${RAW_W}x${RAW_H} -> scaled=${scaledW}x${scaledH} (align↓${ALIGN}) ${iponeCoefficient.value[index].width} ${iponeCoefficient.value[index].height}`
);
} else {
console.log(resData.type, '坐标返回x:', resData.x, 'y:', resData.y);
@@ -484,7 +527,7 @@ const initVideoStream = async (udid, index) => {
phoneXYinfo.value[index].id = resData.device
if (resData.type == 'Likes') {//判断是否是 点赞
phoneXYinfo.value[index].Likes = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
}
} else if (resData.type == 'Comment') {//打开评论
@@ -498,7 +541,7 @@ const initVideoStream = async (udid, index) => {
phoneXYinfo.value[index].ComPush = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
setTimeout(() => {
Back('', index)
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
setTimeout(() => {
Back('', index)
}, 1000)
@@ -612,7 +655,7 @@ const initVideoStream = async (udid, index) => {
// 用法:
(async () => {
const result = await randomDelayAndExecute();
if (runType.value[0] !== 'brushLive') {
if (runType.value !== 'brushLive') {
return
}
//30%概率
@@ -661,7 +704,7 @@ const initVideoStream = async (udid, index) => {
// ----------------------------------------------------------------------------------------------------报错处理
//如果该视频无法被评论,或者没有评论,返回刷下一条视频
if (resData.type == 'Comtext' || resData.type == 'CommentText') {
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
Back('', index)
setTimeout(() => {
@@ -687,7 +730,7 @@ const initVideoStream = async (udid, index) => {
}, 1000)
}, 1000)
} else if (resData.type == 'Privatetex' || resData.type == 'hostVideo' || resData.type == 'search' || resData.type == 'Attention' || resData.type == 'Comment') {
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
//关注的时候出现无法私信和没有视频的情况 错误重置
resetApp(udid, index)
setTimeout(() => {
@@ -697,7 +740,7 @@ const initVideoStream = async (udid, index) => {
}
} else if (resData.type == 'getmesNum') {
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
LikesToLikesToLikes(deviceInformation.value[index].udid, index)
}
//getmesNum出现没有消息的情况
@@ -907,8 +950,8 @@ onMounted(() => {
//私信
textContentpriArr.value.forEach((item, indexA) => {
textContentpri.value[indexA] = resB[getRandomNumber(resB.length - 1)];
runType.value[indexA] = 'follow'
console.log('runType', runType.value[indexA])
runType.value = 'follow'
console.log('runType', runType.value)
})
deviceInformation.value.forEach((device, indexB) => {
if (getHostList().length <= 0) return;
@@ -927,7 +970,7 @@ onMounted(() => {
} else {
// stroageHost.value = getHostList()
stroageHost.value.push(({ country: data.country, text: data.hostsId, state: false }))
if (runType.value[0] == 'follow') {
if (runType.value == 'follow') {
setHostList(stroageHost.value)
}
@@ -1051,7 +1094,7 @@ async function LikesToCommentToComPush(udid, index) {
//点赞主页4个作品+评论最后一个作品并返回
async function LikesToLikesToLikes(udid, index) {
isStop.value = false;
runType.value[index] = 'follow';
runType.value = 'follow';
// await sendWsTask(index, { udid, action: 'click', type: 'getmesNum', index, resourceId: 'com.zhiliaoapp.musically:id/jyv' });
await sendWsTask(index, { udid, action: 'click', type: 'search', index, resourceId: 'com.zhiliaoapp.musically:id/gtz' });
@@ -1093,7 +1136,7 @@ function setComText(index) {
}, 300);
console.log('发送评论内容', index, textContent.value[index])
wslist[index].send(setClipboard(textContent.value[index]));
if (runType.value[index] === 'follow') {
if (runType.value === 'follow') {
textContent.value[index] = getContentList()[index][getRandomNumber(getContentList()[index].length - 1)];
}
}
@@ -1124,7 +1167,7 @@ function setPrivateText(index, datatype) {
}, 300);
console.log('发送私信内容', index, textContentpri.value[index])
//如果是在关注主播中,发送的开场白进行对应国家翻译
if (runType.value[index] === 'follow' && datatype == 'PrivatePush') {
if (runType.value === 'follow' && datatype == 'PrivatePush') {
translation({ msg: getContentpriList()[index][getRandomNumber(getContentpriList()[index].length - 1)], country: hostIdArr.value[index].country }).then(res => {
console.log(res)
textContentpri.value[index] = res;
@@ -1312,7 +1355,7 @@ function sendWsTask(index, data) {
if (data.type == 'isHost') {
}
if (data.type == 'Comment') {
if (runType.value[index] == 'follow') {
if (runType.value == 'follow') {
clickxy(160, 360, index)
}
}
@@ -1431,7 +1474,7 @@ function stop() {
//停止当前任务
//重置当前状态
runType.value[i] = ''
runType.value = ''
//清除观看视频定时器
clearInterval(playTimer.value[i])
playTimer.value[i] = null;//清除定时器
@@ -1458,7 +1501,7 @@ function openMonitor(type) {
deviceInformation.value.forEach((device, index) => {
wsActions.getmesNum(device.udid, index)
runType.value[index] = 'listen'
runType.value = 'listen'
})
isShowMes.value = setInterval(() => {
deviceInformation.value.forEach((device, index) => {
@@ -1471,7 +1514,7 @@ function openMonitor(type) {
function cloesMonitor() {
isMonitorOn.value = false;//关闭监听
deviceInformation.value.forEach((device, index) => {
runType.value[index] = ''
runType.value = ''
})
clearInterval(isShowMes.value)
isShowMes.value = ''
@@ -1481,14 +1524,14 @@ function cloesMonitor() {
function parentNum() {
isStop.value = false;
deviceInformation.value.forEach((device, index) => {
runType.value[index] = 'like'
runType.value = 'like'
wsActions.isHost(device.udid, index)
})
}
function brushLive() {
isStop.value = false;
deviceInformation.value.forEach((device, index) => {
runType.value[index] = 'brushLive'
runType.value = 'brushLive'
wsActions.toLive(device.udid, index)
})
}
@@ -1518,7 +1561,7 @@ function onDialogConfirm(result, type, index, isMon) {
isMonitor.value = isMon //是否自动回复
textContentpriArr.value.forEach((item, indexA) => {
textContentpri.value[indexA] = result[getRandomNumber(result.length - 1)];
runType.value[indexA] = 'follow'
runType.value = 'follow'
})
// isStop.value = true; //停止所有任务
setContentpriList(result)