mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 06:55:51 +00:00
ci: auto build & obfuscate [2026-05-16 19:16:28] (Jenkins #21)
This commit is contained in:
98
core/table-system/infra/persistence.js
Normal file
98
core/table-system/infra/persistence.js
Normal file
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* @file ITablePersistence 实现 —— 表格状态的持久化层。
|
||||
*
|
||||
* 替代 manager.js 中:
|
||||
* - saveStateToMessage(state, targetMessage) → 写入指定消息的 extra
|
||||
* - 16 处复制样板(getContext + saveStateToMessage + saveChat / saveChatDebounced)
|
||||
* 被合并为 commitToLastMessage / commitToLastMessageAsync 两个函数
|
||||
*
|
||||
* 不读取 store;调用方显式传入要持久化的 state。这样:
|
||||
* - 测试容易(不依赖全局单例)
|
||||
* - 万一未来需要在事务边界提交"快照"而非当前 state,接口已就位
|
||||
*
|
||||
* @typedef {import('../dto/Table.js').TableState} TableState
|
||||
*/
|
||||
|
||||
import { saveChat } from '/script.js';
|
||||
import { getContext } from '/scripts/extensions.js';
|
||||
import { saveChatDebounced } from '../../../utils/utils.js';
|
||||
import { log } from '../logger.js';
|
||||
|
||||
/**
|
||||
* message.extra 中存储表格状态的 key。
|
||||
* 此值不能轻易改 —— 所有历史聊天的存档都用这个 key。
|
||||
*/
|
||||
export const TABLE_DATA_KEY = 'amily2_tables_data';
|
||||
|
||||
/**
|
||||
* 把状态深拷贝写入指定消息的 metadata。
|
||||
* 不主动调用 saveChat —— 写盘时机由调用方决定。
|
||||
*
|
||||
* @param {TableState | null} stateToSave
|
||||
* @param {Object} targetMessage
|
||||
* @returns {boolean} 是否写入成功
|
||||
*/
|
||||
export function saveStateToMessage(stateToSave, targetMessage) {
|
||||
if (!stateToSave || !targetMessage) {
|
||||
log('缺少状态或目标消息,无法保存。', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!targetMessage.extra) {
|
||||
targetMessage.extra = {};
|
||||
}
|
||||
|
||||
targetMessage.extra[TABLE_DATA_KEY] = JSON.parse(JSON.stringify(stateToSave));
|
||||
log(`表格状态已准备写入消息 [${targetMessage.mes.substring(0, 20)}...]`, 'info');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把 state 提交到 chat 最新一条消息并立即 saveChat。
|
||||
*
|
||||
* 该函数封装了 manager.js 中复制了 16 次的样板:
|
||||
* const context = getContext();
|
||||
* if (context.chat && context.chat.length > 0) {
|
||||
* const lastMessage = context.chat[context.chat.length - 1];
|
||||
* if (saveStateToMessage(state, lastMessage)) {
|
||||
* saveChat();
|
||||
* return;
|
||||
* }
|
||||
* }
|
||||
* saveChatDebounced();
|
||||
*
|
||||
* @param {TableState | null} state
|
||||
* @returns {boolean} true = 走 last-message commit 路径;false = 降级到 debounced
|
||||
*/
|
||||
export function commitToLastMessage(state) {
|
||||
const context = getContext();
|
||||
if (context.chat && context.chat.length > 0) {
|
||||
const lastMessage = context.chat[context.chat.length - 1];
|
||||
if (saveStateToMessage(state, lastMessage)) {
|
||||
saveChat();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
saveChatDebounced();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* commitToLastMessage 的 async 变体。
|
||||
* deleteRow / restoreRow / rollbackState 等需要等 saveChat 完成后才做后续渲染的场景使用。
|
||||
*
|
||||
* @param {TableState | null} state
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export async function commitToLastMessageAsync(state) {
|
||||
const context = getContext();
|
||||
if (context.chat && context.chat.length > 0) {
|
||||
const lastMessage = context.chat[context.chat.length - 1];
|
||||
if (saveStateToMessage(state, lastMessage)) {
|
||||
await saveChat();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
await saveChatDebounced();
|
||||
return false;
|
||||
}
|
||||
117
core/table-system/infra/store.js
Normal file
117
core/table-system/infra/store.js
Normal file
@@ -0,0 +1,117 @@
|
||||
/**
|
||||
* @file ITableStore 实现 —— 表格运行时状态的唯一所有者。
|
||||
*
|
||||
* 替代 manager.js 中三个 module-level 可变量:
|
||||
* currentTablesState → 通过 getState/setState 访问
|
||||
* highlightedCells → addHighlight/getHighlights/clearHighlights
|
||||
* updatedTables → markTableUpdated/getUpdatedTables/clearUpdatedTables
|
||||
*
|
||||
* 本模块只承担"存",不触发任何副作用(不保存、不渲染、不发事件总线消息)。
|
||||
* 副作用编排留给 Service 层 / Action 层。
|
||||
*
|
||||
* setState 会触发 subscribe 注册的回调,给 UI / SuperMemory 一个钩子,
|
||||
* 但不直接 import UI(保持 domain 纯度)。
|
||||
*
|
||||
* @typedef {import('../dto/Table.js').TableState} TableState
|
||||
*/
|
||||
|
||||
import { log } from '../logger.js';
|
||||
|
||||
/** @type {TableState | null} */
|
||||
let _state = null;
|
||||
|
||||
/** @type {Set<string>} 形如 "tableIndex-rowIndex-colIndex" */
|
||||
const _highlights = new Set();
|
||||
|
||||
/** @type {Set<number>} 标记本周期内被改过的表格索引 */
|
||||
const _updatedTables = new Set();
|
||||
|
||||
/** @type {Set<(state: TableState | null) => void>} */
|
||||
const _listeners = new Set();
|
||||
|
||||
// ── 主状态 ────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @returns {TableState | null}
|
||||
*/
|
||||
export function getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接替换全局状态。注意:不做深拷贝,调用方需自己负责传入的 state 不被外部 mutate。
|
||||
* @param {TableState | null} newState
|
||||
*/
|
||||
export function setState(newState) {
|
||||
_state = newState;
|
||||
_notify();
|
||||
}
|
||||
|
||||
/**
|
||||
* 订阅 setState 触发的变更通知。返回取消订阅函数。
|
||||
* 仅在 setState 被调用时触发;mutate 同一引用不会触发。
|
||||
* @param {(state: TableState | null) => void} listener
|
||||
* @returns {() => void}
|
||||
*/
|
||||
export function subscribe(listener) {
|
||||
_listeners.add(listener);
|
||||
return () => _listeners.delete(listener);
|
||||
}
|
||||
|
||||
function _notify() {
|
||||
for (const l of _listeners) {
|
||||
try {
|
||||
l(_state);
|
||||
} catch (e) {
|
||||
console.error('[TableStore] listener error:', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 单元格高亮 ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @param {number} tableIndex
|
||||
* @param {number} rowIndex
|
||||
* @param {number} colIndex
|
||||
*/
|
||||
export function addHighlight(tableIndex, rowIndex, colIndex) {
|
||||
_highlights.add(`${tableIndex}-${rowIndex}-${colIndex}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Set<string>}
|
||||
*/
|
||||
export function getHighlights() {
|
||||
return _highlights;
|
||||
}
|
||||
|
||||
export function clearHighlights() {
|
||||
if (_highlights.size > 0) {
|
||||
_highlights.clear();
|
||||
log('已清除所有单元格高亮标记。', 'info');
|
||||
}
|
||||
}
|
||||
|
||||
// ── 更新过的表格标记 ───────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* @param {number} tableIndex
|
||||
*/
|
||||
export function markTableUpdated(tableIndex) {
|
||||
_updatedTables.add(tableIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Set<number>}
|
||||
*/
|
||||
export function getUpdatedTables() {
|
||||
return _updatedTables;
|
||||
}
|
||||
|
||||
export function clearUpdatedTables() {
|
||||
if (_updatedTables.size > 0) {
|
||||
_updatedTables.clear();
|
||||
log('已清除所有表格的更新标记。', 'info');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user