const $ = (sel) => document.querySelector(sel); const $$ = (sel) => Array.from(document.querySelectorAll(sel)); const state = { currentId: null, list: [], dirty: false, }; let weEditor = null; function setStatus(text) { const el = $('#status'); el.textContent = text || ''; } function renderList() { const ul = $('#doc-list'); ul.innerHTML = ''; state.list.forEach((d) => { const li = document.createElement('li'); li.className = 'doc-item' + (d.id === state.currentId ? ' active' : ''); li.textContent = d.title || '(未命名)'; li.onclick = () => loadDoc(d.id); ul.appendChild(li); }); } async function fetchJSON(url, opts = {}) { const res = await fetch(url, opts); if (!res.ok) throw new Error('请求失败: ' + res.status); return res.json(); } async function refreshList() { const data = await fetchJSON('api.php?action=list'); state.list = data.docs || []; renderList(); } async function loadDoc(id) { const data = await fetchJSON('api.php?action=get&id=' + encodeURIComponent(id)); state.currentId = data.id; $('#title-input').value = data.title || ''; if (weEditor) weEditor.setHtml(data.content || ''); $('#btn-save').disabled = true; $('#btn-delete').disabled = !state.currentId; renderList(); setStatus('已加载: ' + (data.title || data.id)); } async function saveDoc() { const payload = { id: state.currentId, title: $('#title-input').value.trim(), content: weEditor ? weEditor.getHtml() : $('#we-editor').innerHTML, }; const data = await fetchJSON('api.php?action=save', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }); state.currentId = data.id; $('#btn-save').disabled = true; $('#btn-delete').disabled = !state.currentId; await refreshList(); renderList(); setStatus('已保存: ' + (payload.title || data.id)); } async function deleteDoc() { if (!state.currentId) return; if (!confirm('确定删除当前文档吗?')) return; const data = await fetchJSON('api.php?action=delete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: state.currentId }), }); state.currentId = null; $('#title-input').value = ''; $('#editor').innerHTML = ''; $('#btn-save').disabled = true; $('#btn-delete').disabled = true; await refreshList(); renderList(); setStatus('文档已删除'); } function newDoc() { state.currentId = null; $('#title-input').value = ''; if (weEditor) weEditor.setHtml(''); $('#btn-save').disabled = false; $('#btn-delete').disabled = true; renderList(); setStatus('新建文档'); } function markDirty() { $('#btn-save').disabled = false; } // 由 wangEditor 处理图片上传 function setupEvents() { $('#btn-save').onclick = saveDoc; $('#btn-delete').onclick = deleteDoc; $('#btn-new').onclick = newDoc; $('#title-input').oninput = markDirty; const shareBtn = $('#btn-share'); if (shareBtn) shareBtn.onclick = shareCurrent; const revokeBtn = $('#btn-share-revoke'); if (revokeBtn) revokeBtn.onclick = revokeShares; } async function init() { setupEvents(); // 初始化 wangEditor const { createEditor, createToolbar } = window.wangEditor || {}; if (createEditor && createToolbar) { const editorConfig = { placeholder: '在此编辑内容…' }; editorConfig.onChange = () => markDirty(); // 配置图片上传到后端 editorConfig.MENU_CONF = editorConfig.MENU_CONF || {}; editorConfig.MENU_CONF['uploadImage'] = { server: 'upload.php', fieldName: 'image', maxFileSize: 10 * 1024 * 1024, timeout: 20 * 1000, customInsert(res, insertFn) { if (res && res.url) insertFn(res.url); }, }; weEditor = createEditor({ selector: '#we-editor', config: editorConfig, mode: 'default' }); createToolbar({ editor: weEditor, selector: '#we-toolbar', mode: 'default' }); } await refreshList(); if (state.list.length) { loadDoc(state.list[0].id).catch(console.error); } else { newDoc(); } } async function shareCurrent() { if (!state.currentId) { alert('请先保存文档,再进行分享'); return; } openShareModal(); } init().catch((e) => setStatus('初始化失败: ' + e.message)); function openShareModal() { const overlay = $('#share-modal'); const linkBox = overlay.querySelector('.link-box'); const linkInput = $('#share-link'); const copyBtn = $('#btn-copy-link'); overlay.style.display = 'flex'; overlay.setAttribute('aria-hidden', 'false'); linkBox.style.display = 'none'; const close = () => { overlay.style.display = 'none'; overlay.setAttribute('aria-hidden', 'true'); }; $('#btn-close-share').onclick = close; overlay.querySelectorAll('.options .btn').forEach((btn) => { btn.onclick = async () => { const mode = btn.getAttribute('data-mode'); try { const data = await fetchJSON('api.php?action=share_create&id=' + encodeURIComponent(state.currentId) + '&mode=' + encodeURIComponent(mode)); const url = (data && data.url) ? (location.origin + data.url) : ''; if (!url) throw new Error('未获取到分享链接'); linkInput.value = url; linkBox.style.display = 'flex'; copyBtn.onclick = async () => { try { await navigator.clipboard.writeText(url); showToast('已复制分享链接:', url); } catch (e) { prompt('复制分享链接', url); } }; } catch (e) { alert('生成分享链接失败:' + e.message); } }; }); } function showToast(text, link) { const el = $('#share-toast'); el.innerHTML = link ? (text + '打开') : text; el.style.display = 'block'; setTimeout(() => { el.style.display = 'none'; }, 3000); } async function revokeShares() { if (!state.currentId) { alert('当前没有文档'); return; } if (!confirm('取消该文档的所有分享链接?此操作不可恢复')) return; try { await fetchJSON('api.php?action=share_revoke_all&id=' + encodeURIComponent(state.currentId)); setStatus('已取消所有分享'); showToast('已取消所有分享'); } catch (e) { alert('取消分享失败:' + e.message); } }