// 消息操作处理模块
import { customAlert, customConfirm } from './modal.js';

export function initMessageActions() {
    document.addEventListener('click', async (e) => {
        // 复制功能
        const btn = e.target.closest('.btn-copy-markdown');
        if (btn) {
            e.stopPropagation();
            const rawContentEl = btn.nextElementSibling;
            if (rawContentEl && rawContentEl.classList.contains('raw-markdown')) {
                const text = rawContentEl.textContent;
                navigator.clipboard.writeText(text).then(() => {
                    const originalHTML = btn.innerHTML;
                    btn.innerHTML = '✅';
                    setTimeout(() => btn.innerHTML = originalHTML, 2000);
                }).catch(async err => {
                    console.error('复制失败:', err);
                    await customAlert('复制失败');
                });
            }
        }
        
        // 删除消息
        const delBtn = e.target.closest('.btn-delete-message');
        if (delBtn) {
            e.stopPropagation();
            const messageEl = delBtn.closest('.message');
            if (!messageEl) return;
            
            const confirmed = await customConfirm('确定要删除这条消息吗?');
            if (!confirmed) return;
            
            const messageId = messageEl.dataset.messageId;
            if (!messageId) {
                await customAlert('无法删除未同步的消息,请刷新页面后重试。');
                return;
            }

            try {
                const res = await fetch(`/AiChat/DeleteMessage?messageId=${messageId}`, {
                    method: 'DELETE'
                });
                const result = await res.json();
                if (result.success) {
                    messageEl.remove();
                } else {
                    await customAlert(result.msg || '删除失败');
                }
            } catch (err) {
                console.error('删除消息失败:', err);
                await customAlert('删除失败: ' + err.message);
            }
        }
    });
}

⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

总体功能

  • 这是一个消息操作处理模块,导出了一个初始化函数 initMessageActions()。调用该函数后,会在文档上添加一个全局点击事件监听器,负责处理“复制 Markdown 原文”和“删除消息”两类交互。

代码逐行功能说明

  1. import 行

    • ./modal.js 导入 customAlertcustomConfirm,用于替代浏览器默认的 alert/confirm(通常是自定义弹窗)。
  2. initMessageActions()

    • 注册 document 的 click 事件(事件委托),在单个监听器中根据点击目标决定执行哪个操作。
  3. 复制功能(复制 Markdown 原文)

    • 查找最近的匹配元素:e.target.closest('.btn-copy-markdown')。如果存在该按钮,说明触发了复制操作。
    • 调用 e.stopPropagation() 阻止事件继续向上传播(避免其它点击处理器也响应)。
    • 获取按钮的下一个兄弟元素 btn.nextElementSibling,并检查其是否具有 raw-markdown 类(假定该元素包含要复制的原始文本)。
    • 读取其 textContent,调用 navigator.clipboard.writeText(text) 将文本写入剪贴板(返回 Promise)。
    • 成功时用简单的视觉反馈:把按钮的 innerHTML 改为 "✅",2 秒后还原为原始内容。
    • 失败时打印错误并调用 customAlert('复制失败') 弹窗提示用户。
  4. 删除消息

    • 查找最近的匹配元素:e.target.closest('.btn-delete-message')。如果存在该按钮,说明触发了删除操作。
    • 调用 e.stopPropagation()
    • 找到包含该按钮的消息容器元素:delBtn.closest('.message')。如果没有找到就直接返回。
    • 弹出自定义确认框 customConfirm('确定要删除这条消息吗?'),用户拒绝则直接返回。
    • 读取消息元素的 data-message-idmessageEl.dataset.messageId),若不存在则提示“无法删除未同步的消息,请刷新页面后重试。”并返回。
    • 使用 fetch 发起 DELETE 请求到 /AiChat/DeleteMessage?messageId=${messageId},等待返回并解析为 JSON。
    • 期待后端返回一个 JSON 对象,包含 success 字段(布尔)和可选的 msg 文本:
      • 如果 result.success 为 true,则从 DOM 中移除该消息元素 messageEl.remove()
      • 否则弹出 customAlert(result.msg || '删除失败')
    • 网络或解析异常时在控制台打印错误并弹出错误信息。

需要的 HTML/DOM 约束(代码假定的结构)

  • 复制按钮:存在类名为 btn-copy-markdown 的元素,其后紧跟一个类名为 raw-markdown 的兄弟元素,且该元素的 textContent 为要复制的文本。
  • 删除按钮:存在类名为 btn-delete-message 的元素,且其祖先中有一个类名为 message 的元素,并且该元素包含 data-message-id 属性用作标识。

涉及的浏览器 API 与行为

  • navigator.clipboard.writeText:异步写剪贴板,某些环境(http vs https、权限)可能受限。
  • Element.closest / nextElementSibling / classList:用于 DOM 查找和判断。
  • fetch:异步网络请求,使用 DELETE 方法并期望 JSON 响应。
  • 自定义弹窗:通过导入的 customAlert/customConfirm 控制用户提示与确认。

可能的注意点与改进建议(可选)

  • clipboard API 在部分浏览器或非安全上下文(非 HTTPS)可能不可用,建议提供回退方案(比如临时 textarea 选中复制)。
  • fetch URL 直接把 messageId 放在查询字符串里,注意编码(可用 encodeURIComponent)。
  • 删除请求没有发送 CSRF token;如果后端需要防 CSRF,需要在请求头或 body 中携带相应 token。
  • 对请求失败的提示信息可以更友好(例如针对网络超时和 4xx/5xx 分别处理)。
  • 使用 innerHTML 修改按钮内容可能带来 XSS 风险或破坏子元素结构,若按钮包含复杂结构可改用 textContent 或专门的状态类来控制样式/图标变更。

如果需要,我可以帮你把这段代码改写为更健壮的版本(添加 clipboard 回退、CSRF 支持、错误级别区分等)。

评论加载中...