mirror of
https://github.com/Wx-2025/ST-Amily2-Chat-Optimisation.git
synced 2026-06-06 08:05:49 +00:00
### 新功能 - **Function Call 填表模式**:在填表设置中新增独立开关,启用后支持通过 OpenAI 兼容接口(DeepSeek / OpenRouter / 各类中转等)直接返回结构化操作列表,绕过 `<Amily2Edit>` 文本解析路径,填表更稳定 - 遇到不支持 `tool_choice` 的接口时自动降级重试 - 对思考模型注入强制调用指令,防止绕过工具直接输出文本 - 全部走 ST 后端代理,修复 CSP 拦截直连外部 URL 的问题 - **主界面新增提示词链编辑器入口**,同时调换了记忆管理与角色世界书的按钮位置 - **规则中心**新增"自动排除用户楼层"选项 ### 修复 - 提示词链按钮点击无响应(改为事件委托方式绑定) - 拖拽组件微抖误触发(加 5px 移动阈值过滤) - 填表检查窗若干问题修复;翰林院(批量回填)修复;防抖逻辑落地 - 角色世界书入口添加使用警告弹窗(强制 10 秒倒计时),提示该功能长期未维护 - ApiProfile `fakeStream` 字段保存丢失问题 - 正文优化默认改为关闭状态 - NGMS / NCCS API 配置槽位标签修正(NGMS→总结,NCCS→填表) - API Profile 面板选择逻辑统一重构,修复多处旧字段覆盖新配置的问题 - 世界书控制参数兼容性修复(排除递归、插入位置、扫描深度等,适配 ST 1.17.0+)
166 lines
4.9 KiB
JavaScript
166 lines
4.9 KiB
JavaScript
export function makeDraggable($element, onClick, storageKey) {
|
|
let isDragging = false;
|
|
let hasDragged = false;
|
|
let startPos = { x: 0, y: 0 };
|
|
let elementStartPos = { x: 0, y: 0 };
|
|
|
|
const getEventCoords = (e) => {
|
|
if (e.touches && e.touches.length > 0) {
|
|
return { x: e.touches[0].clientX, y: e.touches[0].clientY };
|
|
} else if (e.changedTouches && e.changedTouches.length > 0) {
|
|
return { x: e.changedTouches[0].clientX, y: e.changedTouches[0].clientY };
|
|
}
|
|
return { x: e.clientX, y: e.clientY };
|
|
};
|
|
|
|
const keepInBounds = ($elem) => {
|
|
const windowWidth = $(window).width();
|
|
const windowHeight = $(window).height();
|
|
const elemWidth = $elem.outerWidth();
|
|
const elemHeight = $elem.outerHeight();
|
|
|
|
let currentPos = $elem.offset();
|
|
let newLeft = Math.max(0, Math.min(currentPos.left, windowWidth - elemWidth));
|
|
let newTop = Math.max(0, Math.min(currentPos.top, windowHeight - elemHeight));
|
|
|
|
$elem.css({
|
|
left: newLeft + 'px',
|
|
top: newTop + 'px',
|
|
transform: 'none'
|
|
});
|
|
|
|
if (storageKey) {
|
|
localStorage.setItem(storageKey, JSON.stringify({
|
|
left: newLeft + 'px',
|
|
top: newTop + 'px'
|
|
}));
|
|
}
|
|
};
|
|
|
|
const dragStart = (e) => {
|
|
e.preventDefault();
|
|
isDragging = true;
|
|
hasDragged = false;
|
|
|
|
const coords = getEventCoords(e.originalEvent || e);
|
|
startPos = { x: coords.x, y: coords.y };
|
|
|
|
const offset = $element.offset();
|
|
elementStartPos = { x: offset.left, y: offset.top };
|
|
|
|
$element.css({
|
|
'cursor': 'grabbing',
|
|
'transition': 'none'
|
|
});
|
|
|
|
$('body').css({
|
|
'user-select': 'none',
|
|
'-webkit-user-select': 'none',
|
|
'overflow': 'hidden'
|
|
});
|
|
};
|
|
|
|
const DRAG_THRESHOLD = 5;
|
|
|
|
const dragMove = (e) => {
|
|
if (!isDragging) return;
|
|
e.preventDefault();
|
|
if (!hasDragged) {
|
|
const coords = getEventCoords(e.originalEvent || e);
|
|
const dist = Math.abs(coords.x - startPos.x) + Math.abs(coords.y - startPos.y);
|
|
if (dist < DRAG_THRESHOLD) return;
|
|
}
|
|
hasDragged = true;
|
|
|
|
const coords = getEventCoords(e.originalEvent || e);
|
|
const deltaX = coords.x - startPos.x;
|
|
const deltaY = coords.y - startPos.y;
|
|
|
|
let newLeft = elementStartPos.x + deltaX;
|
|
let newTop = elementStartPos.y + deltaY;
|
|
|
|
const windowWidth = $(window).width();
|
|
const windowHeight = $(window).height();
|
|
const elemWidth = $element.outerWidth();
|
|
const elemHeight = $element.outerHeight();
|
|
|
|
newLeft = Math.max(0, Math.min(newLeft, windowWidth - elemWidth));
|
|
newTop = Math.max(0, Math.min(newTop, windowHeight - elemHeight));
|
|
|
|
$element.css({
|
|
left: newLeft + 'px',
|
|
top: newTop + 'px',
|
|
transform: 'none'
|
|
});
|
|
};
|
|
|
|
const dragEnd = (e) => {
|
|
if (!isDragging) return;
|
|
isDragging = false;
|
|
|
|
$element.css({
|
|
'cursor': 'grab',
|
|
'transition': 'transform 0.2s ease, box-shadow 0.2s ease'
|
|
});
|
|
|
|
$('body').css({
|
|
'user-select': 'auto',
|
|
'-webkit-user-select': 'auto',
|
|
'overflow': 'auto'
|
|
});
|
|
|
|
keepInBounds($element);
|
|
|
|
if (!hasDragged && onClick) {
|
|
if (e.type === 'touchend') {
|
|
e.preventDefault();
|
|
setTimeout(onClick, 10);
|
|
} else {
|
|
onClick();
|
|
}
|
|
}
|
|
};
|
|
|
|
$element.on('mousedown', dragStart);
|
|
$element.on('touchstart', dragStart);
|
|
|
|
const namespace = '.draggable' + Date.now();
|
|
$(document).on(`mousemove${namespace}`, dragMove);
|
|
$(document).on(`touchmove${namespace}`, dragMove);
|
|
$(document).on(`mouseup${namespace}`, dragEnd);
|
|
$(document).on(`touchend${namespace}`, dragEnd);
|
|
|
|
$element.on('click', (e) => {
|
|
if (hasDragged) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
}
|
|
});
|
|
|
|
$(window).on(`resize${namespace}`, () => {
|
|
if ($element.length) {
|
|
keepInBounds($element);
|
|
}
|
|
});
|
|
|
|
$element.css({
|
|
'cursor': 'grab',
|
|
'user-select': 'none',
|
|
'-webkit-user-select': 'none'
|
|
});
|
|
|
|
if (storageKey) {
|
|
const savedPos = localStorage.getItem(storageKey);
|
|
if (savedPos) {
|
|
$element.css(JSON.parse(savedPos));
|
|
setTimeout(() => keepInBounds($element), 0);
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
$element.off('mousedown touchstart click');
|
|
$(document).off(namespace);
|
|
$(window).off(namespace);
|
|
};
|
|
}
|