feat:完成清除高亮脚本封装
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* Collabora Online Python 脚本调用工具
|
||||
*
|
||||
* 职责: 统一封装所有 Python 脚本的调用逻辑和响应处理
|
||||
* @encoding UTF-8
|
||||
*/
|
||||
|
||||
export interface ScriptResult {
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: {
|
||||
count?: number;
|
||||
action?: string;
|
||||
unit?: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
timestamp: number;
|
||||
}
|
||||
|
||||
export interface CallScriptOptions {
|
||||
timeout?: number;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
interface PostMessageResponse {
|
||||
MessageId?: string;
|
||||
Values?: {
|
||||
commandName?: string;
|
||||
success?: boolean;
|
||||
result?: string | { type?: string; value?: string };
|
||||
};
|
||||
}
|
||||
|
||||
export async function callPythonScript(
|
||||
iframeWindow: Window,
|
||||
scriptFile: string,
|
||||
functionName: string,
|
||||
args?: Record<string, unknown>,
|
||||
options?: CallScriptOptions
|
||||
): Promise<ScriptResult> {
|
||||
const timeout = options?.timeout || 10000;
|
||||
const verbose = options?.verbose ?? true;
|
||||
|
||||
if (verbose) {
|
||||
console.log('[CallCustomScript] 调用 Python 脚本:', { scriptFile, functionName, args });
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
const cleanup = () => {
|
||||
clearTimeout(timeoutId);
|
||||
window.removeEventListener('message', handleMessage);
|
||||
};
|
||||
|
||||
const timeoutId: NodeJS.Timeout = setTimeout(() => {
|
||||
cleanup();
|
||||
reject(new Error(`Python 脚本调用超时 (${timeout}ms): ${scriptFile}.${functionName}`));
|
||||
}, timeout);
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
try {
|
||||
if (event.source !== iframeWindow) return;
|
||||
|
||||
const data: PostMessageResponse = typeof event.data === 'string'
|
||||
? JSON.parse(event.data) : event.data;
|
||||
|
||||
// 兼容两种 MessageId 格式:
|
||||
// - 'CallPythonScript_Resp' (预期格式)
|
||||
// - 'CallPythonScript-Result' (bundle.js 实际发送的格式)
|
||||
if (data.MessageId !== 'CallPythonScript-Result') return;
|
||||
|
||||
cleanup();
|
||||
|
||||
if (verbose) {
|
||||
console.log('[CallCustomScript] 收到 Python 脚本响应:', data);
|
||||
}
|
||||
|
||||
const result = parseScriptResponse(data, verbose);
|
||||
resolve(result);
|
||||
} catch (error) {
|
||||
cleanup();
|
||||
reject(error);
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
|
||||
const message = {
|
||||
MessageId: 'CallPythonScript',
|
||||
ScriptFile: scriptFile,
|
||||
Function: functionName,
|
||||
Values: args || {},
|
||||
};
|
||||
|
||||
if (verbose) {
|
||||
console.log('[CallCustomScript] 发送 PostMessage:', message);
|
||||
}
|
||||
|
||||
iframeWindow.postMessage(JSON.stringify(message), '*');
|
||||
});
|
||||
}
|
||||
|
||||
function parseScriptResponse(data: PostMessageResponse, verbose: boolean): ScriptResult {
|
||||
const values = data.Values;
|
||||
|
||||
if (!values || typeof values !== 'object') {
|
||||
throw new Error('响应格式错误: Values 字段缺失或格式不正确');
|
||||
}
|
||||
|
||||
let resultValue: string | undefined;
|
||||
|
||||
if (typeof values.result === 'string') {
|
||||
resultValue = values.result;
|
||||
} else if (values.result && typeof values.result === 'object') {
|
||||
resultValue = (values.result as { value?: string }).value;
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
console.log('[CallCustomScript] 解析结果:', {
|
||||
commandName: values.commandName,
|
||||
unoSuccess: values.success,
|
||||
resultRaw: values.result,
|
||||
resultExtracted: resultValue,
|
||||
});
|
||||
}
|
||||
|
||||
if (values.success === false) {
|
||||
return {
|
||||
success: false,
|
||||
message: resultValue || 'UNO 命令执行失败',
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof resultValue !== 'string') {
|
||||
throw new Error('Python 脚本返回值格式错误: result 不是字符串');
|
||||
}
|
||||
|
||||
return parseStandardResponse(resultValue);
|
||||
}
|
||||
|
||||
function parseStandardResponse(message: string): ScriptResult {
|
||||
const timestamp = Date.now();
|
||||
|
||||
if (message.includes('Error:') || message.toLowerCase().includes('error')) {
|
||||
return { success: false, message, timestamp };
|
||||
}
|
||||
|
||||
const countMatch = message.match(/(\w+)\s+(\d+)\s+(regions?|instances?|items?)/i);
|
||||
|
||||
if (countMatch) {
|
||||
const count = parseInt(countMatch[2], 10);
|
||||
return {
|
||||
success: true,
|
||||
message,
|
||||
data: {
|
||||
count,
|
||||
action: countMatch[1].toLowerCase(),
|
||||
unit: countMatch[3].toLowerCase(),
|
||||
},
|
||||
timestamp,
|
||||
};
|
||||
}
|
||||
|
||||
return { success: true, message, timestamp };
|
||||
}
|
||||
|
||||
export async function callPythonScriptBatch(
|
||||
iframeWindow: Window,
|
||||
calls: Array<{
|
||||
scriptFile: string;
|
||||
functionName: string;
|
||||
args?: Record<string, unknown>;
|
||||
}>,
|
||||
options?: CallScriptOptions
|
||||
): Promise<ScriptResult[]> {
|
||||
const results: ScriptResult[] = [];
|
||||
|
||||
for (const call of calls) {
|
||||
try {
|
||||
const result = await callPythonScript(
|
||||
iframeWindow,
|
||||
call.scriptFile,
|
||||
call.functionName,
|
||||
call.args,
|
||||
options
|
||||
);
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : String(error),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
Reference in New Issue
Block a user