// 简单版本的论坛编辑器,确保图片插入功能正常 const { createApp, ref, computed, onMounted, nextTick, onUnmounted } = Vue; const { headTop } = await import(withVer("../component/head-top/head-top.js")); const { createEditor, createToolbar, SlateTransforms, Boot, SlateEditor } = window.wangEditor; class MyButtonMenu { // JS 语法 constructor() { this.title = "居中"; // 自定义菜单标题 this.tag = "button"; } // 获取菜单执行时的 value ,用不到则返回空 字符串或 false getValue(editor) { return " hello "; } // 菜单是否需要激活(如选中加粗文本,“加粗”菜单会激活),用不到则返回 false isActive(editor) { if (editor.getFragment()?.[0]?.textAlign == "center") return true; return false; } // 菜单是否需要禁用(如选中 H1 ,“引用”菜单被禁用),用不到则返回 false isDisabled(editor) { return false; } // 点击菜单时触发的函数 exec(editor, value) { let align = this.isActive(editor) ? "left" : "center"; SlateTransforms.setNodes(editor, { textAlign: align, }); } } const editApp = createApp({ setup() { let titleLength = ref(200); let uniqid = ref(""); const valueA = ref(null); let valueUrl = ""; onMounted(() => { const params = getUrlParams(); uniqid.value = params.uniqid || ""; getUserInfoWin(); checkWConfig(); cUpload(); // console.log(valueA.value); valueUrl = valueA.value.innerText; if (location.hostname == "127.0.0.1") { realname.value = 1; userInfoWin.value = { uin: 1234567890, uid: 1234567890, realname: "测试用户", }; isLogin.value = true; } }); let imageLength = 10; let videoLength = 5; const checkWConfig = () => { const wConfig = JSON.parse(localStorage.getItem("wConfig")) || {}; if (wConfig.time) { const time = new Date(wConfig.time); const now = new Date(); if (now - time > 24 * 60 * 60 * 1000) getWConfig(); else { const config = wConfig.config || {}; titleLength.value = config.max_topic_title_length; imageLength = config.topic_image_count || 0; videoLength = config.topic_video_count || 0; } } else getWConfig(); }; const getWConfig = () => { ajaxGet("/v2/api/config/website").then((res) => { if (res.code == 200) { let data = res["data"] || {}; const config = data.config || {}; titleLength.value = config.max_topic_title_length; imageLength = config.topic_image_count || 0; videoLength = config.topic_video_count || 0; data.time = new Date().toISOString(); localStorage.setItem("wConfig", JSON.stringify(data)); } }); }; let isLogin = ref(false); let realname = ref(0); // 是否已经实名 let userInfoWin = ref({}); let permissions = ref([]); const getUserInfoWin = () => { const checkUser = () => { const user = window.userInfoWin; if (!user) return; document.removeEventListener("getUser", checkUser); realname.value = user.realname; userInfoWin.value = user; if (user?.uin > 0 || user?.uid > 0) isLogin.value = true; permissions.value = user?.authority || []; }; document.addEventListener("getUser", checkUser); }; const openAttest = () => { const handleAttestClose = () => { document.removeEventListener("closeAttest", handleAttestClose); realname.value = window.userInfoWin?.realname || 0; }; // 启动认证流程时添加监听 document.addEventListener("closeAttest", handleAttestClose); loadAttest(2); }; // 跳转登录 const goLogin = () => { if (typeof window === "undefined") return; if (window["userInfoWin"] && Object.keys(window["userInfoWin"]).length !== 0) { if (window["userInfoWin"]["uid"]) isLogin.value = true; else ajax_login(); } else ajax_login(); }; let uConfigData = {}; const cUpload = () => { ajaxGet(`/v2/api/config/upload?type=topic`).then((res) => { const data = res.data; uConfigData = data; init(); }); }; let info = ref({}); let tagList = ref([]); let token = ref(""); const init = () => { ajax("/v2/api/forum/postPublishInit", { uniqid: uniqid.value, }) .then((res) => { const data = res.data; if (res.code != 200) { creationAlertBox("error", res.message || "操作失败"); return; } const infoTarget = data.info || {}; // if (location.hostname == "127.0.0.1") // infoTarget.content = `
表情`;
const link = toolbarRef.value.querySelector('[data-menu-key="insertLink"]');
const linkItem = link.parentElement;
linkItem.classList.add("toolbar-item", "flexacenter");
link.innerHTML = `html = html.replace(/\[p\]([\s\S]*?)\[\/p\]/gi, "
$1
"); // 0. 基础清理:换行符转/g, "
"); html = html.replace(//g, "
");
html = html.replace(/<\/p>
/g, "
$1
'); // 定义图片处理函数 const processImg = (aid, width, height, href) => { const image = imageList.find((img) => String(img.aid) === String(aid)); if (!image) return ""; // 移除已使用的图片 const index = imageList.findIndex((img) => String(img.aid) === String(aid)); if (index > -1) imageList.splice(index, 1); let style = ""; const formatStyleVal = (val) => { if (!val) return null; if (String(val).endsWith('%')) return val; const num = Number(val); return num > 0 ? `${num}px` : null; }; const wStyle = formatStyleVal(width); const hStyle = formatStyleVal(height); let styleParts = []; if (wStyle) styleParts.push(`width: ${wStyle}`); if (hStyle) styleParts.push(`height: ${hStyle}`); if (styleParts.length > 0) style = `style="${styleParts.join('; ')};"`; let dataHref = href ? ` data-href="${href}"` : ""; return `]*>([\s\S]*?)<\/p>/gi, "[p]$1[/p]");
// 3. 处理加粗 [b] (对应 strong, b)
html = html.replace(/<(strong|b)[^>]*>([\s\S]*?)<\/\1>/gi, "[b]$2[/b]");
// 4. 处理图片 [img]
html = html.replace(/]*>/gi, (imgTag) => {
let aid = "";
// 尝试从 src 中获取 aid
const srcMatch = imgTag.match(/src="([^"]+)"/i);
if (srcMatch) {
const aidMatch = srcMatch[1].match(/[?&]aid=(\d+)/);
if (aidMatch) aid = aidMatch[1];
}
// 尝试从 data-aid 中获取 aid
if (!aid) {
const dataAid = imgTag.match(/data-aid="(\d+)"/i);
if (dataAid) aid = dataAid[1];
}
if (!aid) return ""; // 无法获取 aid,跳过
// 获取宽高 (支持 px 和 %)
let w = 0,
h = 0;
const styleMatch = imgTag.match(/style="([^"]+)"/i);
if (styleMatch) {
// 匹配数字+单位 (px或%)
const wMatch = styleMatch[1].match(/width:\s*([\d.]+(?:px|%)?)/i);
const hMatch = styleMatch[1].match(/height:\s*([\d.]+(?:px|%)?)/i);
if (wMatch) {
// 如果是百分比,直接保留字符串;如果是纯数字默认视为 px;如果是 px 去掉单位
let val = wMatch[1];
if (val.endsWith('%')) w = val; // 保留百分比字符串
else w = parseFloat(val); // 转为数字 (px)
}
if (hMatch) {
let val = hMatch[1];
if (val.endsWith('%')) h = val;
else h = parseFloat(val);
}
}
// 兼容 width/height 属性 (通常只有数字)
if (!w) {
const wAttr = imgTag.match(/\swidth="(\d+)"/i);
if (wAttr) w = Number(wAttr[1]);
}
if (!h) {
const hAttr = imgTag.match(/\sheight="(\d+)"/i);
if (hAttr) h = Number(hAttr[1]);
}
let result = "";
if (w || h) { // 只要有一个有值
const formatVal = (val) => {
if (typeof val === 'string' && val.endsWith('%')) return val;
return val ? parseFloat(Number(val).toFixed(2)) : 0;
};
result = `[img=${formatVal(w)},${formatVal(h)}]${aid}[/img]`;
} else {
result = `[img]${aid}[/img]`;
}
// 处理 data-href,包裹在 [url] 中
const hrefMatch = imgTag.match(/data-href="([^"]+)"/i);
if (hrefMatch && hrefMatch[1]) {
result = `[url=${hrefMatch[1]}]${result}[/url]`;
}
return result;
});
// 5. 处理视频 [attach]
html = html.replace(/