AI 功能通用实现模板(基于 MicroEditor)
核心流程
保存当前光标/选区
const savedRange = this.saveSelection();弹出多行输入对话框(自定义 DOM,非
window.prompt)包含
<textarea rows="8">、确定按钮、取消按钮。使用 Promise 等待用户输入。
恢复选区并聚焦编辑器
this.restoreSelection(savedRange);this.editor.focus();(如需要)插入即时反馈提示(临时节点)
使用document.execCommand('insertHTML', false, 临时节点HTML)。发起 AJAX 请求(调用对应的后端 AI 接口,如
/admin/ai/write.php)。移除临时节点,并再次恢复选区。
将返回内容插入编辑器(支持 HTML 格式,可转换换行等)。
同步到隐藏 textarea(
this.syncToTextarea())。
关键函数(已在 MicroEditor 类中实现)
saveSelection()/restoreSelection(saved):保存/恢复光标位置。syncToTextarea():同步编辑器内容到 textarea。editorDiv/editor:编辑器的可编辑 DOM 元素。
后端接口规范
URL:
/admin/ai/{功能名}.php方法:POST
请求体:
{ "prompt": "用户输入的需求" }(可扩展其他参数)响应:
{ "content": "生成的文本或 HTML" }(或error字段)
可复用的 UI 组件
多行输入对话框(样式与配色助手的模态框一致)
即时反馈提示(“🤖 AI 正在创作,请稍候…”)
错误提示(
alert或模态框)
扩展点
增加“重新生成”按钮(复用当前输入,再次请求)
增加“插入并替换选中内容”选项
支持流式输出(SSE)以实时显示生成过程
//添加ai写作助手
// 添加 AI 写作助手(多行输入框,带即时提示)
async aiWriting() {
// 1. 保存当前光标位置
const savedRange = this.saveSelection();
// 2. 创建自定义多行输入对话框
const dialog = document.createElement('div');
dialog.style.cssText = `
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);
z-index: 10000; width: 500px; max-width: 90%;
`;
dialog.innerHTML = `
<h3 style="margin-top:0;">AI 写作助手</h3>
<textarea rows="8" style="width:100%; margin-bottom:10px; padding:8px;"
placeholder="请输入写作需求,例如:写一篇关于公司10周年庆典的新闻稿,500字左右。"></textarea>
<div style="text-align:right;">
<button id="aiDialogOk" style="padding:5px 15px;">生成</button>
<button id="aiDialogCancel" style="padding:5px 15px; margin-left:10px;">取消</button>
</div>
`;
document.body.appendChild(dialog);
const textarea = dialog.querySelector('textarea');
const okBtn = dialog.querySelector('#aiDialogOk');
const cancelBtn = dialog.querySelector('#aiDialogCancel');
// 等待用户输入
const promptText = await new Promise((resolve) => {
const close = (value) => {
dialog.remove();
resolve(value);
};
okBtn.onclick = () => close(textarea.value.trim());
cancelBtn.onclick = () => close(null);
// 点击遮罩关闭
dialog.addEventListener('click', (e) => {
if (e.target === dialog) close(null);
});
});
if (!promptText) return; // 用户取消或未输入
// 3. 恢复保存的选区并聚焦编辑器(关键步骤,确保后续插入位置正确)
this.restoreSelection(savedRange);
if (this.editor) this.editor.focus(); // 假设编辑器 DOM 元素为 this.editor,请根据实际调整
// 4. 在光标位置插入即时提示(临时节点)
const tempId = 'ai-temp-' + Date.now();
const tempHtml = `<span id="${tempId}" style="color:#999;">🤖 AI 正在创作,请稍候...</span>`;
document.execCommand('insertHTML', false, tempHtml);
// 5. 发起 AI 生成请求
try {
const response = await fetch('/admin/ai/write.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt: promptText })
});
const data = await response.json();
// 6. 移除临时提示节点
const tempElem = document.getElementById(tempId);
if (tempElem) tempElem.remove();
// 7. 再次恢复选区(临时节点被移除后原位置保留,恢复后即可插入正式内容)
this.restoreSelection(savedRange);
if (data.content) {
// 将换行符转为 HTML 换行,保持段落格式
const htmlContent = data.content.replace(/\n/g, '<br>');
document.execCommand('insertHTML', false, htmlContent);
} else {
alert(data.error || '生成失败');
}
} catch (err) {
console.error(err);
// 出错时也要移除临时节点并恢复选区
const tempElem = document.getElementById(tempId);
if (tempElem) tempElem.remove();
this.restoreSelection(savedRange);
alert('请求失败:' + err.message);
}
// 8. 同步内容到隐藏 textarea(如果编辑器需要)
this.syncToTextarea();
}
发表评论 (0)
留下你的足迹