Files
tkAiPage/src/views/Untitled-1.vue
2025-07-15 13:45:36 +08:00

1537 lines
60 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="main">
<el-scrollbar class="left">
<div class=" center-line">
<!-- <el-button class="open" @click="wsActions.open(device.udid, index)"></el-button>
<el-button class="Back" @click="Back(device.udid, index)"></el-button>
<el-button class="Home" @click="Home(device.udid, index)"></el-button>
<el-button class="Overview" @click="Overview(device.udid, index)"></el-button> -->
<!-- <el-button @click="play(device.udid, index)">play</el-button> -->
<!-- <el-button class="open" @click="slideDown(device.udid, index)"></el-button>
<el-button class="open" @click="slideUp(device.udid, index)"></el-button>
<el-button class="open" @click="clickLike(device.udid, index)"></el-button> -->
<div></div>
<!-- <el-button @click="clickLikes(device.udid, index)">点赞</el-button> -->
<!-- <el-button @click="stopLike(index)">停止点赞</el-button> -->
<!-- <div></div>
<el-button @click="clickComment(device.udid, index)">评论</el-button>
<el-button @click="clickComtext(device.udid, index)">评论框</el-button>
<el-button @click="clickComPush(device.udid, index)">发布评论</el-button>
<div></div>
<el-button @click="clicktomy(device.udid, index)">主页</el-button> -->
<!-- <el-button @click="wsActions.clickAttention(device.udid, index)">关注/私信</el-button> -->
<!-- <div></div>
<el-button @click="clickPrivatetext(device.udid, index)">私信输入</el-button>
<el-button @click="clickPrivatePush(device.udid, index)">私信发送</el-button> -->
<el-button type="warning" @click="reloadfun()">刷新</el-button>
<div></div>
<!-- <el-button @click="wsActions.clickCopy(device.udid, index)">找私信</el-button> -->
<!-- <el-button @click="wsActions.clickCopyList(device.udid, index)">私信列表</el-button> -->
<div></div>
<!-- <el-button @click="wsActions.getmesNum(device.udid, index)">获取收件箱</el-button> -->
<!-- <el-button @click="wsActions.getSize(device.udid, index)">获取屏幕尺寸</el-button> -->
<!-- <el-button @click="wsActions.slideRight(device.udid, index)">右滑</el-button> -->
<!-- <el-button @click="wsActions.isHost(device.udid, index)">一键养号</el-button> -->
<el-button type="success" @click="openTk()">打开tiktok</el-button>
<el-button type="success"
@click="showDialog = true; dialogTitle = '评论'; selectedDevice = 999">一键养号</el-button>
<el-button type="success"
@click="showDialog = true; dialogTitle = '主播ID'; selectedDevice = 999">一键关注并打招呼</el-button>
<el-button type="success" v-if="!isShowMes" @click="openMonitor()">开启监测消息</el-button>
<el-button type="danger" v-else @click="cloesMonitor()">关闭监测消息</el-button>
<el-button type="danger" @click="stop()">全部停止</el-button>
<el-button type="danger" @click="router.push('/')">登出</el-button>
<div></div>
<div></div>
<!-- <el-button @click="wsActions.test(device.udid, index)">截屏</el-button> -->
<div></div>
<!-- <el-button @click="wsActions.search(device.udid, index)">搜索</el-button>
<div></div>
<el-button @click="wsActions.searchHost(device.udid, index)">搜主播</el-button>
<div></div>
<el-button @click="wsActions.toHost(device.udid, index)">主页</el-button>
<div></div>
<el-button @click="LikesToLikesToLikes(device.udid, index)">批量关注</el-button> -->
<div></div>
<!-- <div style="display: flex;">
<div style="width: 150px;">主播id</div>
<el-input style="border: 1px solid #000;" v-model="hostIdContent[index]" type="text"></el-input>
<el-button @click="setHostId(index)">发送</el-button>
</div>
<div style="display: flex;">
<div style="width: 150px;">评论内容</div>
<el-input style="border: 1px solid #000;" v-model="textContent[index]" type="text"></el-input>
<el-button @click="setComText(index)">发送</el-button>
</div> -->
<!-- <div style="display: flex;">
<div style="width: 150px;">私信内容</div>
<el-input style="border: 1px solid #000;" v-model="textContentpri[index]" type="text"></el-input>
<el-button @click="setPrivateText(index)">发送</el-button>
</div> -->
<div></div>
<!-- <el-button @click="clickxy(160, 360, index)">开始/暂停</el-button> -->
<div></div>
<!-- <el-button @click="clickxy(284, 392, index, 9)">长按</el-button> -->
<!-- <el-button @click="getText(index)">获取粘贴板内容</el-button> -->
<div></div>
<!-- <el-button @click="LikesToCommentToComPush(device.udid, index)">设置自动化坐标</el-button> -->
<!-- <el-button @click="start(device.udid, index)">开始执行</el-button> -->
<!-- <el-button @click="stop(device.udid, index)">停止</el-button> -->
<div></div>
<!-- <el-button @click="wsActions.isVideoAndLive(device.udid, index)">判断视频还是直播</el-button> -->
</div>
</el-scrollbar>
<div class="content" @click.self="selectedDevice = 999">
<div class="video-container" @click.self="selectedDevice = 999" v-for="(device, index) in deviceInformation"
:key="device.udid" @mouseup="(e) => handleCanvasup(device.udid, e, index)">
<div class="video-canvas">
<video :ref="(el) => (videoElement[device.udid] = el)" autoplay muted playsinline
:style="getVideoStyle(index)" @click.stop="selectedDeviceFun(index)"></video>
<canvas class="canvas" v-show="selectedDevice == index" :ref="(el) => (canvasRef[device.udid] = el)"
@mousemove.stop="(e) => handleMouseMove(device.udid, e, index)"
@mousedown.stop="(e) => handleCanvasdown(device.udid, e, index)">
</canvas>
</div>
<div class="input-info" v-show="selectedDevice == index"
:style="{ left: phone.width * 1.4 + 4 + '0px' }">
<!-- <div class="input-info" v-show="false"> -->
<el-button @click="showDialog = true; dialogTitle = '主播ID';">批量关注</el-button>
<div></div>
<el-button @click="showDialog = true; dialogTitle = '评论';">导入评论</el-button>
<div></div>
<el-button @click="getComArr(index, '评论')">查看评论</el-button>
<div></div>
<el-button @click="showDialog = true; dialogTitle = '私信';">导入私信</el-button>
<div></div>
<el-button @click="getComArr(index, '私信')">查看私信</el-button>
<el-button @click="wsActions.getmesNum(device.udid, index)">检测消息</el-button>
<el-button @click="wsActions.clickMesage(device.udid, index)">进入消息</el-button>
<el-button
@click="wsActions.clickCopyList(device.udid, index); openShowChat = true; istranslate = true">翻译本页对话</el-button>
<el-button @click="wsActions.getSize(device.udid, index)">获取屏幕尺寸</el-button>
<div style="display: flex;">
<el-input style="border: 1px solid #000;" v-model="textContent[index]" type="text"></el-input>
<el-button @click="setComText(index)">发送</el-button>
</div>
<el-button @click="wsActions.test(device.udid, index)">截屏</el-button>
<!-- <el-button @click="wsActions.isHost(device.udid, index)">一键养号</el-button> -->
</div>
</div>
<!--
<div class="video-container" @click.self="selectedDevice = 999" v-for="item in 4" :style="getVideoStyle()"
:class="{ 'bottom-row': item >= 2 }">
<div style="position: relative;box-sizing: border-box; ">
</div>
</div> -->
</div>
<div class="right">
<!-- <el-button @click="openShowChat = !openShowChat">聊天</el-button> -->
<ChatDialog :visible="openShowChat" :messages="chatList" />
<!-- <ChatDialog :visible="openShowChat" :leftMsg="chatContent.left" :rightMsg="chatContent.right"
@close="show = false" /> -->
</div>
<MultiLineInputDialog v-model:visible="showDialog" :initialText='""' :title="dialogTitle"
:index="selectedDevice" @confirm="onDialogConfirm" @cancel="onDialogCancel" />
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted, onBeforeUnmount, watch, inject } from "vue";
import VideoConverter from "h264-converter";
import { Buffer } from 'buffer'; // 如果在浏览器环境需要引入buffer包
import { useRouter } from 'vue-router';
import { setphoneXYinfo, getphoneXYinfo } from '@/utils/storage'
import { set } from "lodash";
import { toBufferBtn, stringToUtf8ByteArray, getClipboard, setClipboard, bufferToString, startsWithHeader, trimLongArray, base64ToBinary, toBuffer } from '@/utils/bufferUtils';
import { createWsActions } from '@/utils/wsActions';
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
import { chat, translation } from "@/api/chat";
import MultiLineInputDialog from '@/components/MultiLineInputDialog.vue'; // 根据实际路径修改
import ChatDialog from '@/components/ChatDialog.vue'
const router = useRouter();
let wsActions = null;
// 引入刷新方法
const reload = inject("reload")
let refresh = ref(true);
let phone = ref({ width: 207, height: 470 });
const openStr = base64ToBinary("ZQBwAAAAAAA8CgLQAtAAAAAAAAAAAAD/AAAAAAAAAAAAAAAA"); //开启视频流的启动命令
const eitwo = base64ToBinary("BAIAAABHVFJD"); //开启设备信息的命令
let isshow = ref(true);
let playTimer = ref([{}, {}, {}, {}, {}, {}, {}, {}]); // 播放定时器
let isdown = ref(false);
const videoElement = ref({});
let deviceInformation = ref([]);
//当前弹窗类型
let dialogTitle = ref('');
//评论文本内容
let textContent = ref(['', '', '', '', '', '', '', '']);
let textContentArr = ref([[], [], [], [], [], [], [], [], []]);
//主播id内容
let hostIdContent = ref(['', '', '', '', '', '', '', '']);
let hostIdContentArr = ref([[], [], [], [], [], [], [], [], []]);
//私信文本内容
let textContentpri = ref(['', '', '', '', '', '', '', '']);
let textContentpriArr = ref([[], [], [], [], [], [], [], [], []]);
//保存聊天内容
let chatList = ref([]);
//传入弹窗的聊天内容
let chatContent = ref({
left: '',
right: ''
});
//选中设备
let selectedDevice = ref(999);
//ws列表
let wslist = [];
// 是否停止点赞
let isStopLike = ref([false, false, false, false, false, false, false, false]);
//播放器列表
let instanceList = ref([{}, {}, {}, {}, {}, {}, {}, {}]);
//是否是在关注主播
let runType = ref(['', '', '', '', '', '', '', '']);
//屏幕尺寸系数
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 }]);
//是否是发送的内容
let isSend = ref(false)
//adb任务队列
const taskQueues = new Map(); // 每个设备一个队列
//弹窗是否显示
let showDialog = ref(false);
//监听消息定时器
let isShowMes = ref();
//给ws-scrcpy发送的数据格式
const mouseData = {
type: 2,
action: 0,
pointerId: 0,
position: {
point: { x: 0, y: 0 },
screenSize: { width: 320, height: 720 },
},
pressure: 1,
buttons: 1,
};
//打开聊天窗口的状态
let openShowChat = ref(false);
let istranslate = ref(false); //是否是翻译本页
let phoneXYinfo = ref(getphoneXYinfo() == null ? [{}, {}, {}, {}, {}, {}, {}, {}] : getphoneXYinfo());
console.log('phoneXYinfo.value', phoneXYinfo.value)
const wsCache = new Map();
//``````````````````````````````````````````````````````````````````````````````````
// 初始化 手机显示WebSocket 和视频流
const initVideoStream = (udid, index) => {
//``````````````````````````````````````````````````````````````````````````````````
// 1. 检查缓存中是否已有实例
if (wsCache.has(udid)) {
const cachedWs = wsCache.get(udid);
if (cachedWs.readyState === WebSocket.OPEN) {
return cachedWs;
}
// 如果连接已关闭,清除缓存并重新创建
wsCache.delete(udid);
}
// 2. 创建专用实例容器
instanceList.value[index] = {
wsVideo: null,
converter: null,
timer: null
};
//``````````````````````````````````````````````````````````````````````````````````
if (!videoElement.value) return;
// 1. 创建 h264-converter 实例
instanceList.value[index].converter = new VideoConverter(videoElement.value[udid], 60, 1);
// instanceList.value[index].converter.play();
// 2. 连接 WebSocket
wslist[index] = new WebSocket(
`ws://127.0.0.1:8000/?action=proxy-adb&remote=tcp%3A8886&udid=${udid}`
);
wslist[index].binaryType = "arraybuffer";
wslist[index].onopen = () => {
console.log("手机显示ws已开启");
wsActions = createWsActions(wslist, isStopLike);
// 发送 开启 视频流数据
setTimeout(() => {
wslist[index].send(openStr);
}, 300);
playTimer.value[index] = setTimeout(() => {
instanceList.value[index].converter.play();
}, 3000);
//``````````````````````````````````````````````````````````````````````````````````
wsCache.set(udid, instanceList.value[index]);
//``````````````````````````````````````````````````````````````````````````````````
};
const magicSize = stringToUtf8ByteArray('scrcpy_message');
// 3. 处理接收到的二进制数据
wslist[index].onmessage = (event) => {
const data = new Uint8Array(event.data);
//判断返回的如果是字符串为自定义返回
if (typeof event.data == 'string') {
if (isStopLike.value[index]) {
createTaskQueue(index).clear();//清除队伍中的任务
return;
}
const resData = JSON.parse(event.data)
//成功处理
console.log('自定义返回', resData)
if (resData.status === 'success') {
//触发长按该位置
if (resData.type == 'clickCopy') {
console.log('长按', resData.x * iponeCoefficient.value[index].width, resData.y * iponeCoefficient.value[index].height, index)
clickxy(resData.x * iponeCoefficient.value[index].width, resData.y * iponeCoefficient.value[index].height, index, 9) //index为9的时候长按
setTimeout(() => {
wsActions.clickCopyText(resData.udid, index)
}, 1500);
} else if (resData.type == 'getmesNum') {
if (resData.message == 0) {
console.log('没有消息')
} else if (resData.message == 1) {
console.log('有消息')
} else if (resData.message == '点击成功') {
console.log('双击', iponeCoefficient.value[index].width, iponeCoefficient.value[index].height)
setTimeout(() => {
clickxy(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) //index为9的时候长按
}, 100)
wsActions.clickMesage(deviceInformation.value[index].udid, index) //点击消息进入对话框
}, 1500)
}
} else if (resData.type == 'clickMesage') {
wsActions.clickCopyList(deviceInformation.value[index].udid, index)
} else if (resData.type == 'isVideoAndLive') {
console.log(resData.message)
} else if (resData.type == 'clickCopyList') { //获取到的消息列表
//打印所有信息
console.log('消息列表', resData.message)
chatList.value = resData.message
getTranslation(chatList.value)
const mesBox = resData.message[resData.message.length - 1]
//打印最新一条信息
console.log('最新消息', mesBox)
console.log("翻译", istranslate.value)
if (istranslate.value == false) {
console.log("执行ai")
chat({ msg: mesBox.text }).then(res => {
console.log("ai返回", res)
textContentpri.value[index] = res
PrivatetexToPrivatePush(deviceInformation.value[index].udid, index)
})
} else {
console.log("翻译本页")
istranslate.value = false
}
} else if (resData.action == 'getSize') {
console.log(iponeCoefficient.value, '手机尺寸宽度:', resData.width, '高度:', resData.height);
iponeCoefficient.value[index].width = 320 / resData.width
iponeCoefficient.value[index].height = 720 / resData.height
console.log('尺寸系数', iponeCoefficient.value[index])
} else {
console.log(resData.type, '坐标返回x:', resData.x, 'y:', resData.y);
// clickxy(resData.x * 0.3, resData.y * 0.3, index)
}
phoneXYinfo.value[index].id = resData.udid
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') {
wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
}
} else if (resData.type == 'Comment') {//打开评论
phoneXYinfo.value[index].Comment = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
} else if (resData.type == 'Comtext') {//评论输入
phoneXYinfo.value[index].Comtext = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
// setTimeout(() => {
// setComText(index)//粘贴内容
// }, 1000)
} else if (resData.type == 'ComPush') {//评论发送
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') {
setTimeout(() => {
Back('', index)
}, 1000)
} else {
setTimeout(() => {
wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
setTimeout(() => {
console.log('观看视频中')
randomSeeVideo(deviceInformation.value[index].udid, index) //50秒后继续循环任务
}, 1000);
}, 1000)
}
}, 800)
} else if (resData.type == 'tomy') {//打开主页
phoneXYinfo.value[index].tomy = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
} else if (resData.type == 'Attention') {//关注、打开私信
phoneXYinfo.value[index].Attention = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
// LikesToCommentToComPush(deviceInformation.value[index].udid, index) //是否继续循环任务
} else if (resData.type == 'return') {//私信评论
phoneXYinfo.value[index].return = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
// wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
// setTimeout(() => {
// LikesToCommentToComPush(deviceInformation.value[index].udid, index)
// }, 1000);
} else if (resData.type == 'addHost') {//添加关注
phoneXYinfo.value[index].addHost = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
setTimeout(() => {
wsActions.isHost(deviceInformation.value[index].udid, index)//检测
}, 1000);
} else if (resData.type == 'Privatetex') {//私信评论
phoneXYinfo.value[index].Privatetex = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
} else if (resData.type == 'PrivatePush') {//私信发送
phoneXYinfo.value[index].PrivatePush = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
//如果是在关注主播的任务中
if (runType.value[index] == 'follow') {
runType.value[index] = ''
}
setTimeout(() => {
Back('', index);
setTimeout(() => {
Back('', index);
if (runType.value[index] == 'listen') {
} else if (runType.value[index] == 'like' || runType.value[index] == 'follow') {
LikesToLikesToLikes(deviceInformation.value[index].udid, index, 2)
} else {
}
}, 1000);
}, 1000);
} else if (resData.type == 'clickCopy') {//点击复制
phoneXYinfo.value[index].clickCopy = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
} else if (resData.type == 'hostVideo') {//点击复制
phoneXYinfo.value[index].hostVideo = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
} else if (resData.type == 'isHost') {//视频关注主播
phoneXYinfo.value[index].isHost = { x: resData.x * iponeCoefficient.value[index].width, y: resData.y * iponeCoefficient.value[index].height }
if (resData.message == 0) {
console.log('无关注', index)
Back(deviceInformation.value[index].udid, index)
setTimeout(() => {
console.log('观看视频中', index)
randomSeeVideo(deviceInformation.value[index].udid, index) //30-50秒后继续循环任务
}, 1000);
} else if (resData.message == 1) {
console.log('有关注', index)
const randomNum = Math.random(); // 生成一个0到1之间的随机数
if (randomNum < 0.5) {
console.log('进行点赞评论', index)
LikesToCommentToComPush(deviceInformation.value[index].udid, index)
} else {
console.log('下一个', index)
wsActions.slideDown(deviceInformation.value[index].udid, index)//是否继续下一个视频
setTimeout(() => {
console.log('观看视频中', index)
randomSeeVideo(deviceInformation.value[index].udid, index) //30-50秒后继续循环任务
}, 1000);
}
}
}
setphoneXYinfo(phoneXYinfo.value)
if (resData.type != 'isHost') {
if (resData.type == 'hostVideo' || resData.type == 'Likes') {
setTimeout(() => {
createTaskQueue(index).next(); // 继续队列中下一个任务
}, 5000)
} else {
createTaskQueue(index).next(); // 继续队列中下一个任务
}
}
} else {
// --------------------------------------------------------------------------报错处理
// console.error(resData.type, resData)
//如果该视频无法被评论,返回刷下一条视频
if (resData.type == 'Comtext') {
if (runType.value[index] == 'follow') {
createTaskQueue(index).clear();//清除队伍中的任务
Back('', index)
setTimeout(() => {
Back('', index)
setTimeout(() => {
Back('', index)
LikesToLikesToLikes(deviceInformation.value[index].udid, index, 2)
}, 1000)
}, 1000)
} else {
createTaskQueue(index).clear();//清除队伍中的任务
Back('', index)
setTimeout(() => {
Back('', index)
setTimeout(() => {
wsActions.isHost(deviceInformation.value[index].udid, index)
}, 1000)
}, 1000)
}
//如果该视频无法被私信,返回刷下一条视频
} else if (resData.type == 'Privatetex') {
createTaskQueue(index).clear();//清除队伍中的任务
Back('', index)
setTimeout(() => {
Back('', index)
LikesToLikesToLikes(deviceInformation.value[index].udid, index, 2)
}, 1000)
} else if (resData.type == 'hostVideo') {
createTaskQueue(index).clear();//清除队伍中的任务
Back('', index)
setTimeout(() => {
LikesToLikesToLikes(deviceInformation.value[index].udid, index, 2)
}, 1000)
} else if (resData.type == 'getmesNum' || resData.type == 'clickMesage') {
} else if (resData.type == 'clickCopyList') {
//如果无法获取到聊天记录,返回继续检测
Back('', index)
} else {
console.error(resData.message); // 错误处理
ElMessage.error(resData.message);
createTaskQueue(index).clear();//清除队伍中的任务
}
// createTaskQueue(index).next(); // 继续队列中下一个任务
}
}
//返回粘贴板内容
if (startsWithHeader(magicSize, data)) {
if (!isSend.value) {
const buffer = trimLongArray(data, magicSize);
const paste = bufferToString(buffer);
console.log('获取粘贴板内容', paste)
}
}
//视频流处理
if (instanceList.value[index].converter) {
if (isshow.value) {
instanceList.value[index].converter.appendRawData(data);
}
}
};
// 4. 错误处理
wslist[index].onerror = (error) => {
wsCache.delete(udid); // 错误时清理缓存
};
//``````````````````````````````````````````````````````````````````````````````````
wslist[index].onclose = (event) => {
wsCache.delete(udid)// 自动清理缓存
clearInterval(instanceList.value[index].timer); // 清理定时器// 移除缓存
};
//``````````````````````````````````````````````````````````````````````````````````
};
// 配置参数
let canvasRef = ref({});
// 初始化画布
const initCanvas = (udid) => {
const canvas = canvasRef.value[udid];
const dpr = window.devicePixelRatio || 1;
canvas.style.width = `${phone.value.width * 1.4}px`;
canvas.style.height = `${phone.value.height * 1.4}px`;
canvas.width = phone.value.width * 1.4 * dpr;
canvas.height = phone.value.height * 1.4 * dpr;
const ctx = canvas.getContext("2d");
ctx.scale(dpr, dpr);
// 绘制参考网格(可选)
ctx.strokeStyle = "#ffffff00";
for (let x = 0; x <= phone.value.width; x += 100) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, phone.value.height);
ctx.stroke();
}
};
// 鼠标按下事件处理
const handleCanvasdown = (udid, event, index) => {
const { x, y } = getCanvasCoordinate(event, udid);
console.log("鼠标按下", x, y);
isdown.value = true;
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
// console.log(mouseData);
console.log(index)
setTimeout(() => {
selectedDevice.value = index;
}, 300);
console.log(wslist)
wslist[index].send(toBuffer(mouseData));
};
// 鼠标抬起事件处理
const handleCanvasup = (udid, event, index) => {
const { x, y } = getCanvasCoordinate(event, udid);
// position.endX = floorNum(x)
// position.endY = floorNum(y)
isdown.value = false;
mouseData.action = 1;
mouseData.pressure = 0;
mouseData.buttons = 0;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
// console.log(mouseData);
wslist[index].send(toBuffer(mouseData));
};
// 鼠标移动事件处理
const handleMouseMove = (udid, event, index) => {
if (isdown.value) {
const { x, y } = getCanvasCoordinate(event, udid);
// position.startX = floorNum(x)
// position.startY = floorNum(y)
mouseData.action = 2;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
// console.log(mouseData);
wslist[index].send(toBuffer(mouseData));
}
};
// 坐标计算
const getCanvasCoordinate = (event, udid) => {
const canvas = canvasRef.value[udid];
const rect = canvas.getBoundingClientRect();
const dpr = window.devicePixelRatio || 1;
return {
x: (event.clientX - rect.left) / 0.9138 * dpr,
y: (event.clientY - rect.top) / 0.9138 * dpr,
};
};
//返回上一层
const Back = (udid, index) => {
wslist[index].send(toBufferBtn({ "type": 0, "action": 0, "keycode": 4, "metaState": 0, "repeat": 0 }));
wslist[index].send(toBufferBtn({ "type": 0, "action": 1, "keycode": 4, "metaState": 0, "repeat": 0 }));
}
//返回首页
const Home = (udid, index) => {
wslist[index].send(toBufferBtn({ "type": 0, "action": 0, "keycode": 3, "metaState": 0, "repeat": 0 }));
wslist[index].send(toBufferBtn({ "type": 0, "action": 1, "keycode": 3, "metaState": 0, "repeat": 0 }));
}
//任务视图
const Overview = (udid, index) => {
wslist[index].send(toBufferBtn({ "type": 0, "action": 0, "keycode": 187, "metaState": 0, "repeat": 0 }));
wslist[index].send(toBufferBtn({ "type": 0, "action": 1, "keycode": 187, "metaState": 0, "repeat": 0 }));
}
//回车 index手机下标 state up按下 down抬起 keycode 键
const key = (index, state, keycode) => {
// console.log("退格", index)
if (index === 999) {
return
} else {
if (state == 'up') {
wslist[index].send(toBufferBtn({ "type": 0, "action": 1, "keycode": keycode, "metaState": 0, "repeat": 0 }));
} else if (state == 'down') {
wslist[index].send(toBufferBtn({ "type": 0, "action": 0, "keycode": keycode, "metaState": 0, "repeat": 0 }));
}
}
}
const handleVisibilityChange = () => {
if (document.visibilityState === "hidden") {
if (playTimer.value) {
console.log("清除定时器");
playTimer.value.forEach(Timer => {
clearInterval(Timer);
});
playTimer.value = [{}, {}, {}, {}, {}, {}, {}, {}];
}
console.log("页面被隐藏");
isshow.value = false;
// 页面被隐藏时执行的逻辑
} else if (document.visibilityState === "visible") {
console.log("页面变为可见");
setTimeout(() => {
isshow.value = true;
// ObtainDeviceInformation();
}, 500);
}
};
onMounted(() => {
document.addEventListener("visibilitychange", handleVisibilityChange);
ObtainDeviceInformation();
window.addEventListener('keydown', (e) => {
console.log('触发按键了 键盘事件有效', e)
if (e.key == 'Backspace') {
key(selectedDevice.value, 'down', 67)
}
})
window.addEventListener('keyup', (e) => {
// console.log('触发按键了 键盘事件有效抬起', e.keyCode, e.key)
if (e.key == 'Backspace') {
key(selectedDevice.value, 'up', 67)
}
})
const loading = ElLoading.service({
lock: true,
text: '初始化中...',
background: 'rgba(0, 0, 0, 0.7)',
})
setTimeout(() => {
loading.close()
}, 2000)
});
onBeforeUnmount(() => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
});
// 组件卸载时清理
onUnmounted(() => {
console.log("卸载组件");
cloesMonitor(); //关闭检测消息
});
//获取设备信息
const ObtainDeviceInformation = () => {
// 2. 连接 WebSocket
const ws = new WebSocket("ws://127.0.0.1:8000/?action=multiplex");
ws.binaryType = "arraybuffer";
ws.onopen = () => {
ws.send(eitwo);
};
// 3. 处理接收到的二进制数据
ws.onmessage = (event) => {
const data = JSON.parse(new TextDecoder('utf-8').decode(event.data).replace(/[^\x20-\x7F]/g, ''));
try {
console.log('数组', data)
if (data.type == "devicelist") {
deviceInformation.value = [];
const filteredList = data.data.list.filter(item => item.state === 'device');
//检测到设备列表时,渲染所有设备
filteredList.forEach((item, index) => {
console.log(item);
if (item.state === "device") {
deviceInformation.value.push(item);
console.log("deviceInformation", deviceInformation.value);
setTimeout(() => {
initVideoStream(item.udid, index);
initCanvas(item.udid);
setTimeout(() => {
wsActions.getSize(item.udid, index)
}, 2000)
}, 300);
}
})
} else if (data.type == "device") {
if (data.data.device.state === "offline") {
//监听设备信息,出现离线设备,则删除设备信息
deviceInformation.value.forEach((item, index) => {
if (item.udid === data.data.device.udid) {
deviceInformation.value.splice(index, 1);
if (index < wslist.length - 1) {
deviceInformation.value.forEach((item, index1) => {
//关闭websocket连接
wslist.forEach((item, index) => {
item.close();
})
//重新连接websocket
new Promise((resolve, reject) => {
setTimeout(() => {
try {
initVideoStream(item.udid, index1);
initCanvas(item.udid);
} catch (error) {
reject(error);
}
}, 300);
});
})
}
console.log("deviceInformation", deviceInformation.value);
}
})
} else if (data.data.device.state === "device") {
let isrepeat = false;
//监听设备信息,出现新设备,则添加设备信息
deviceInformation.value.forEach((item, index) => {
if (item.udid == data.data.device.udid) {
isrepeat = true;
}
})
if (!isrepeat) {
deviceInformation.value.push(data.data.device);
// setTimeout(() => {
// initVideoStream(data.data.device.udid, deviceInformation.value.length - 1);
// initCanvas(data.data.device.udid);
// }, 300);
new Promise((resolve, reject) => {
setTimeout(() => {
try {
initVideoStream(data.data.device.udid, deviceInformation.value.length - 1);
initCanvas(data.data.device.udid);
} catch (error) {
// reject(error);
}
}, 1000);
});
}
};
}
} catch (e) {
console.error(e);
}
};
}
//喜欢-输入评论
async function LikesToCommentToComPush(udid, index) {
await sendWsTask(index, { udid, action: 'click', type: 'Likes', index, resourceId: 'com.zhiliaoapp.musically:id/dy6' });
await sendWsTask(index, { udid, action: 'click', type: 'Comment', index, resourceId: 'com.zhiliaoapp.musically:id/cvd' });
await sendWsTask(index, { udid, action: 'click', type: 'Comtext', index, resourceId: 'com.zhiliaoapp.musically:id/cs0' });
await sendWsTask(index, { udid, action: 'click', type: 'ComPush', index, resourceId: 'com.zhiliaoapp.musically:id/bqg' });
}
//点赞主页4个作品+评论最后一个作品并返回
async function LikesToLikesToLikes(udid, index, type) {
isStopLike.value[index] = false;
runType.value[index] = 'follow';
if (type == 2) {
await sendWsTask(index, { udid, action: 'click', type: 'searchTxt', index, resourceId: 'com.zhiliaoapp.musically:id/f0l' });
await sendWsTask(index, { udid, action: 'click', type: 'close', index, resourceId: 'com.zhiliaoapp.musically:id/blw' });
} else if (type == 1) {
await sendWsTask(index, { udid, action: 'click', type: 'search', index, resourceId: 'com.zhiliaoapp.musically:id/gtz' });
}
await sendWsTask(index, { udid, action: 'click', type: 'searchHost', index, resourceId: 'com.zhiliaoapp.musically:id/t6f' });
await sendWsTask(index, { udid, action: 'click', type: 'toHost', index, resourceId: 'com.zhiliaoapp.musically:id/iso' });
await sendWsTask(index, { udid, action: 'click', type: 'hostVideo', index, resourceId: 'com.zhiliaoapp.musically:id/u3o', num: 0 });
await sendWsTask(index, { udid, action: 'click', type: 'Likes', index, resourceId: 'com.zhiliaoapp.musically:id/dy6' });
await sendWsTask(index, { udid, action: 'click', type: 'Likes', index, resourceId: 'com.zhiliaoapp.musically:id/dy6' });
await sendWsTask(index, { udid, action: 'click', type: 'Likes', index, resourceId: 'com.zhiliaoapp.musically:id/dy6' });
await sendWsTask(index, { udid, action: 'click', type: 'Likes', index, resourceId: 'com.zhiliaoapp.musically:id/dy6' });
await sendWsTask(index, { udid, action: 'click', type: 'Comment', index, resourceId: 'com.zhiliaoapp.musically:id/cvd' });
await sendWsTask(index, { udid, action: 'click', type: 'Comtext', index, resourceId: 'com.zhiliaoapp.musically:id/cs0' });
await sendWsTask(index, { udid, action: 'click', type: 'ComPush', index, resourceId: 'com.zhiliaoapp.musically:id/bqg' });
await sendWsTask(index, { udid, action: 'click', type: 'Attention', index, resourceId: 'com.zhiliaoapp.musically:id/dhx' });
await sendWsTask(index, { udid, action: 'click', type: 'Attention', index, resourceId: 'com.zhiliaoapp.musically:id/dhx' });
await sendWsTask(index, { udid, action: 'click', type: 'Privatetex', index, resourceId: 'com.zhiliaoapp.musically:id/hob' });
await sendWsTask(index, { udid, action: 'click', type: 'PrivatePush', index, resourceId: 'com.zhiliaoapp.musically:id/hog' });
// await sendWsTask(index, { udid, action: 'click', type: 'fanhui', index, resourceId: 'com.zhiliaoapp.musically:id/awi' });
}
//私信
async function PrivatetexToPrivatePush(udid, index) {
await sendWsTask(index, { udid, action: 'click', type: 'Privatetex', index, resourceId: 'com.zhiliaoapp.musically:id/hob' });
await sendWsTask(index, { udid, action: 'click', type: 'PrivatePush', index, resourceId: 'com.zhiliaoapp.musically:id/hog' });
}
//发送评论字符到手机方法
function setComText(index) {
isSend.value = true;
setTimeout(() => {
isSend.value = false;
}, 300);
console.log('发送评论内容', index, textContent.value[index])
wslist[index].send(setClipboard(textContent.value[index]));
textContent.value[index] = textContentArr.value[index][getRandomNumber(textContentArr.value[index].length - 1)];
}
//发送主播ID字符到手机方法
function setHostId(index) {
isSend.value = true;
setTimeout(() => {
isSend.value = false;
}, 300);
console.log('发送主播id内容', index, hostIdContent.value[index])
wslist[index].send(setClipboard(hostIdContent.value[index])); //发送内容
//获取当前主播ID的下标
const indexBom = hostIdContentArr.value[index].indexOf(hostIdContent.value[index]) + 1;
console.log(hostIdContentArr.value[index].indexOf(hostIdContent.value[index]) + 1, '当前主播下标');
console.log(hostIdContentArr.value[index], '主播列表');
//如果是最后一个ID 则重置
if (indexBom == hostIdContentArr.value[index].length) {
// isStopLike.value[index] = true;
hostIdContent.value[index] = ''
return
}
hostIdContent.value[index] = hostIdContentArr.value[index][indexBom];
console.log(hostIdContent.value[index], '下次搜索')
}
//发送私信字符到手机方法
function setPrivateText(index) {
isSend.value = true;
setTimeout(() => {
isSend.value = false;
}, 300);
console.log('发送私信内容', index, textContentpri.value[index])
wslist[index].send(setClipboard(textContentpri.value[index]));
textContentpri.value[index] = textContentpriArr.value[index][getRandomNumber(textContentpriArr.value[index].length - 1)];
}
//获取手机粘贴板方法
function getText(index) {
wslist[index].send(getClipboard());
}
function getComArr(index, type) {
if (type == '评论') {
ElMessageBox.alert(textContentArr.value[index], `当前${type}内容`, {
confirmButtonText: 'OK',
})
} else {
ElMessageBox.alert(textContentpriArr.value[index], `当前${type}内容`, {
confirmButtonText: 'OK',
})
}
}
//传入xy坐标 进行点击
function clickxy(x, y, index, type) {
console.log('clickxy方法', x, y)
if (type == 3) { //关注/私信 后的返回和下滑
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
wslist[index].send(toBuffer(mouseData));
setTimeout(() => {
mouseData.action = 1;
wslist[index].send(toBuffer(mouseData));
}, 100)
//返回和下滑
setTimeout(() => {
Back('', index)
setTimeout(() => {
wsActions.slideDown(phoneXYinfo.value[index].id, index)
setTimeout(() => {
start(phoneXYinfo.value[index].id, index)
}, 300)
}, 300)
}, 300)
} else if (type == 2) { //评论过后的返回和右滑
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
wslist[index].send(toBuffer(mouseData));
setTimeout(() => {
mouseData.action = 1;
wslist[index].send(toBuffer(mouseData));
}, 100)
//返回和右滑
setTimeout(() => {
Back('', index)
setTimeout(() => {
wsActions.slideRight(phoneXYinfo.value[index].id, index)
}, 300)
}, 300)
} else if (type == 1) {//评论框点击后的发送内容
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
wslist[index].send(toBuffer(mouseData));
setTimeout(() => {
mouseData.action = 1;
wslist[index].send(toBuffer(mouseData));
}, 100)
//发送内容
setTimeout(() => {
console.log('点击了')
setComText(index)
}, 300)
} else if (type == 9) { //长按
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
wslist[index].send(toBuffer(mouseData));
console.log('鼠标按下')
setTimeout(() => {
mouseData.action = 1;
wslist[index].send(toBuffer(mouseData));
console.log('抬起按下')
}, 1500)
} else {
mouseData.action = 0;
mouseData.pressure = 1;
mouseData.buttons = 1;
mouseData.position.point.x = x;
mouseData.position.point.y = y;
wslist[index].send(toBuffer(mouseData));
setTimeout(() => {
mouseData.action = 1;
wslist[index].send(toBuffer(mouseData));
}, 100)
}
}
//创建任务实例
function createTaskQueue(index) {
if (!taskQueues.has(index)) {
taskQueues.set(index, []);
}
return {
enqueue(task) {
taskQueues.get(index).push(task);
if (taskQueues.get(index).length === 1) {
task(); // 执行第一个任务
}
},
next() {
const queue = taskQueues.get(index);
queue.shift(); // 移除已完成任务
if (queue.length > 0) {
queue[0](); // 执行下一个任务
}
},
clear() {
taskQueues.set(index, []); // 清除所有任务
}
};
}
//发送检查该手机的xy坐标任务
function sendWsTask(index, data) {
console.log('发送任务', data.type);
return new Promise((resolve) => {
const queue = createTaskQueue(index);
const task = () => {
//发送评论的文本粘贴事件
if (data.type == 'Likes') {
clickxy(160, 360, index)
}
if (data.type == 'isHost') {
// clickxy(160, 360, index)
}
if (data.type == 'Comment') {
if (runType.value[index] == 'follow') {
clickxy(160, 360, index)
}
}
if (data.type == 'ComPush') {
setTimeout(() => {
setComText(index)//粘贴内容
}, 500)
}
if (data.type == 'searchHost') {
setTimeout(() => {
setHostId(index)//粘贴内容
}, 500)
}
//发送私信的文本粘贴事件
if (data.type == 'PrivatePush') {
setPrivateText(index)
}
//关注前的返回和右滑
if (data.type == 'Attention') {
// setTimeout(() => {
// Back('', index)
// setTimeout(() => {
// wsActions.slideRight(data.udid, index)
// }, 500);
// }, 500);
}
//发送关注之前的返回
if (data.type == 'addHost') {
// setTimeout(() => {
// Back('', index)
// setTimeout(() => {
// clickxy(160, 360, index)
// wsActions.isHost(data.udid, index)
// }, 1000);
// }, 500);
}
//发送任务
console.log('发送任务', data);
if (data.type == 'Attention') {
setTimeout(() => {
wslist[index].send(JSON.stringify(data));
resolve();
}, 1000)
} else {
wslist[index].send(JSON.stringify(data));
resolve();
}
// 表示当前任务“已发出”,但不是“已完成”
// 实际完成由 onmessage 中的 success 决定并继续执行队列
};
queue.enqueue(task);
});
}
// 生成start秒到end秒的随机延迟
function randomDelay(start, end) {
return Math.floor(Math.random() * end * 1000) + start * 1000;
}
//一个0到n之间的随机整数
function getRandomNumber(n) {
return Math.floor(Math.random() * (n + 1));
}
//延迟30-50秒后检测关注
function randomSeeVideo(udid, index) {
const delay = Math.floor(Math.random() * (50 - 30 + 1) + 30) * 1000;
setTimeout(() => {
console.log('观看结束', index);
wsActions.isHost(udid, index)//检测
}, delay);
}
//选中样式
function getVideoStyle(index) {
const isSelected = selectedDevice.value === index;
const baseWidth = phone.value.width;
const baseHeight = phone.value.height;
// console.log(isSelected, '是否相等')
return {
width: isSelected ? baseWidth * 1.4 + 'px' : baseWidth + 'px',
height: isSelected ? baseHeight * 1.4 + 'px' : baseHeight + 'px',
border: isSelected ? '2px solid blue' : '1px solid blue',
position: isSelected ? 'absolute' : 'relative',
top: isSelected ? '0' : 'unset',
left: isSelected ? '0' : 'unset',
zIndex: isSelected ? 1000 : 1,
pointerEvents: isSelected ? 'none' : 'auto',
};
}
function stop(udid, index) {
// actions[index] = [];
createTaskQueue(index).clear();//清除队伍中的任务
cloesMonitor();
isStopLike.value.forEach((item, i) => {
isStopLike.value[i] = true;
runType.value[index] = ''
})
console.log('停止', isStopLike.value);
}
//刷新页面方法
function reloadfun() {
reload()
}
// //返回次数
// function repeatBack(index, times, delay = 1000) {
// if (typeof times !== 'number' || times <= 0) return;
// for (let i = 1; i <= times; i++) {
// setTimeout(() => {
// Back('', index);
// }, i * delay);
// }
// }
function openTk() {
deviceInformation.value.forEach((device, index) => {
wsActions.open(device.udid, index)
})
}
//监听所有手机是否有消息
function openMonitor() {
deviceInformation.value.forEach((device, index) => {
wsActions.getmesNum(device.udid, index)
isStopLike.value[index] = false;
runType.value[index] = 'listen'
})
isShowMes.value = setInterval(() => {
deviceInformation.value.forEach((device, index) => {
wsActions.getmesNum(device.udid, index)
isStopLike.value[index] = false;
})
}, 10000)
}
//关闭监听
function cloesMonitor() {
deviceInformation.value.forEach((device, index) => {
runType.value[index] = ''
})
clearInterval(isShowMes.value)
isShowMes.value = ''
}
//一键养号
function parentNum() {
deviceInformation.value.forEach((device, index) => {
isStopLike.value[index] = false;
runType.value[index] = 'like'
wsActions.isHost(device.udid, index)
})
}
//取消弹窗
function onDialogCancel() {
}
//确认多行文本框内容
function onDialogConfirm(result, type, index) {
console.log(result, type, index);
if (type == '评论') {
//index ==999 表示全部
if (index == 999) {
textContentArr.value.forEach((item, indexA) => {
textContentArr.value[indexA] = result;
textContent.value[indexA] = result[getRandomNumber(result.length - 1)];
})
parentNum()
} else if (index == 998) {
textContentArr.value.forEach((item, indexA) => {
textContentArr.value[indexA] = result;
textContent.value[indexA] = result[getRandomNumber(result.length - 1)];
})
//打开私信弹窗
selectedDevice.value = 999;
dialogTitle.value = '私信';
setTimeout(() => {
showDialog.value = true;
}, 600)
} else {
textContentArr.value[index] = result;
textContent.value[index] = result[getRandomNumber(result.length - 1)];
}
} else if (type == '私信') {
//index ==999 表示全部
if (index == 999) {
textContentpriArr.value.forEach((item, indexA) => {
textContentpriArr.value[indexA] = result;
textContentpri.value[indexA] = result[getRandomNumber(result.length - 1)];
})
deviceInformation.value.forEach((device, indexB) => {
LikesToLikesToLikes(device.udid, indexB, 1)
})
} else {
textContentpriArr.value[index] = result;
textContentpri.value[index] = result[getRandomNumber(result.length - 1)];
}
} else if (type == '主播ID') {
//index ==999 表示全部
if (index == 999) {
//分割数组 几台设备 分为几个数组
const hostIdArrList = splitArray(result, deviceInformation.value.length)
deviceInformation.value.forEach((device, indexA) => {
hostIdContentArr.value[indexA] = hostIdArrList[indexA];
hostIdContent.value[indexA] = hostIdContentArr.value[indexA][0];
})
//打开评论弹窗
selectedDevice.value = 998;
dialogTitle.value = '评论';
setTimeout(() => {
showDialog.value = true;
}, 600)
} else {
hostIdContentArr.value[index] = result;
hostIdContent.value[index] = result[0];
deviceInformation.value.forEach((device, indexA) => {
if (index == indexA) {
LikesToLikesToLikes(device.udid, index, 1)
}
})
}
}
}
//分割数组
function splitArray(array, parts) {
if (!Array.isArray(array)) {
console.warn('splitArray: 第一个参数应为数组');
return [];
}
const len = array.length;
const n = parseInt(parts, 10);
if (isNaN(n) || n <= 0) {
console.warn('splitArray: 份数应为大于 0 的整数');
return [];
}
const result = [];
for (let i = 0; i < n; i++) {
// 计算第 i 份的起始和结束索引
const start = Math.floor(i * len / n);
const end = Math.floor((i + 1) * len / n);
result.push(array.slice(start, end));
}
return result;
}
function selectedDeviceFun(index) {
selectedDevice.value = index
// chatContent.value.left = chatList.value[index].leftMsg
// chatContent.value.right = chatList.value[index].rightMsg
// console.log(chatList.value);
// console.log(chatContent.value);
}
function getTranslation(list) {
list.forEach((item, index) => {
translation({ msg: item.text }).then(res => {
console.log(res);
chatList.value[index].text = res
})
})
}
</script>
<style scoped lang="less">
body {
user-select: none;
}
.main {
display: flex;
width: 100vw;
height: 100vh;
background: #222;
}
.left {
background: #191c23;
width: 20vw;
box-sizing: content-box;
}
.content {
width: 50vw;
display: grid;
grid-template-columns: repeat(3, minmax(160px, 320px));
/* 每行 3 个,宽度自适应 */
/* gap: 10px; */
}
.right {
width: 30vw;
background-color: #272727;
}
.video-container {
position: relative;
// padding: 10px;
width: 100%;
width: auto;
/* 取消 100%,避免换行 */
display: inline-block;
display: flex;
transition: all 0.3s ease-in-out;
.video-canvas {
position: absolute;
box-sizing: border-box;
}
.input-info {
color: rgb(255, 255, 255);
background-color: #424242;
position: absolute;
z-index: 10;
}
}
video {
transition: all 0.3s ease-in-out;
/* 关键:让 video 不拦截鼠标事件 */
/* 添加动画 */
}
.top-row {
align-items: flex-start;
/* 上对齐 */
}
.bottom-row {
align-items: flex-end;
/* 下对齐 */
margin-top: auto;
}
video {
/* position: relative; */
width: 100%;
height: 100%;
position: absolute;
z-index: 1;
/* object-fit: contain; */
/* transform: scale(0.27); */
/* 缩小到原始尺寸的50% */
/* transform-origin: top left; */
/* 控制缩放原点 */
}
.canvas {
position: absolute;
top: 0;
left: 0;
z-index: 9;
/* transform: scale(0.27); */
/* 缩小到原始尺寸的50% */
/* transform-origin: top left; */
/* 控制缩放原点 */
}
.open {
background: url(../assets/open.png) no-repeat center center;
background-size: 60% 60%;
}
.Back {
background: url(../assets/Back.png) no-repeat center center;
background-size: 60% 60%;
}
.Home {
background: url(../assets/Home.png) no-repeat center center;
background-size: 60% 60%;
}
.Overview {
background: url(../assets/Overview.png) no-repeat center center;
background-size: 60% 60%;
}
.el-button {
width: 200px;
margin: 20px;
// background-color: darkcyan;
// color: white;
position: relative;
z-index: 999;
}
.center-justify {
display: flex;
justify-content: space-around;
align-items: center;
}
.center-line {
display: flex;
flex-direction: column;
align-items: center;
// justify-content: center;
}
</style>