重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构 - 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐 - 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作 - 新增管理后台、支付与云端文件 API,更新 README 与项目规范 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* 平台抽象层 - 统一接口定义
|
||||
* 桌面端由 js/platform/electron.js 实现,网页端由 js/platform/web.js 实现。
|
||||
* 业务代码通过 window.platformBridge 或兼容的 window.sysAPI / window.dialog 调用。
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
// 若已存在(由 electron 或 web 注入),则不覆盖
|
||||
if (typeof window.platformBridge !== 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 默认空实现,避免未注入时报错(仅作占位,实际运行前必须注入 electron 或 web 实现)
|
||||
function notImplemented() {
|
||||
console.warn('[platform] bridge not injected');
|
||||
return Promise.reject(new Error('Platform bridge not available'));
|
||||
}
|
||||
|
||||
window.platformBridge = {
|
||||
readHistory: notImplemented,
|
||||
writeHistory: notImplemented,
|
||||
readJsonFile: notImplemented,
|
||||
showOpenDialog: notImplemented,
|
||||
showSaveDialog: notImplemented,
|
||||
writeFile: notImplemented,
|
||||
readFile: notImplemented,
|
||||
getAppVersion: function () { return Promise.resolve('0.0.0'); },
|
||||
getLocale: function () { return 'zh'; },
|
||||
getUserDataPath: function () { return ''; },
|
||||
getSystemFonts: function () { return Promise.resolve([]); },
|
||||
openDesignPage: function () {},
|
||||
openFirstPage: function () {},
|
||||
onClose: function () {},
|
||||
runClose: function () {},
|
||||
openHelp: function () {},
|
||||
printPdf: notImplemented,
|
||||
getScaleRate: function () { return typeof window !== 'undefined' ? (window.devicePixelRatio || 1) : 1; },
|
||||
clipboard: {
|
||||
readText: function () { return Promise.resolve(''); },
|
||||
writeText: function () { return Promise.resolve(); }
|
||||
}
|
||||
};
|
||||
})();
|
||||
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* 平台抽象层 - Electron 实现
|
||||
* 仅在存在 require 且可加载 electron 时使用;封装 IPC、dialog、fs、remote。
|
||||
*/
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
if (typeof require === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var ipcRenderer, dialog, path, fs, remote, clipboard;
|
||||
try {
|
||||
ipcRenderer = require('electron').ipcRenderer;
|
||||
dialog = require('@electron/remote').dialog;
|
||||
path = require('path');
|
||||
fs = require('fs');
|
||||
remote = require('@electron/remote');
|
||||
clipboard = require('electron').clipboard;
|
||||
} catch (e) {
|
||||
console.warn('[platform] Electron modules not available', e);
|
||||
return;
|
||||
}
|
||||
|
||||
var exePath = remote.app.getPath('userData');
|
||||
var historyFilePath = path.join(exePath, 'data.json');
|
||||
|
||||
var bridge = {
|
||||
readHistory: function () {
|
||||
return ipcRenderer.invoke('history:read');
|
||||
},
|
||||
writeHistory: function (data) {
|
||||
return ipcRenderer.invoke('history:write', data);
|
||||
},
|
||||
readJsonFile: function (filePath) {
|
||||
if (!filePath) return Promise.resolve(null);
|
||||
return ipcRenderer.invoke('file:read-json', filePath);
|
||||
},
|
||||
showOpenDialog: function (options) {
|
||||
return dialog.showOpenDialog(options).then(function (result) {
|
||||
return { canceled: result.canceled, filePaths: result.filePaths };
|
||||
});
|
||||
},
|
||||
showSaveDialog: function (options) {
|
||||
return dialog.showSaveDialog(options);
|
||||
},
|
||||
writeFile: function (filePath, content) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var buf = Buffer.isBuffer(content) ? content : (typeof content === 'string' ? Buffer.from(content, 'utf8') : Buffer.from(content));
|
||||
fs.writeFile(filePath, buf, 'utf8', function (err) {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
},
|
||||
writeFileSync: function (filePath, content) {
|
||||
fs.writeFileSync(filePath, content, 'utf8');
|
||||
},
|
||||
readFile: function (filePath) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
fs.readFile(filePath, function (err, data) {
|
||||
if (err) reject(err);
|
||||
else resolve(data);
|
||||
});
|
||||
});
|
||||
},
|
||||
readFileSync: function (filePath) {
|
||||
return fs.readFileSync(filePath);
|
||||
},
|
||||
existsSync: function (p) {
|
||||
return fs.existsSync(p);
|
||||
},
|
||||
getAppVersion: function () {
|
||||
return ipcRenderer.invoke('app:get-version');
|
||||
},
|
||||
getLocale: function () {
|
||||
return remote.app.getLocale();
|
||||
},
|
||||
getUserDataPath: function () {
|
||||
return exePath;
|
||||
},
|
||||
getSystemFonts: function () {
|
||||
return new Promise(function (resolve, reject) {
|
||||
ipcRenderer.once('font-list', function (ev, fonts) {
|
||||
resolve(fonts || []);
|
||||
});
|
||||
ipcRenderer.send('get-sys-fonts');
|
||||
setTimeout(function () {
|
||||
resolve([]);
|
||||
}, 10000);
|
||||
});
|
||||
},
|
||||
openDesignPage: function (file, type) {
|
||||
ipcRenderer.send('open-design-page', file || 'empty', type || '1');
|
||||
},
|
||||
openFirstPage: function () {
|
||||
ipcRenderer.send('open-first-page');
|
||||
},
|
||||
onClose: function (callback) {
|
||||
ipcRenderer.on('close', callback);
|
||||
},
|
||||
runClose: function () {
|
||||
ipcRenderer.send('run-close');
|
||||
},
|
||||
openHelp: function () {
|
||||
ipcRenderer.send('open-help-file');
|
||||
},
|
||||
printPdf: function (urlOrBlob) {
|
||||
ipcRenderer.send('print-pdf', urlOrBlob);
|
||||
},
|
||||
getScaleRate: function () {
|
||||
return typeof window !== 'undefined' && window.devicePixelRatio ? window.devicePixelRatio : 1;
|
||||
},
|
||||
clipboard: {
|
||||
readText: function () {
|
||||
return Promise.resolve(clipboard.readText());
|
||||
},
|
||||
writeText: function (text) {
|
||||
clipboard.writeText(text);
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.platformBridge = bridge;
|
||||
|
||||
// 兼容现有命名
|
||||
window.sysAPI = {
|
||||
readHistory: bridge.readHistory,
|
||||
writeHistory: bridge.writeHistory,
|
||||
readJsonFile: bridge.readJsonFile,
|
||||
getAppVersion: bridge.getAppVersion
|
||||
};
|
||||
window.dialog = {
|
||||
showOpenDialog: bridge.showOpenDialog,
|
||||
showSaveDialog: bridge.showSaveDialog
|
||||
};
|
||||
window.path = path;
|
||||
window.fs = fs;
|
||||
window.remote = remote;
|
||||
window.ipcRenderer = ipcRenderer;
|
||||
window.clipboard = clipboard;
|
||||
window.exePath = exePath;
|
||||
window.fullPath = historyFilePath;
|
||||
})();
|
||||
Reference in New Issue
Block a user