压缩
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<title>
|
||||
<%= webpackConfig.name %>
|
||||
</title>
|
||||
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
|
||||
<!-- pywebview API 自动注入,无需手动引入脚本 -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -21,12 +21,20 @@
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
/* width: 1600px;
|
||||
height: 900px; */
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#app {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,74 +1,100 @@
|
||||
// pythonBridge.js
|
||||
// 适配 pywebview API (替代原有的 QWebChannel)
|
||||
import { ref, onMounted } from 'vue';
|
||||
|
||||
const bridge = ref(null);
|
||||
const isReady = ref(false);
|
||||
|
||||
// 统一安全调用,确保 Qt 响应有回调可执行
|
||||
const callBridge = (method, ...args) => {
|
||||
if (!bridge.value || typeof bridge.value[method] !== 'function') return;
|
||||
const last = args[args.length - 1];
|
||||
const hasCallback = typeof last === 'function';
|
||||
const callback = hasCallback ? args.pop() : () => { };
|
||||
bridge.value[method](...args, callback);
|
||||
};
|
||||
|
||||
// 防御:若 Qt 返回了未知 id,忽略以免 execCallbacks 报错
|
||||
const patchQWebChannel = () => {
|
||||
if (!window.QWebChannel || QWebChannel.__patchedIgnoreMissing) return;
|
||||
const originalHandleResponse = QWebChannel.prototype.handleResponse;
|
||||
QWebChannel.__patchedIgnoreMissing = true;
|
||||
QWebChannel.prototype.handleResponse = function (message) {
|
||||
const cb = this.execCallbacks && this.execCallbacks[message.id];
|
||||
if (message.id && typeof cb !== 'function') {
|
||||
console.warn('忽略未知的 WebChannel 响应', message);
|
||||
/**
|
||||
* 等待 pywebview API 准备就绪
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const waitForPywebview = () => {
|
||||
return new Promise((resolve) => {
|
||||
// 如果已经存在,直接返回
|
||||
if (window.pywebview && window.pywebview.api) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
return originalHandleResponse.call(this, message);
|
||||
};
|
||||
// 监听 pywebviewready 事件
|
||||
window.addEventListener('pywebviewready', () => {
|
||||
resolve();
|
||||
}, { once: true });
|
||||
});
|
||||
};
|
||||
|
||||
// 初始化 QWebChannel
|
||||
const initBridge = () => {
|
||||
if (/localhost/.test(window.location.href)) return;
|
||||
patchQWebChannel();
|
||||
new QWebChannel(qt.webChannelTransport, (channel) => {
|
||||
// 兜底:任何缺失的回调都返回空函数,避免 execCallbacks 报错
|
||||
channel.execCallbacks = new Proxy(channel.execCallbacks || {}, {
|
||||
get(target, prop) {
|
||||
const val = target[prop];
|
||||
if (typeof val === 'function') return val;
|
||||
// 返回空函数,确保 handleResponse 可调用
|
||||
return () => {};
|
||||
},
|
||||
set(target, prop, value) {
|
||||
target[prop] = value;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
/**
|
||||
* 统一安全调用 pywebview API
|
||||
* pywebview 的方法调用会返回 Promise
|
||||
*/
|
||||
const callBridge = async (method, ...args) => {
|
||||
if (!bridge.value || typeof bridge.value[method] !== 'function') {
|
||||
console.warn(`[pythonBridge] 方法不存在: ${method}`);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const result = await bridge.value[method](...args);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`[pythonBridge] 调用 ${method} 失败:`, error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
bridge.value = channel.objects.bridge;
|
||||
/**
|
||||
* 初始化 pywebview 桥接
|
||||
*/
|
||||
const initBridge = async () => {
|
||||
// 监听 DevTools 快捷键 (Ctrl + Shift + P)
|
||||
window.addEventListener('keydown', (e) => {
|
||||
// 1. 自定义快捷键: Ctrl + Shift + P -> 调用后端
|
||||
if (e.ctrlKey && e.shiftKey && (e.key === 'p' || e.key === 'P')) {
|
||||
e.preventDefault();
|
||||
callBridge('openDevTools');
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 屏蔽 F12 (防止用户按下 F12 打开)
|
||||
if (e.key === 'F12') {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// 开发环境 (localhost) 不初始化
|
||||
if (/localhost/.test(window.location.href)) {
|
||||
console.log('[pythonBridge] 开发环境,跳过初始化');
|
||||
return;
|
||||
}
|
||||
|
||||
await waitForPywebview();
|
||||
|
||||
if (window.pywebview && window.pywebview.api) {
|
||||
bridge.value = window.pywebview.api;
|
||||
isReady.value = true;
|
||||
console.log('[pythonBridge] 初始化成功');
|
||||
} else {
|
||||
console.error('[pythonBridge] pywebview API 初始化失败');
|
||||
}
|
||||
};
|
||||
|
||||
export function usePythonBridge() {
|
||||
// 调用 Python 方法
|
||||
const fetchDataConfig = (data) => {
|
||||
return new Promise((resolve) => {
|
||||
if (!bridge.value) return resolve(null);
|
||||
callBridge('fetchDataConfig', data, (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
const fetchDataConfig = async (data) => {
|
||||
if (!bridge.value) return null;
|
||||
return await callBridge('fetchDataConfig', data);
|
||||
};
|
||||
|
||||
// 查询获取主播的数据
|
||||
const fetchDataCount = () => {
|
||||
return new Promise((resolve) => {
|
||||
if (!bridge.value) return resolve(null);
|
||||
callBridge('fetchDataCount', (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
const fetchDataCount = async () => {
|
||||
if (!bridge.value) return null;
|
||||
const result = await callBridge('fetchDataCount');
|
||||
// pywebview 返回的是字符串,需要解析
|
||||
try {
|
||||
return typeof result === 'string' ? JSON.parse(result) : result;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 打开 tk 后台
|
||||
@@ -91,23 +117,25 @@ export function usePythonBridge() {
|
||||
};
|
||||
|
||||
// 查询登录状态
|
||||
const backStageloginStatus = () => {
|
||||
return new Promise((resolve) => {
|
||||
if (!bridge.value) return resolve(null);
|
||||
callBridge('backStageloginStatus', (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
const backStageloginStatus = async () => {
|
||||
if (!bridge.value) return null;
|
||||
const result = await callBridge('backStageloginStatus');
|
||||
try {
|
||||
return typeof result === 'string' ? JSON.parse(result) : result;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 查询登录状态(副账号)
|
||||
const backStageloginStatusCopy = () => {
|
||||
return new Promise((resolve) => {
|
||||
if (!bridge.value) return resolve(null);
|
||||
callBridge('backStageloginStatusCopy', (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
const backStageloginStatusCopy = async () => {
|
||||
if (!bridge.value) return null;
|
||||
const result = await callBridge('backStageloginStatusCopy');
|
||||
try {
|
||||
return typeof result === 'string' ? JSON.parse(result) : result;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 导出表格
|
||||
@@ -120,19 +148,33 @@ export function usePythonBridge() {
|
||||
};
|
||||
|
||||
// 获取版本号
|
||||
const getVersion = () => {
|
||||
return new Promise((resolve) => {
|
||||
if (!bridge.value) return resolve(null);
|
||||
callBridge('currentVersion', (result) => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
const getVersion = async () => {
|
||||
if (!bridge.value) return null;
|
||||
return await callBridge('currentVersion');
|
||||
};
|
||||
|
||||
// 存储账号信息
|
||||
const storageAccountInfo = async (key, data) => {
|
||||
if (!bridge.value) return false;
|
||||
return await callBridge('storageAccountInfo', key, JSON.stringify(data));
|
||||
};
|
||||
|
||||
// 读取账号信息
|
||||
const readAccountInfo = async (key) => {
|
||||
if (!bridge.value) return null;
|
||||
const result = await callBridge('readAccountInfo', key);
|
||||
try {
|
||||
return typeof result === 'string' ? JSON.parse(result) : result;
|
||||
} catch {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 在组件挂载时初始化桥接
|
||||
onMounted(initBridge);
|
||||
|
||||
return {
|
||||
isReady,
|
||||
fetchDataConfig,
|
||||
fetchDataCount,
|
||||
loginBackStage,
|
||||
@@ -143,5 +185,7 @@ export function usePythonBridge() {
|
||||
exportToExcel,
|
||||
stopScript,
|
||||
getVersion,
|
||||
storageAccountInfo,
|
||||
readAccountInfo,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -171,8 +171,8 @@ const onSubmit = () => {
|
||||
|
||||
<style lang="less">
|
||||
.main {
|
||||
width: 1600px;
|
||||
height: 900px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -185,14 +185,14 @@ const onSubmit = () => {
|
||||
.container {
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
width: 1600px;
|
||||
height: 900px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.right {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 1600px;
|
||||
height: 900px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px 40px 20px 50px;
|
||||
border-left: 3px solid #23516e;
|
||||
position: relative;
|
||||
@@ -363,4 +363,4 @@ const onSubmit = () => {
|
||||
::v-deep(.el-input__inner::placeholder) {
|
||||
color: @bg-color;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -411,14 +411,15 @@ const submit = () => {
|
||||
//开启查询次数
|
||||
getHostTimer.value = setInterval(() => {
|
||||
fetchDataCount().then((res) => {
|
||||
hostData.value = JSON.parse(res);
|
||||
if (isLimit.value) {
|
||||
if (hostData.value.canInvitationCount >= hostNum.value) {
|
||||
unsubmit();
|
||||
alert('爬取完毕')
|
||||
if (res) {
|
||||
hostData.value = res;
|
||||
if (isLimit.value) {
|
||||
if (hostData.value.canInvitationCount >= hostNum.value) {
|
||||
unsubmit();
|
||||
alert('爬取完毕')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}, 1000);
|
||||
getNumTimer.value = setInterval(() => {
|
||||
@@ -511,7 +512,7 @@ const openTK = () => {
|
||||
|
||||
function getloginStatus() {
|
||||
backStageloginStatus().then((res) => {
|
||||
const data = JSON.parse(res);
|
||||
const data = res;
|
||||
tkData.value[data.index].code = data.code
|
||||
|
||||
if (data.code == 1) {
|
||||
@@ -524,7 +525,7 @@ function getloginStatus() {
|
||||
}
|
||||
function getloginStatusCopy() {
|
||||
backStageloginStatusCopy().then((res) => {
|
||||
const data = JSON.parse(res);
|
||||
const data = res;
|
||||
tkData.value[data.index].code = data.code
|
||||
|
||||
if (data.code == 1) {
|
||||
@@ -949,4 +950,4 @@ const checkVPN = async () => {
|
||||
/* 垂直居中 */
|
||||
/* 示例高度,根据需要调整 */
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user