AiDemo/electron/winaxHelper.js
2025-10-24 17:31:14 +08:00

573 行
17 KiB
JavaScript

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

const { ipcMain, BrowserWindow } = require('electron');
const path = require('path');
const fs = require('fs');
let winax;
try {
winax = require('winax');
console.log('✅ Winax loaded successfully');
} catch (error) {
console.warn('❌ Winax not available:', error.message);
}
class WPSHelper {
constructor() {
this.wpsApp = null;
this.activeDocument = null;
this.isConnected = false;
this.documents = new Map();
this.checkInterval = null;
this.lastParagraphContent = '';
this.startMonitoring();
console.log('🔄 WPSHelper initialized');
}
connectToWPS() {
if (!winax) {
console.warn('⚠️ Winax not available, using fallback mode');
this.setupFallbackMode();
return false;
}
try {
this.wpsApp = new winax.Object('KWPS.Application');
this.wpsApp.Visible = true;
this.isConnected = true;
console.log('✅ Connected to WPS');
this.setupEventListeners();
this.startMonitoring();
this.sendWPSStatus();
return true;
} catch (error) {
console.error('❌ Failed to connect to WPS:', error);
this.isConnected = false;
this.setupFallbackMode();
return false;
}
}
setupEventListeners() {
this.lastActiveDocument = null;
this.lastDocumentCount = 0;
}
startMonitoring() {
if (this.checkInterval) {
clearInterval(this.checkInterval);
}
this.checkInterval = setInterval(() => {
this.checkWPSStatus();
this.updateDocumentsList();
}, 2000);
}
checkWPSStatus() {
try {
if (this.wpsApp && this.isConnected) {
try {
const name = this.wpsApp.Name;
this.isConnected = true;
} catch (error) {
this.isConnected = false;
this.wpsApp = null;
}
} else {
this.isConnected = false;
}
} catch (error) {
this.isConnected = false;
this.wpsApp = null;
}
}
updateDocumentsList() {
if (!this.isConnected || !this.wpsApp) {
if (!this.isConnected) {
this.simulateDocumentsList();
}
return;
}
try {
const newDocs = new Map();
let documents;
try {
documents = this.wpsApp.Documents;
} catch (error) {
return;
}
for (let i = 1; i <= documents.Count; i++) {
try {
const doc = documents.Item(i);
const fullName = doc.FullName;
const name = doc.Name;
newDocs.set(fullName, {
name: name,
path: fullName,
document: doc,
isActive: doc === this.activeDocument
});
} catch (error) {
console.warn('Error accessing document:', error);
}
}
this.documents = newDocs;
this.sendDocumentsList();
} catch (error) {
console.error('Error updating documents list:', error);
}
}
getFullParagraphContent() {
if (!this.isConnected || !this.wpsApp || !this.activeDocument) {
return this.getFallbackParagraphContent();
}
try {
const selection = this.wpsApp.Selection;
if (!selection) {
return this.getFallbackParagraphContent();
}
const originalStart = selection.Start;
const originalEnd = selection.End;
try {
selection.Expand(5); // wdParagraph
const text = selection.Text;
const revisions = this.getRevisionsInSelection(selection);
const comments = this.getCommentsInSelection(selection);
selection.SetRange(originalStart, originalEnd);
return {
text: text.trim(),
html: text.trim(),
revisions: revisions,
comments: comments,
hasRevisions: revisions.length > 0,
hasComments: comments.length > 0
};
} catch (error) {
selection.SetRange(originalStart, originalEnd);
return this.getFallbackParagraphContent();
}
} catch (error) {
return this.getFallbackParagraphContent();
}
}
getRevisionsInSelection(selection) {
const revisions = [];
if (!selection || !selection.Revisions) return revisions;
try {
const revisionsCount = selection.Revisions.Count;
for (let i = 1; i <= revisionsCount; i++) {
try {
const revision = selection.Revisions.Item(i);
revisions.push({
type: 'insert',
author: revision.Author || '未知作者',
date: revision.Date || new Date(),
text: revision.Range.Text || '',
index: i
});
} catch (error) {
console.warn('Error getting revision:', error);
}
}
} catch (error) {
console.warn('Could not access revisions:', error.message);
}
return revisions;
}
getCommentsInSelection(selection) {
const comments = [];
if (!selection || !selection.Comments) return comments;
try {
const commentsCount = selection.Comments.Count;
for (let i = 1; i <= commentsCount; i++) {
try {
const comment = selection.Comments.Item(i);
comments.push({
author: comment.Author || '未知作者',
date: comment.Date || new Date(),
text: comment.Range.Text || '',
index: i
});
} catch (error) {
console.warn('Error getting comment:', error);
}
}
} catch (error) {
console.warn('Could not access comments:', error.message);
}
return comments;
}
getFallbackParagraphContent() {
return {
text: this.lastParagraphContent || '',
html: this.lastParagraphContent || '',
revisions: [],
comments: [],
hasRevisions: false,
hasComments: false
};
}
updateParagraphWithRevisions(newContent) {
if (!this.isConnected || !this.wpsApp || !this.activeDocument) {
return { success: false, error: 'WPS not connected' };
}
try {
const selection = this.wpsApp.Selection;
if (!selection) {
return { success: false, error: 'No selection available' };
}
const originalStart = selection.Start;
const originalEnd = selection.End;
try {
selection.Expand(5); // wdParagraph
const originalText = selection.Text.trim();
if (originalText === newContent.trim()) {
return { success: true, unchanged: true };
}
selection.Text = newContent;
this.lastParagraphContent = newContent;
return {
success: true,
originalContent: originalText,
newContent: newContent,
hasChanges: true
};
} catch (error) {
return { success: false, error: error.message };
} finally {
try {
selection.SetRange(originalStart, originalStart);
} catch (e) {}
}
} catch (error) {
return { success: false, error: error.message };
}
}
navigateParagraph(direction) {
if (!this.isConnected || !this.wpsApp || !this.activeDocument) {
return false;
}
try {
const selection = this.wpsApp.Selection;
if (!selection) {
return false;
}
if (direction === 'prev') {
selection.MoveUp(5, 1); // wdParagraph
} else if (direction === 'next') {
selection.MoveDown(5, 1); // wdParagraph
}
return true;
} catch (error) {
console.error('Error navigating paragraphs:', error);
return false;
}
}
openDocument(filePath) {
if (!this.isConnected || !this.wpsApp) {
console.log('WPS not connected, using fallback');
return false;
}
try {
if (!fs.existsSync(filePath)) {
throw new Error('File does not exist: ' + filePath);
}
const doc = this.wpsApp.Documents.Open(filePath);
this.activeDocument = doc;
this.documents.set(filePath, {
name: doc.Name,
path: filePath,
document: doc,
isActive: true
});
this.sendDocumentsList();
this.sendActiveDocumentChange();
console.log('Document opened successfully:', path.basename(filePath));
return true;
} catch (error) {
console.error('Error opening document:', error);
return false;
}
}
switchToDocument(filePath) {
if (!this.isConnected || !this.wpsApp) {
return false;
}
const docInfo = this.documents.get(filePath);
if (docInfo && docInfo.document) {
try {
docInfo.document.Activate();
this.activeDocument = docInfo.document;
this.sendActiveDocumentChange();
return true;
} catch (error) {
console.error('Error switching document:', error);
}
}
return false;
}
handleRevision(action, revisionIndex) {
if (!this.isConnected || !this.wpsApp || !this.activeDocument) {
return { success: false, error: 'WPS not connected' };
}
try {
if (revisionIndex !== null) {
const revision = this.activeDocument.Revisions.Item(revisionIndex);
if (action === 'accept') {
revision.Accept();
} else {
revision.Reject();
}
} else {
const revisions = this.activeDocument.Revisions;
if (action === 'accept') {
revisions.AcceptAll();
} else {
revisions.RejectAll();
}
}
return { success: true };
} catch (error) {
return { success: false, error: error.message };
}
}
addComment(commentText) {
if (!this.isConnected || !this.wpsApp || !this.activeDocument) {
return { success: false, error: 'WPS not connected' };
}
try {
const selection = this.wpsApp.Selection;
if (!selection) {
return { success: false, error: 'No selection available' };
}
const comment = selection.Comments.Add(selection.Range);
comment.Range.Text = commentText;
return { success: true, comment: commentText };
} catch (error) {
return { success: false, error: error.message };
}
}
setTrackRevisions(track) {
if (!this.isConnected || !this.wpsApp) return false;
try {
this.wpsApp.ActiveDocument.TrackRevisions = track;
return true;
} catch (error) {
console.warn('Could not set track revisions:', error.message);
return false;
}
}
setupFallbackMode() {
console.log('Setting up fallback mode');
this.isConnected = false;
this.startMonitoring();
setTimeout(() => {
this.simulateDocumentsList();
}, 2000);
}
simulateDocumentsList() {
const mockDocuments = [
{
name: '示例文档.docx',
path: 'C:\\Documents\\示例文档.docx',
isActive: true
}
];
this.sendDocumentsList(mockDocuments);
const sampleParagraph = `这是一个示例段落内容。在回退模式下,您可以查看界面功能,但实际的WPS文档操作需要安装WPS并确保Winax正常工作。
当前功能包括:
• 文档列表显示
• 段落内容显示
• 基本的导航操作
• 文件拖拽处理
要启用完整的WPS集成功能,请确保
1. 已安装WPS Office
2. Winax模块正确安装
3. 应用程序有足够的权限访问COM组件`;
this.sendFullParagraphContent({
text: sampleParagraph,
html: sampleParagraph,
revisions: [],
comments: [],
hasRevisions: false,
hasComments: false
});
}
sendWPSStatus() {
if (ipcMain) {
const windows = BrowserWindow.getAllWindows();
windows.forEach(window => {
if (window && !window.isDestroyed()) {
try {
window.webContents.send('wps-status-changed', {
connected: this.isConnected,
hasActiveDocument: !!this.activeDocument,
documentCount: this.documents.size,
timestamp: new Date().toISOString()
});
} catch (error) {
console.warn('Error sending WPS status:', error);
}
}
});
}
}
sendDocumentsList(documents = null) {
if (ipcMain) {
const docs = documents || Array.from(this.documents.values()).map(doc => ({
name: doc.name,
path: doc.path,
isActive: doc.document === this.activeDocument
}));
const windows = BrowserWindow.getAllWindows();
windows.forEach(window => {
if (window && !window.isDestroyed()) {
try {
window.webContents.send('documents-list-changed', docs);
} catch (error) {
console.warn('Error sending documents list:', error);
}
}
});
}
}
sendActiveDocumentChange() {
if (ipcMain && this.activeDocument) {
const windows = BrowserWindow.getAllWindows();
windows.forEach(window => {
if (window && !window.isDestroyed()) {
try {
window.webContents.send('active-document-changed', {
name: this.activeDocument.Name,
path: this.activeDocument.FullName
});
} catch (error) {
console.warn('Error sending active document change:', error);
}
}
});
}
}
sendFullParagraphContent(content) {
if (ipcMain) {
const windows = BrowserWindow.getAllWindows();
windows.forEach(window => {
if (window && !window.isDestroyed()) {
try {
window.webContents.send('full-paragraph-content-changed', content);
} catch (error) {
console.warn('Error sending full paragraph content:', error);
}
}
});
}
}
getStatus() {
if (!this.isConnected) this.connectToWPS();
return {
connected: this.isConnected,
activeDocument: this.activeDocument ? {
name: this.activeDocument.Name,
path: this.activeDocument.FullName
} : null,
documents: Array.from(this.documents.values()).map(doc => ({
name: doc.name,
path: doc.path,
isActive: doc.document === this.activeDocument
})),
currentParagraph: this.lastParagraphContent,
timestamp: new Date().toISOString()
};
}
cleanup() {
console.log('Cleaning up WPSHelper resources...');
if (this.checkInterval) {
clearInterval(this.checkInterval);
this.checkInterval = null;
}
if (this.wpsApp) {
try {
console.log('WPS application reference cleaned');
} catch (error) {
console.warn('Error cleaning WPS application:', error);
}
this.wpsApp = null;
}
this.activeDocument = null;
this.isConnected = false;
this.documents.clear();
console.log('WPSHelper cleanup completed');
}
}
const wpsHelper = new WPSHelper();
module.exports = { wpsHelper };