稳定测试版
This commit is contained in:
@@ -2,8 +2,17 @@
|
||||
<div class="main">
|
||||
<el-scrollbar class="left"> <!-- 左边栏 -->
|
||||
<div style="position: absolute;left: 20px; top: 20px;">
|
||||
<el-button style="background: linear-gradient(90deg, #60a5fa, #34d399); color: azure;"
|
||||
<el-button style="background: linear-gradient(90deg, #60a5fa, #34d399); color: azure; "
|
||||
@click="showMyInfo = true">人设编辑</el-button>
|
||||
|
||||
<!-- <el-button style="background: linear-gradient(90deg, #60a5fa, #34d399); color: azure;" @click="MesNewList.push({
|
||||
sender: 'Alice', // 或 name/user/from
|
||||
device: 'iPhone 14 Pro', // 或 deviceName/udid
|
||||
text: '你好呀~', // 或 content
|
||||
time: '2023-10-01 12:00:00', // 可选;有些是 'time' 会被过滤或 content
|
||||
type: 'msg' // 可选;有些是 'time' 会被过滤
|
||||
})">新增</el-button> -->
|
||||
<!-- <el-button @click="updates([{ id: 10022, aiOperation: 1 }])">更新请求</el-button> -->
|
||||
</div>
|
||||
|
||||
<div class="center-line"> <!-- 左边栏按钮 -->
|
||||
@@ -37,7 +46,7 @@
|
||||
@mousemove.stop="(e) => onCanvasMove(device.deviceId, e, index)" />
|
||||
</div>
|
||||
<div class="input-info" v-show="selectedDevice == index">
|
||||
|
||||
<div class="app-button" @click="restartTikTok({ udid: device.deviceId })">重置tiktok</div>
|
||||
<div class="app-button" @click="getMesList(device.deviceId)">获取当前聊天记录</div>
|
||||
<div class="app-button" @click="stopOne(device.deviceId)">停止任务</div>
|
||||
<div class="app-button" @click="runTask(runType, device.deviceId)">开启</div>
|
||||
@@ -47,13 +56,17 @@
|
||||
</div>
|
||||
<div class="right center-line" @click.self="selectedDevice = 999">
|
||||
<!-- <div style="margin: 30px;"></div> -->
|
||||
|
||||
<ChatDialog :visible="openShowChat" :messages="chatList" />
|
||||
<MessageDialogd :visible="openShowChat" :messages="MesNewList" :sound-src="ding" />
|
||||
</div>
|
||||
<img v-if="isWifi" style="position: absolute; right: 20px; top: 10px; height: 30px;" src="@/assets/wifi.png"></img>
|
||||
<MultiLineInputDialog v-model:visible="showDialog" :initialText='initialTextStr' :title="dialogTitle"
|
||||
:index="selectedDevice" @confirm="onDialogConfirm" @cancel="stopAll" />
|
||||
<HostListManagerDialog v-model:visible="showHostDlg" @save="onHostSaved" @invitType="invitTypeFun" />
|
||||
|
||||
<TranslationDialog v-model="showtransDlg" :type="transDlgType" :translateFn="doTranslate"
|
||||
storage-key-prefix="demo-translation" @confirm="onConfirm" @cancel="stopAll" />
|
||||
</div>
|
||||
<!-- <AgentGuildDialog v-model="showMyInfo" :model="formInit" @save="handleSave" /> -->
|
||||
<AgentGuildDialog v-model="showMyInfo" :model="{
|
||||
@@ -92,12 +105,12 @@
|
||||
<div>总时长</div>
|
||||
<div><b>{{ schedAMin + schedBMin }}</b> 分钟(必须等于 60)</div>
|
||||
|
||||
<!-- <div>换号</div>
|
||||
<div>换号</div>
|
||||
<div style="display:flex; gap:8px; align-items:center;">
|
||||
<el-switch v-model="interruptEnabled" active-text="开启换号" />
|
||||
<el-input-number v-model="interruptEveryMin" :min="1" :max="180" />
|
||||
<span>分钟换一次</span>
|
||||
</div> -->
|
||||
<el-input-number v-model="interruptEveryMin" :min="1" :max="24" />
|
||||
<span>小时换一次</span>
|
||||
</div>
|
||||
<div>联盟号</div>
|
||||
<div style="display:flex; gap:8px; align-items:center;">
|
||||
<el-switch v-model="isAlliance" active-text="联盟号快速私信" />
|
||||
@@ -121,19 +134,21 @@ import {
|
||||
setphoneXYinfo, getphoneXYinfo, getUser,
|
||||
getHostList, setHostList, getContentpriList,
|
||||
setContentpriList, getContentList, setContentList,
|
||||
setsessionId, getsessionId, getContentpriListMultiline
|
||||
setsessionId, getsessionId, getContentListMultiline, getContentpriListMultiline
|
||||
} from '@/stores/storage'
|
||||
import { connectSSE } from '@/utils/sseUtils'
|
||||
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
|
||||
import { chat, translationToChinese, translation } from "@/api/chat";
|
||||
import { chat, translationToChinese, translation, customTranslation } from "@/api/chat";
|
||||
import HostListManagerDialog from '@/components/HostListManagerDialog.vue'
|
||||
import AgentGuildDialog from '@/components/AgentGuildDialog.vue'
|
||||
|
||||
import MultiLineInputDialog from '@/components/MultiLineInputDialog.vue'; // 根据实际路径修改
|
||||
import TranslationDialog from '@/components/translationDialog.vue'; // 根据实际路径修改
|
||||
|
||||
import ChatDialog from '@/components/ChatDialog.vue'
|
||||
import MessageDialogd from '@/components/MessageDialogd.vue'
|
||||
import { pickTikTokBundleId } from '@/utils/arrUtils'
|
||||
import { logout } from '@/api/account';
|
||||
import { logout, updates } from '@/api/account';
|
||||
import {
|
||||
getDeviceList,
|
||||
toHome,
|
||||
@@ -153,7 +168,10 @@ import {
|
||||
aiConfig,
|
||||
selectLast,
|
||||
updatelast,
|
||||
stopAllTask
|
||||
changeAccount,
|
||||
stopAllTask,
|
||||
anchorList,
|
||||
restartTikTok
|
||||
} from '@/api/ios';
|
||||
import ding from '@/assets/mes.wav'
|
||||
import { set } from "lodash";
|
||||
@@ -163,6 +181,10 @@ const openShowChat = ref(true)
|
||||
const showHostDlg = ref(false)
|
||||
//ai人设弹框
|
||||
const showMyInfo = ref(false)
|
||||
//翻译弹框
|
||||
const showtransDlg = ref(false)
|
||||
let transDlgType = ref('')
|
||||
|
||||
// 假设这是你已有的数据
|
||||
const borkerConfig = reactive({
|
||||
agentName: '',
|
||||
@@ -171,12 +193,15 @@ const borkerConfig = reactive({
|
||||
contact: ''
|
||||
})
|
||||
|
||||
//评论 自动化
|
||||
let common = ref(true);
|
||||
let initialTextStr = ref('') // 初始文本字符串
|
||||
// 批次缓冲(仅用于当前“波”)
|
||||
let batch = []; // [{ country, text }]
|
||||
let flushTimer = null;
|
||||
|
||||
let hostList = []
|
||||
let hostList = [] // 主播列表
|
||||
let comonList = [] //评论列表
|
||||
//查询列表轮询
|
||||
let getListtimer = null;
|
||||
let userdata = getUser();
|
||||
@@ -288,9 +313,15 @@ const buttons = [
|
||||
};
|
||||
|
||||
if (isLocked('like')) return
|
||||
// runType.value = 'like'
|
||||
// deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId }))
|
||||
dialogTitle.value = '视频评论';
|
||||
setTimeout(() => {
|
||||
showDialog.value = true;
|
||||
|
||||
initialTextStr.value = getContentListMultiline();
|
||||
}, 500)
|
||||
|
||||
runType.value = 'like'
|
||||
deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId }))
|
||||
},
|
||||
show: () => true,
|
||||
img: {
|
||||
@@ -314,24 +345,31 @@ const buttons = [
|
||||
{
|
||||
label: '监测消息',
|
||||
onClick: () => {
|
||||
if (runType.value == 'lisen') {
|
||||
if (runType.value == 'listen') {
|
||||
deviceInformation.value.forEach((item) => {
|
||||
stopScript({ udid: item.deviceId })
|
||||
})
|
||||
runType.value = ''
|
||||
return
|
||||
};
|
||||
if (isLocked('lisen')) return
|
||||
|
||||
runType.value = 'lisen'
|
||||
if (isLocked('listen')) return
|
||||
//如果传评论就注释一下两行代码,解开后面代码
|
||||
runType.value = 'listen'
|
||||
deviceInformation.value.forEach((item) => monitorMessages({ udid: item.deviceId }))
|
||||
// dialogTitle.value = '评论(无消息将刷视频)';
|
||||
// setTimeout(() => {
|
||||
// showDialog.value = true;
|
||||
|
||||
// initialTextStr.value = getContentListMultiline();
|
||||
// }, 500)
|
||||
|
||||
},
|
||||
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: () => ctrlStyle('lisen')
|
||||
style: () => ctrlStyle('listen')
|
||||
|
||||
},
|
||||
// {
|
||||
@@ -371,9 +409,9 @@ const isAlliance = ref(false)
|
||||
// 是否开启
|
||||
const interruptEnabled = ref(false)
|
||||
// 每隔多少分钟打断一次(可做弹窗配置)
|
||||
const interruptEveryMin = ref(15)
|
||||
const interruptEveryMin = ref(2)
|
||||
// 打断器最大重试次数 & 每次超时(按需调)
|
||||
const interruptMaxRetries = 3
|
||||
const interruptMaxRetries = 1
|
||||
const interruptCallTimeoutMs = 120_000
|
||||
|
||||
// 运行态
|
||||
@@ -673,44 +711,76 @@ const selectDevice = (index) => {
|
||||
const dragState = ref({}) // 以 index 作为 key 保存 {ox, oy, t}
|
||||
|
||||
const onCanvasDown = (udid, e, index) => {
|
||||
// 记录起点(Canvas 内的 offset)
|
||||
dragState.value[index] = { ox: e.offsetX, oy: e.offsetY, t: Date.now(), udid }
|
||||
// 记录起点(Canvas 内 offset)和时间
|
||||
const startDev = mapToDeviceXY(index, e.offsetX, e.offsetY) // 也记录“设备坐标”起点,便于直接打印
|
||||
dragState.value[index] = {
|
||||
ox: e.offsetX,
|
||||
oy: e.offsetY,
|
||||
t: Date.now(),
|
||||
udid,
|
||||
startDevXY: startDev,
|
||||
startOffsetXY: { x: e.offsetX, y: e.offsetY }
|
||||
}
|
||||
}
|
||||
|
||||
const onCanvasMove = (udid, e, index) => {
|
||||
// 如需在 overlay 上画指示、十字线等,可在这里使用 e.offsetX/e.offsetY
|
||||
// 若要实时观察滑动轨迹(可选)
|
||||
const st = dragState.value[index]
|
||||
if (!st) return
|
||||
const curDev = mapToDeviceXY(index, e.offsetX, e.offsetY)
|
||||
// 建议:调试阶段打开,稳定后可注释或做节流
|
||||
// console.log('[MOVE]', {
|
||||
// udid,
|
||||
// offsetXY: { x: e.offsetX, y: e.offsetY },
|
||||
// deviceXY: curDev,
|
||||
// elapsedMs: Date.now() - st.t
|
||||
// })
|
||||
}
|
||||
|
||||
const onCanvasUp = async (udid, e, index) => {
|
||||
const st = dragState.value[index]
|
||||
if (!st) return
|
||||
|
||||
const { ox, oy, t } = st
|
||||
const { ox, oy, t, startDevXY, startOffsetXY } = st
|
||||
const dx = e.offsetX - ox
|
||||
const dy = e.offsetY - oy
|
||||
const elapsed = Date.now() - t
|
||||
delete dragState.value[index]
|
||||
|
||||
// 映射到真实分辨率
|
||||
const p0 = mapToDeviceXY(index, ox, oy)
|
||||
const p1 = mapToDeviceXY(index, e.offsetX, e.offsetY)
|
||||
console.log(" x, y", p0, p1)
|
||||
// 判断是“点按”还是“滑动”
|
||||
const MOVE_THR = 5 // 像素阈值(可按需调整)
|
||||
// 终点(设备坐标 & 画布 offset)
|
||||
const endDevXY = mapToDeviceXY(index, e.offsetX, e.offsetY)
|
||||
const endOffsetXY = { x: e.offsetX, y: e.offsetY }
|
||||
|
||||
// ✅ 这里打印:起点/终点(两套坐标)+ 耗时
|
||||
console.log('[鼠标滑动,起点/终点)+ 耗时]', {
|
||||
udid,
|
||||
start: {
|
||||
offsetXY: startOffsetXY, // 画布内起点
|
||||
deviceXY: startDevXY // 设备坐标起点
|
||||
},
|
||||
end: {
|
||||
offsetXY: endOffsetXY, // 画布内终点
|
||||
deviceXY: endDevXY // 设备坐标终点
|
||||
},
|
||||
deltaOffset: { dx, dy },
|
||||
durationMs: elapsed,
|
||||
})
|
||||
|
||||
// === 你原有逻辑:tap or swipe ===
|
||||
const MOVE_THR = 5
|
||||
const isTap = Math.hypot(dx, dy) < MOVE_THR && elapsed < 500
|
||||
|
||||
try {
|
||||
if (isTap) {
|
||||
await tapAction({ udid, x: p1.x, y: p1.y })
|
||||
// console.log('tap', p1)
|
||||
await tapAction({ udid, x: endDevXY.x, y: endDevXY.y })
|
||||
} else {
|
||||
// 只需要方向:1上/2左/3下/4右
|
||||
const rotation = Number((deviceInformation.value[index] || {}).rotation || 0)
|
||||
|
||||
const code = getSwipeCodeWithRotation(dx, dy, rotation) // 必定得到1~4
|
||||
console.log("code", code)
|
||||
await swipeAction({ udid, direction: code })
|
||||
// //通过方向判断code 1234
|
||||
// const rotation = Number((deviceInformation.value[index] || {}).rotation || 0)
|
||||
// const code = getSwipeCodeWithRotation(dx, dy, rotation)
|
||||
// await swipeAction({ udid, direction: code })
|
||||
|
||||
//通过自定义滑动坐标和时间传参
|
||||
await swipeAction({ udid, sx: startDevXY.x, sy: startDevXY.y, ex: endDevXY.x, ey: endDevXY.y, duration: elapsed / 1000 })
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
@@ -826,64 +896,90 @@ async function stopAll() {
|
||||
}
|
||||
|
||||
//确认多行文本框内容
|
||||
function onDialogConfirm(result, type, index, isMon) {
|
||||
// console.log(type, result, isMon);
|
||||
console.log(type)
|
||||
function onDialogConfirm(result, type, index, data) {
|
||||
console.log(type, result, data);
|
||||
if (type == '主播ID') {
|
||||
hostList = (result || []).map(id => ({ id, country: '' }))
|
||||
|
||||
dialogTitle.value = '私信';
|
||||
//无需评论,注释,如果需要注释下面代码,放开后面代码
|
||||
// dialogTitle.value = '私信';
|
||||
// setTimeout(() => {
|
||||
// showDialog.value = true;
|
||||
|
||||
// initialTextStr.value = getContentpriListMultiline();
|
||||
// }, 500)
|
||||
dialogTitle.value = '评论';
|
||||
setTimeout(() => {
|
||||
showDialog.value = true;
|
||||
|
||||
initialTextStr.value = getContentpriListMultiline();
|
||||
initialTextStr.value = getContentListMultiline();
|
||||
}, 500)
|
||||
} else if (type == '评论') {
|
||||
comonList = result
|
||||
setContentList(result)
|
||||
common.value = data.common
|
||||
// dialogTitle.value = '私信';
|
||||
// setTimeout(() => {
|
||||
// showDialog.value = true;
|
||||
|
||||
// initialTextStr.value = getContentpriListMultiline();
|
||||
// }, 500)
|
||||
transDlgType.value = '私信'
|
||||
showtransDlg.value = true
|
||||
} else if (type == '私信') {
|
||||
runType.value = 'follow'
|
||||
setContentpriList(result)
|
||||
// console.log('hostList', hostList)
|
||||
// runType.value = 'follow'
|
||||
// setContentpriList(result)
|
||||
|
||||
if (isAlliance.value) {
|
||||
followAndGreetUnion(
|
||||
{
|
||||
deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
anchorList: hostList.map(item => ({
|
||||
anchorId: item.id,
|
||||
country: item.country,
|
||||
invitationType: item.invitationType,
|
||||
state: stateByInvType(item.invitationType),
|
||||
})),
|
||||
prologueList: result,
|
||||
needReply: isMon
|
||||
}
|
||||
).then((res) => {
|
||||
ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
// if (isAlliance.value) {
|
||||
// followAndGreetUnion(
|
||||
// {
|
||||
// deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
// anchorList: hostList.map(item => ({
|
||||
// anchorId: item.id,
|
||||
// country: item.country,
|
||||
// invitationType: item.invitationType,
|
||||
// state: stateByInvType(item.invitationType),
|
||||
// })),
|
||||
// prologueList: result,
|
||||
// needReply: data.auto,
|
||||
// needTranslate: data.needTranslate,
|
||||
// }
|
||||
// ).then((res) => {
|
||||
// ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
|
||||
hostList = []
|
||||
})
|
||||
} else {
|
||||
passAnchorData(
|
||||
{
|
||||
deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
anchorList: hostList.map(item => ({
|
||||
anchorId: item.id,
|
||||
country: item.country,
|
||||
invitationType: item.invitationType,
|
||||
state: stateByInvType(item.invitationType),
|
||||
})),
|
||||
prologueList: result,
|
||||
needReply: isMon
|
||||
}
|
||||
).then((res) => {
|
||||
ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
|
||||
hostList = []
|
||||
})
|
||||
|
||||
}
|
||||
// hostList = []
|
||||
// })
|
||||
// } else {
|
||||
// passAnchorData(
|
||||
// {
|
||||
// deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
// anchorList: hostList.map(item => ({
|
||||
// anchorId: item.id,
|
||||
// country: item.country,
|
||||
// invitationType: item.invitationType,
|
||||
// state: stateByInvType(item.invitationType),
|
||||
// })),
|
||||
// prologueList: result,
|
||||
// comment: comonList,
|
||||
// needReply: data.auto,
|
||||
// needTranslate: data.needTranslate,
|
||||
// isComment: data.common
|
||||
// }
|
||||
// ).then((res) => {
|
||||
// ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
|
||||
// hostList = []
|
||||
// })
|
||||
|
||||
// }
|
||||
} else if (type == '视频评论') {
|
||||
runType.value = 'like'
|
||||
deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId, comment: result, isComment: data.common }))
|
||||
} else if (type == '评论(无消息将刷视频)') {
|
||||
runType.value = 'listen'
|
||||
deviceInformation.value.forEach((item) => monitorMessages({ udid: item.deviceId, comment: result }))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -898,6 +994,7 @@ onMounted(async () => {
|
||||
const res = await window.electronAPI.isiproxy({
|
||||
intervalMs: 2000,
|
||||
exeName: 'iproxy.exe',
|
||||
// maxWaitMs: 3000, // 可选:5分钟超时
|
||||
maxWaitMs: 300000, // 可选:5分钟超时
|
||||
});
|
||||
if (res.running) {
|
||||
@@ -915,12 +1012,34 @@ onMounted(async () => {
|
||||
|
||||
window.electronAPI.startMq(userdata.tenantId, userdata.id)
|
||||
// 初始化时获取设备列表
|
||||
getListtimer = setInterval(() => {
|
||||
|
||||
//每3秒获取一次设备列表 消息列表 和 查询主播列表是否还有主播
|
||||
getListtimer = setInterval(async () => {
|
||||
getDeviceListFun()
|
||||
selectLastFun()
|
||||
const hostsList = await getStoredHostList()
|
||||
// console.log(hostsList.length)
|
||||
//当私信主播时,主播列表没有数据了,提示列表空了 并且关闭私信
|
||||
if (runType.value == 'follow') {
|
||||
if (hostsList.length <= 0) {
|
||||
await stopAll()
|
||||
runType.value = 'like'
|
||||
deviceInformation.value.forEach((item) => growAccount({ udid: item.deviceId }))
|
||||
ElMessageBox.alert('私信全部完成!(刷视频中)', '提示', {
|
||||
confirmButtonText: 'OK',
|
||||
callback: (action) => {
|
||||
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}, 3000)
|
||||
|
||||
setInterval(async () => {
|
||||
await checkVPN()
|
||||
}, 1000 * 20)
|
||||
|
||||
if (!await isAiConfig()) {
|
||||
showMyInfo.value = true
|
||||
}
|
||||
@@ -959,9 +1078,10 @@ onMounted(async () => {
|
||||
const country = data && data.country != null ? data.country : ''
|
||||
const text = data && (data.hostsId != null ? data.hostsId : data.text)
|
||||
const invitationType = data && (data.invitationType != null ? data.invitationType : '')
|
||||
const id = data && data.id != null ? data.id : ''
|
||||
if (!text) return
|
||||
|
||||
batch.push({ country, text, invitationType })
|
||||
batch.push({ country, text, invitationType, id })
|
||||
|
||||
scheduleFlush((items) => {
|
||||
// 批量入库
|
||||
@@ -971,6 +1091,10 @@ onMounted(async () => {
|
||||
invitationType: h.invitationType,
|
||||
state: stateByInvType(h.invitationType),
|
||||
}))
|
||||
updates(items.map(h => ({
|
||||
id: h.id,
|
||||
aiOperation: 1,
|
||||
})))
|
||||
addTempAnchorData(list)
|
||||
}, 400)
|
||||
})
|
||||
@@ -1014,21 +1138,16 @@ const getDeviceListFun = () => {
|
||||
//获取新消息
|
||||
const selectLastFun = () => {
|
||||
selectLast().then((res) => {
|
||||
// console.log("返回", deviceInformation, res)
|
||||
let mesInfoData = res
|
||||
mesInfoData.forEach(element => {
|
||||
deviceInformation.value.forEach((item, index) => {
|
||||
console.log(res)
|
||||
console.log(item.deviceId == element.device)
|
||||
if (item.deviceId == element.device) {
|
||||
element.device = index + 1 + '号设备'
|
||||
console.log(element.device)
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// console.log('============', mesInfoData)
|
||||
MesNewList.value = mesInfoData
|
||||
MesNewList.value = [...mesInfoData];
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1079,7 +1198,7 @@ async function uploadLogFile() {
|
||||
|
||||
}
|
||||
}
|
||||
function runTask(key, deviceId) {
|
||||
function runTask(key, deviceId, type) {
|
||||
console.log('[schedule] 切换到任务:', key, printCurrentTime())
|
||||
|
||||
forceActivate(key, async () => {
|
||||
@@ -1094,6 +1213,7 @@ function runTask(key, deviceId) {
|
||||
deviceList: [deviceId],
|
||||
anchorList: [],
|
||||
prologueList: getContentpriList(),
|
||||
comment: comonList,
|
||||
needReply: false
|
||||
}
|
||||
).then((res) => {
|
||||
@@ -1102,7 +1222,7 @@ function runTask(key, deviceId) {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//第一个小时结束后,第二轮开始的时候,直接进入follow
|
||||
setTimeout(() => {
|
||||
runType.value = 'follow'
|
||||
|
||||
@@ -1111,6 +1231,7 @@ function runTask(key, deviceId) {
|
||||
deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
anchorList: [],
|
||||
prologueList: getContentpriList(),
|
||||
comment: comonList,
|
||||
needReply: false
|
||||
}
|
||||
).then((res) => {
|
||||
@@ -1194,20 +1315,46 @@ function resumeAfterInterrupt() {
|
||||
pauseSnapshot = null
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行一次中断器函数
|
||||
* 该函数会尝试使用设备列表中的每个设备更改账户,并检查是否所有操作都成功
|
||||
* @returns {Promise<boolean>} 返回一个Promise,解析为布尔值,表示操作是否全部成功
|
||||
*/
|
||||
async function runInterrupterOnce() {
|
||||
// TODO: 换成你的真实调用,比如:替换
|
||||
// const ok = await someApi({ ... })
|
||||
// return !!ok
|
||||
|
||||
// 示例:包装一个带超时的 Promise;把你的方法放到 promiseFn 里
|
||||
// 定义一个异步函数,用于执行设备账户更改操作
|
||||
const promiseFn = async () => {
|
||||
// 这里放你的真实逻辑
|
||||
changeAccount
|
||||
console.log('[换号] 正在执行...')
|
||||
// 比如 await doDailyCheck(); 然后返回 true/false
|
||||
return true
|
||||
}
|
||||
return await withTimeout(promiseFn(), interruptCallTimeoutMs).catch(() => false)
|
||||
// 从deviceInformation中提取设备ID,并过滤掉无效值
|
||||
const devices = (deviceInformation.value || [])
|
||||
.map(d => d?.deviceId)
|
||||
.filter(Boolean);
|
||||
|
||||
// 如果没有有效设备,直接返回false
|
||||
if (!devices.length) return false;
|
||||
console.log(devices.length + '台设备换账号')
|
||||
// 为每个设备创建一个检查函数,用于尝试更改账户
|
||||
const checks = devices.map(async (udid) => {
|
||||
try {
|
||||
// 尝试更改账户并检查返回结果
|
||||
const res = await changeAccount({ udid: udid });
|
||||
// 检查返回值是否表示成功
|
||||
return (
|
||||
res.code === 200
|
||||
);
|
||||
} catch {
|
||||
// 如果出错,返回false
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// 等待所有检查完成,并获取结果
|
||||
const settled = await Promise.allSettled(checks);
|
||||
// 检查是否所有操作都成功完成
|
||||
const allOk = settled.every(s => s.status === 'fulfilled' && s.value === true);
|
||||
return allOk;
|
||||
};
|
||||
|
||||
// 使用超时机制执行promiseFn,捕获超时或其他错误并返回false
|
||||
return await withTimeout(promiseFn(), interruptCallTimeoutMs).catch(() => false);
|
||||
}
|
||||
|
||||
function withTimeout(p, ms) {
|
||||
@@ -1222,7 +1369,7 @@ function startScheduleLoop() {
|
||||
lastInterruptTs = Date.now()
|
||||
localStorage.setItem('INT_LAST_TS', String(lastInterruptTs))
|
||||
// 先按当前 index 跑一次,保持“即刻对齐”
|
||||
runTask(schedulePlan[scheduleState.index].key)
|
||||
runTask(schedulePlan[scheduleState.index].key, null, 1)
|
||||
|
||||
if (scheduleTimer) clearInterval(scheduleTimer)
|
||||
|
||||
@@ -1235,12 +1382,12 @@ function startScheduleLoop() {
|
||||
const now = Date.now()
|
||||
if (!lastInterruptTs) lastInterruptTs = now // 首次初始化
|
||||
|
||||
const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000
|
||||
const due = now - lastInterruptTs >= interruptEveryMin.value * 60_000 * 60_000
|
||||
|
||||
console.log(
|
||||
'due=', due,
|
||||
'elapsed=', now - lastInterruptTs,
|
||||
'threshold=', interruptEveryMin.value * 60_000
|
||||
'threshold=', interruptEveryMin.value * 60_000 * 60_000
|
||||
)
|
||||
if (due) {
|
||||
interrupting = true
|
||||
@@ -1251,7 +1398,8 @@ function startScheduleLoop() {
|
||||
pauseSnapshot = { index: scheduleState.index, elapsedBeforePause }
|
||||
|
||||
// 停掉当前片段
|
||||
await stopCurrentMode()
|
||||
await stopAll()
|
||||
|
||||
|
||||
// 执行中断任务(带重试)
|
||||
let ok = false
|
||||
@@ -1296,7 +1444,7 @@ function startScheduleLoop() {
|
||||
|
||||
function forceActivate(key, runner) {
|
||||
// 跳过互斥逻辑,直接切换
|
||||
runType.value = key;
|
||||
// runType.value = key;
|
||||
if (typeof runner === 'function') runner();
|
||||
}
|
||||
|
||||
@@ -1402,6 +1550,131 @@ function stopOne(deviceId) {
|
||||
})
|
||||
}
|
||||
|
||||
//查看主播库主播信息
|
||||
async function getStoredHostList() {
|
||||
const v = await anchorList()
|
||||
return v ? v : []
|
||||
}
|
||||
|
||||
|
||||
let isWifi = ref(false);
|
||||
const checkVPN = async () => {
|
||||
try {
|
||||
// 设置超时 5 秒钟
|
||||
const timeout = new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error('请求超时')), 10000) // 10秒超时
|
||||
);
|
||||
|
||||
// 使用 Promise.race 来进行超时控制
|
||||
const response = await Promise.race([
|
||||
fetch('https://www.google.com', { method: 'HEAD', mode: 'no-cors' }),
|
||||
timeout
|
||||
]);
|
||||
|
||||
// 判断 fetch 请求是否成功
|
||||
if (response && response.type === 'opaque') {
|
||||
// ElMessage.success('VPN连接正常!');
|
||||
isWifi.value = false;
|
||||
} else {
|
||||
ElMessage.error('VPN连接失败,无法访问网络。');
|
||||
isWifi.value = true;
|
||||
}
|
||||
} catch (error) {
|
||||
// 捕获超时错误或其他错误
|
||||
ElMessage.error('VPN连接失败,无法访问网络。');
|
||||
isWifi.value = true;
|
||||
}
|
||||
};
|
||||
|
||||
// 语言选项(也可以使用内置默认)
|
||||
// const languages = [
|
||||
// { label: '简体中文 (zh-CN)', value: 'zh-CN' },
|
||||
// { label: 'English (en)', value: 'en' },
|
||||
// { label: '日本語 (ja)', value: 'ja' },
|
||||
// ]
|
||||
|
||||
// 模拟翻译函数:你可以接入自己后端或第三方接口 sentences文本 targetLang语言
|
||||
async function doTranslate(sentences, targetLang) {
|
||||
const str = arrayToString(sentences)
|
||||
try {
|
||||
const response = await customTranslation({
|
||||
"msg": str,
|
||||
"language": targetLang
|
||||
})
|
||||
console.log(response)
|
||||
|
||||
|
||||
// 1️⃣ 去掉首尾的大括号
|
||||
const raw = response.replace(/^{|}$/g, '')
|
||||
|
||||
// 2️⃣ 按换行符切割为数组
|
||||
const arr = raw.split('\n').map(s => s.trim()).filter(Boolean)
|
||||
|
||||
console.log(arr)
|
||||
// 简单演示逻辑(真实情况应调用 API)
|
||||
return arr
|
||||
} catch (error) {
|
||||
console.error('Translation error:', error)
|
||||
// 发生错误时返回空数组
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
// 接收“确定”事件返回结果
|
||||
function onConfirm({ type, strings, auto }) {
|
||||
console.log('✅ 确认返回:', type, strings, auto)
|
||||
showtransDlg.value = false
|
||||
runType.value = 'follow'
|
||||
setContentpriList(strings)
|
||||
|
||||
if (isAlliance.value) {
|
||||
followAndGreetUnion(
|
||||
{
|
||||
deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
anchorList: hostList.map(item => ({
|
||||
anchorId: item.id,
|
||||
country: item.country,
|
||||
invitationType: item.invitationType,
|
||||
state: stateByInvType(item.invitationType),
|
||||
})),
|
||||
prologueList: strings,
|
||||
needReply: data.auto,
|
||||
// needTranslate: data.needTranslate,
|
||||
}
|
||||
).then((res) => {
|
||||
ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
|
||||
hostList = []
|
||||
})
|
||||
} else {
|
||||
passAnchorData(
|
||||
{
|
||||
deviceList: deviceInformation.value.map(item => item.deviceId),
|
||||
anchorList: hostList.map(item => ({
|
||||
anchorId: item.id,
|
||||
country: item.country,
|
||||
invitationType: item.invitationType,
|
||||
state: stateByInvType(item.invitationType),
|
||||
})),
|
||||
prologueList: strings, //私信对象
|
||||
comment: comonList, //评论列表
|
||||
needReply: auto, //自动回复
|
||||
// needTranslate: data.needTranslate,
|
||||
isComment: common.value //是否评论
|
||||
}
|
||||
).then((res) => {
|
||||
ElMessage({ type: 'success', message: '任务开启成功' });
|
||||
console.log("启动成功")
|
||||
hostList = []
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function arrayToString(arr) {
|
||||
// 过滤空项并用 \n 连接
|
||||
return arr.filter(Boolean).join(' \n')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
|
||||
Reference in New Issue
Block a user