collabdocchat 2.5.4 → 2.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -793,7 +793,7 @@
|
|
|
793
793
|
|
|
794
794
|
确定要清除吗?`))return;if(prompt(`请输入群组名称以确认删除:
|
|
795
795
|
|
|
796
|
-
群组名称:`+i.name)!==i.name){alert("❌ 群组名称不匹配,操作已取消");return}try{const j=document.getElementById("clearChatBtn"),C=j.innerHTML;j.innerHTML="⏳ 清除中...",j.disabled=!0;const G=localStorage.getItem("token"),q=await fetch(`http://localhost:
|
|
796
|
+
群组名称:`+i.name)!==i.name){alert("❌ 群组名称不匹配,操作已取消");return}try{const j=document.getElementById("clearChatBtn"),C=j.innerHTML;j.innerHTML="⏳ 清除中...",j.disabled=!0;const G=localStorage.getItem("token"),q=await fetch(`http://localhost:3000/api/messages/group/${i._id}/clear`,{method:"DELETE",headers:{Authorization:`Bearer ${G}`,"Content-Type":"application/json"}});if(!q.ok){const X=await q.json();throw new Error(X.message||"清除失败")}const Y=await q.json();b.innerHTML='<div class="empty-state" style="padding: 40px; text-align: center; color: var(--text-secondary);">✨ 聊天记录已清空</div>',alert(`✅ 成功清除 ${Y.deletedCount||0} 条聊天记录!`),j.innerHTML=C,j.disabled=!1}catch(j){console.error("清除聊天记录失败:",j),alert("❌ 清除失败: "+j.message);const C=document.getElementById("clearChatBtn");C.innerHTML="🗑️ 清除记录",C.disabled=!1}}),document.getElementById("muteAllBtn").addEventListener("click",async()=>{try{const p=!d;d=!!(await a.setMuteAll(i._id,p)).mutedAll,s();const j=document.createElement("div");j.className="notification",j.textContent=d?"已开启全体禁言(成员无法发言)":"已取消全体禁言",b.appendChild(j),b.scrollTop=b.scrollHeight}catch(p){alert("设置失败: "+p.message)}}),document.getElementById("manageMuteBtn").addEventListener("click",async()=>{u=(await a.getGroup(i._id)).group,r=new Set((u.mutedUsers||[]).map(String));const L=document.getElementById("membersList");L.innerHTML=u.members.filter(j=>j._id.toString()!==o).map(j=>{const C=r.has(j._id.toString());return`
|
|
797
797
|
<div style="display: flex; align-items: center; justify-content: space-between; padding: 12px; border-bottom: 1px solid var(--border);">
|
|
798
798
|
<div style="display: flex; align-items: center; gap: 10px;">
|
|
799
799
|
<div class="avatar" style="width: 35px; height: 35px;">${j.username[0].toUpperCase()}</div>
|
|
@@ -813,7 +813,7 @@
|
|
|
813
813
|
<span class="message-time">${new Date(p.timestamp).toLocaleTimeString()}</span>
|
|
814
814
|
</div>
|
|
815
815
|
<div class="message-content" style="${C?"background: linear-gradient(135deg, rgb(99, 102, 241) 0%, rgb(139, 92, 246) 100%); color: white; padding: 16px; border-radius: 12px; box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);":""}">${j}</div>
|
|
816
|
-
`,b.appendChild(L),b.scrollTop=b.scrollHeight}}),e.on("chat_blocked",p=>{if(p.groupId===i._id){const L=document.createElement("div");L.className="notification",L.textContent=p.message||"消息发送失败",b.appendChild(L),b.scrollTop=b.scrollHeight}});const c=()=>{const p=k.value.trim();p&&(e.sendChatMessage(i._id,t.username,p),k.value="")};B.addEventListener("click",c),k.addEventListener("keypress",p=>{p.key==="Enter"&&c()}),document.getElementById("openAIBtn").addEventListener("click",()=>{document.getElementById("aiModal").classList.remove("hidden")}),document.getElementById("closeAIModal").addEventListener("click",()=>{document.getElementById("aiModal").classList.add("hidden")}),document.querySelectorAll(".quick-question-btn").forEach(p=>{p.addEventListener("click",()=>{document.getElementById("aiInputText").value=p.dataset.question,document.getElementById("aiSendBtnModal").click()}),p.addEventListener("mouseenter",L=>{L.target.style.background="var(--primary)",L.target.style.color="white",L.target.style.transform="translateY(-2px)"}),p.addEventListener("mouseleave",L=>{L.target.style.background="var(--bg)",L.target.style.color="inherit",L.target.style.transform="translateY(0)"})});const v=document.getElementById("aiInputText");v.addEventListener("input",()=>{v.style.height="auto",v.style.height=v.scrollHeight+"px"}),v.addEventListener("keydown",p=>{p.key==="Enter"&&!p.shiftKey&&(p.preventDefault(),document.getElementById("aiSendBtnModal").click())}),v.addEventListener("focus",()=>{v.style.borderColor="var(--primary)"}),v.addEventListener("blur",()=>{v.style.borderColor="var(--border)"});const w=document.getElementById("aiSendBtnModal");w.addEventListener("mouseenter",()=>{w.style.transform="scale(1.05)"}),w.addEventListener("mouseleave",()=>{w.style.transform="scale(1)"}),document.getElementById("aiSendBtnModal").addEventListener("click",async()=>{const p=document.getElementById("aiInputText"),L=p.value.trim();if(!L)return;const j=document.getElementById("aiChatMessages"),C=document.createElement("div");C.className="ai-message user",C.style.cssText="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 18px; border-radius: 18px 18px 4px 18px; margin: 10px 0; max-width: 75%; margin-left: auto; text-align: right; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); animation: slideInRight 0.3s ease;",C.textContent=L,j.appendChild(C),p.value="";const G=document.createElement("div");G.className="ai-message ai loading",G.style.cssText="background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",G.textContent="思考中...",j.appendChild(G),j.scrollTop=j.scrollHeight;try{const q=localStorage.getItem("token"),X=await(await fetch("http://localhost:
|
|
816
|
+
`,b.appendChild(L),b.scrollTop=b.scrollHeight}}),e.on("chat_blocked",p=>{if(p.groupId===i._id){const L=document.createElement("div");L.className="notification",L.textContent=p.message||"消息发送失败",b.appendChild(L),b.scrollTop=b.scrollHeight}});const c=()=>{const p=k.value.trim();p&&(e.sendChatMessage(i._id,t.username,p),k.value="")};B.addEventListener("click",c),k.addEventListener("keypress",p=>{p.key==="Enter"&&c()}),document.getElementById("openAIBtn").addEventListener("click",()=>{document.getElementById("aiModal").classList.remove("hidden")}),document.getElementById("closeAIModal").addEventListener("click",()=>{document.getElementById("aiModal").classList.add("hidden")}),document.querySelectorAll(".quick-question-btn").forEach(p=>{p.addEventListener("click",()=>{document.getElementById("aiInputText").value=p.dataset.question,document.getElementById("aiSendBtnModal").click()}),p.addEventListener("mouseenter",L=>{L.target.style.background="var(--primary)",L.target.style.color="white",L.target.style.transform="translateY(-2px)"}),p.addEventListener("mouseleave",L=>{L.target.style.background="var(--bg)",L.target.style.color="inherit",L.target.style.transform="translateY(0)"})});const v=document.getElementById("aiInputText");v.addEventListener("input",()=>{v.style.height="auto",v.style.height=v.scrollHeight+"px"}),v.addEventListener("keydown",p=>{p.key==="Enter"&&!p.shiftKey&&(p.preventDefault(),document.getElementById("aiSendBtnModal").click())}),v.addEventListener("focus",()=>{v.style.borderColor="var(--primary)"}),v.addEventListener("blur",()=>{v.style.borderColor="var(--border)"});const w=document.getElementById("aiSendBtnModal");w.addEventListener("mouseenter",()=>{w.style.transform="scale(1.05)"}),w.addEventListener("mouseleave",()=>{w.style.transform="scale(1)"}),document.getElementById("aiSendBtnModal").addEventListener("click",async()=>{const p=document.getElementById("aiInputText"),L=p.value.trim();if(!L)return;const j=document.getElementById("aiChatMessages"),C=document.createElement("div");C.className="ai-message user",C.style.cssText="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 12px 18px; border-radius: 18px 18px 4px 18px; margin: 10px 0; max-width: 75%; margin-left: auto; text-align: right; box-shadow: 0 2px 8px rgba(102, 126, 234, 0.3); animation: slideInRight 0.3s ease;",C.textContent=L,j.appendChild(C),p.value="";const G=document.createElement("div");G.className="ai-message ai loading",G.style.cssText="background: var(--bg-tertiary); padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",G.textContent="思考中...",j.appendChild(G),j.scrollTop=j.scrollHeight;try{const q=localStorage.getItem("token"),X=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${q}`},body:JSON.stringify({question:L,groupId:i==null?void 0:i._id})})).json();G.remove();const te=document.createElement("div");te.className="ai-message ai",te.style.cssText="background: var(--bg-secondary); padding: 15px 18px; border-radius: 18px 18px 18px 4px; margin: 10px 0; max-width: 75%; border: 1px solid var(--border); box-shadow: 0 2px 4px rgba(0,0,0,0.05); animation: slideInLeft 0.3s ease; line-height: 1.6;",te.textContent=X.answer||"抱歉,我无法回答这个问题。",j.appendChild(te),j.scrollTop=j.scrollHeight}catch(q){G.remove();const Y=document.createElement("div");Y.className="ai-message ai error",Y.style.cssText="background: var(--danger); color: white; padding: 12px 16px; border-radius: 12px; margin: 10px 0; max-width: 70%;",Y.textContent="抱歉,发生了错误: "+q.message,j.appendChild(Y),j.scrollTop=j.scrollHeight}}),window.showImageModal=p=>{const L=document.getElementById("imagePreviewModal"),j=document.getElementById("previewImage"),C=document.getElementById("downloadImageBtn");j.src=p,L.classList.remove("hidden"),C.onclick=async()=>{try{const q=await(await fetch(p)).blob(),Y=window.URL.createObjectURL(q),X=document.createElement("a");X.href=Y,X.download=`whiteboard-${Date.now()}.png`,document.body.appendChild(X),X.click(),document.body.removeChild(X),window.URL.revokeObjectURL(Y)}catch(G){console.error("下载失败:",G),alert("下载失败,请重试")}}},document.getElementById("closeImagePreview").addEventListener("click",()=>{document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("imagePreviewModal").addEventListener("click",p=>{p.target.id==="imagePreviewModal"&&document.getElementById("imagePreviewModal").classList.add("hidden")}),document.getElementById("openWhiteboardBtn").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.remove("hidden"),P()}),document.getElementById("closeWhiteboardModal").addEventListener("click",()=>{document.getElementById("whiteboardModal").classList.add("hidden")});function P(){const p=document.getElementById("whiteboardCanvas");if(!p)return;const L=p.getContext("2d");let j=!1,C="pen",G="#000000",q=3,Y=0,X=0;document.querySelectorAll(".tool-btn").forEach(J=>{J.onclick=()=>{document.querySelectorAll(".tool-btn").forEach(ee=>{ee.style.background="transparent",ee.style.borderColor="var(--border)",ee.style.color="inherit",ee.classList.remove("active")}),J.style.background="var(--primary)",J.style.borderColor="var(--primary)",J.style.color="white",J.classList.add("active"),C=J.dataset.tool}});const te=document.getElementById("colorPickerCanvas");te&&(te.onchange=J=>{G=J.target.value});const ue=document.getElementById("brushSizeCanvas"),ie=document.getElementById("brushSizeLabel");ue&&ie&&(ue.oninput=J=>{q=J.target.value,ie.textContent=`大小: ${q}`}),p.onmousedown=J=>{j=!0;const ee=p.getBoundingClientRect();Y=J.clientX-ee.left,X=J.clientY-ee.top},p.onmousemove=J=>{if(!j)return;const ee=p.getBoundingClientRect(),de=J.clientX-ee.left,ve=J.clientY-ee.top;L.beginPath(),L.moveTo(Y,X),L.lineTo(de,ve),L.strokeStyle=C==="eraser"?"#ffffff":G,L.lineWidth=q,L.lineCap="round",L.stroke(),Y=de,X=ve},p.onmouseup=()=>{j=!1},p.onmouseleave=()=>{j=!1},document.getElementById("clearCanvasBtn").onclick=()=>{confirm("确定要清空画布吗?")&&L.clearRect(0,0,p.width,p.height)},document.getElementById("saveCanvasBtn").onclick=()=>{const J=p.toDataURL("image/png"),ee=document.createElement("a");ee.download=`whiteboard-${Date.now()}.png`,ee.href=J,ee.click(),alert("白板已保存!")},document.getElementById("sendToGroupBtn").onclick=async()=>{try{const J=p.toDataURL("image/png"),ee=await fetch(J).then(Ze=>Ze.blob()),de=new FormData;de.append("file",ee,`whiteboard-${Date.now()}.png`),de.append("groupId",i._id),de.append("description","协作白板作品");const ve=localStorage.getItem("token"),Xe=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${ve}`},body:de});if(Xe.ok){const Mt=`http://localhost:3000/api/files/${(await Xe.json()).file._id}/download?token=${ve}`;e.sendChatMessage(i._id,t.username,`[白板作品]${Mt}`),alert("白板作品已发送到群聊!"),document.getElementById("whiteboardModal").classList.add("hidden")}else throw new Error("上传失败")}catch(J){console.error("发送白板作品错误:",J),alert("发送失败: "+J.message)}}}}async function V(h){if(!i){h.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}h.innerHTML=`
|
|
817
817
|
<div class="view-header">
|
|
818
818
|
<h2>随机点名 - ${i.name}</h2>
|
|
819
819
|
</div>
|
|
@@ -923,7 +923,7 @@
|
|
|
923
923
|
</div>
|
|
924
924
|
`}).join("")}
|
|
925
925
|
</div>
|
|
926
|
-
`;const w=document.getElementById("auditPagination"),P=document.getElementById("pageInfo");P.textContent=`第 ${v.pagination.page} 页,共 ${v.pagination.pages} 页`,document.getElementById("prevPage").disabled=v.pagination.page<=1,document.getElementById("nextPage").disabled=v.pagination.page>=v.pagination.pages,w.style.display=v.pagination.pages>1?"flex":"none"}catch(s){console.error("加载审计日志失败:",s),document.getElementById("auditLogs").innerHTML='<div class="error-state">加载失败: '+s.message+"</div>"}}async function k(){try{const r=new Date,d=new Date(r.getTime()-7*24*60*60*1e3),s=await a.getAuditSummary({startDate:r.toISOString().split("T")[0],endDate:r.toISOString().split("T")[0]}),c=await a.getAuditSummary({startDate:d.toISOString().split("T")[0],endDate:r.toISOString().split("T")[0]});document.getElementById("todayCount").textContent=s.summary.totalLogs,document.getElementById("weekCount").textContent=c.summary.totalLogs,document.getElementById("activeUsers").textContent=c.summary.topUsers.length}catch(r){console.error("加载统计信息失败:",r)}}function B(r){var w,P,p,L,j,C;const d=((w=r.user)==null?void 0:w.username)||"未知用户",s=T(r.action),c=r.resourceTitle||r.resourceId;let v='<strong style="color: #6366f1;">'+d+"</strong> ";switch(r.action){case"document_create":v+='创建了文档 <strong>"'+c+'"</strong>';break;case"document_update":v+='更新了文档 <strong>"'+c+'"</strong>',(P=r.details)!=null&&P.field&&(v+=" 的 <strong>"+y(r.details.field)+"</strong>");break;case"document_delete":v+='删除了文档 <strong>"'+c+'"</strong>';break;case"content_edit":if(v+='编辑了文档 <strong>"'+c+'"</strong> 的内容',r.changes){const G=((p=r.changes.insertions)==null?void 0:p.reduce((Y,X)=>Y+X.length,0))||0,q=((L=r.changes.deletions)==null?void 0:L.reduce((Y,X)=>Y+X.length,0))||0;(G>0||q>0)&&(v+=' (<span style="color: #10b981;">+'+G+'</span> / <span style="color: #ef4444;">-'+q+"</span> 字符)")}break;case"title_edit":v+='修改了文档 <strong>"'+c+'"</strong> 的标题',(j=r.details)!=null&&j.oldValue&&((C=r.details)!=null&&C.newValue)&&(v+=' 从 <strong>"'+r.details.oldValue+'"</strong> 改为 <strong>"'+r.details.newValue+'"</strong>');break;case"document_permission_change":v+='修改了文档 <strong>"'+c+'"</strong> 的权限设置';break;default:v+="执行了 <strong>"+s+"</strong> 操作"}return v}function y(r){return{title:"标题",content:"内容",permissions:"权限",status:"状态",tags:"标签",category:"分类",description:"描述"}[r]||r}function g(r){if(r==null)return'<span style="color: var(--text-tertiary); font-style: italic;">空</span>';if(typeof r=="object")return JSON.stringify(r,null,2);const d=String(r);return d.length>500?d.substring(0,500)+'... <span style="color: var(--text-tertiary); font-style: italic;">(内容过长,已截断)</span>':d.replace(/</g,"<").replace(/>/g,">")}window.showAuditDetail=async r=>{var d,s,c,v,w,P;try{const p=localStorage.getItem("token"),C=(await(await fetch(`http://localhost:
|
|
926
|
+
`;const w=document.getElementById("auditPagination"),P=document.getElementById("pageInfo");P.textContent=`第 ${v.pagination.page} 页,共 ${v.pagination.pages} 页`,document.getElementById("prevPage").disabled=v.pagination.page<=1,document.getElementById("nextPage").disabled=v.pagination.page>=v.pagination.pages,w.style.display=v.pagination.pages>1?"flex":"none"}catch(s){console.error("加载审计日志失败:",s),document.getElementById("auditLogs").innerHTML='<div class="error-state">加载失败: '+s.message+"</div>"}}async function k(){try{const r=new Date,d=new Date(r.getTime()-7*24*60*60*1e3),s=await a.getAuditSummary({startDate:r.toISOString().split("T")[0],endDate:r.toISOString().split("T")[0]}),c=await a.getAuditSummary({startDate:d.toISOString().split("T")[0],endDate:r.toISOString().split("T")[0]});document.getElementById("todayCount").textContent=s.summary.totalLogs,document.getElementById("weekCount").textContent=c.summary.totalLogs,document.getElementById("activeUsers").textContent=c.summary.topUsers.length}catch(r){console.error("加载统计信息失败:",r)}}function B(r){var w,P,p,L,j,C;const d=((w=r.user)==null?void 0:w.username)||"未知用户",s=T(r.action),c=r.resourceTitle||r.resourceId;let v='<strong style="color: #6366f1;">'+d+"</strong> ";switch(r.action){case"document_create":v+='创建了文档 <strong>"'+c+'"</strong>';break;case"document_update":v+='更新了文档 <strong>"'+c+'"</strong>',(P=r.details)!=null&&P.field&&(v+=" 的 <strong>"+y(r.details.field)+"</strong>");break;case"document_delete":v+='删除了文档 <strong>"'+c+'"</strong>';break;case"content_edit":if(v+='编辑了文档 <strong>"'+c+'"</strong> 的内容',r.changes){const G=((p=r.changes.insertions)==null?void 0:p.reduce((Y,X)=>Y+X.length,0))||0,q=((L=r.changes.deletions)==null?void 0:L.reduce((Y,X)=>Y+X.length,0))||0;(G>0||q>0)&&(v+=' (<span style="color: #10b981;">+'+G+'</span> / <span style="color: #ef4444;">-'+q+"</span> 字符)")}break;case"title_edit":v+='修改了文档 <strong>"'+c+'"</strong> 的标题',(j=r.details)!=null&&j.oldValue&&((C=r.details)!=null&&C.newValue)&&(v+=' 从 <strong>"'+r.details.oldValue+'"</strong> 改为 <strong>"'+r.details.newValue+'"</strong>');break;case"document_permission_change":v+='修改了文档 <strong>"'+c+'"</strong> 的权限设置';break;default:v+="执行了 <strong>"+s+"</strong> 操作"}return v}function y(r){return{title:"标题",content:"内容",permissions:"权限",status:"状态",tags:"标签",category:"分类",description:"描述"}[r]||r}function g(r){if(r==null)return'<span style="color: var(--text-tertiary); font-style: italic;">空</span>';if(typeof r=="object")return JSON.stringify(r,null,2);const d=String(r);return d.length>500?d.substring(0,500)+'... <span style="color: var(--text-tertiary); font-style: italic;">(内容过长,已截断)</span>':d.replace(/</g,"<").replace(/>/g,">")}window.showAuditDetail=async r=>{var d,s,c,v,w,P;try{const p=localStorage.getItem("token"),C=(await(await fetch(`http://localhost:3000/api/audit/${r}`,{headers:{Authorization:`Bearer ${p}`}})).json()).log,G=document.getElementById("auditDetailModal"),q=document.getElementById("auditDetailContent"),Y=ue=>({create:"#10b981",update:"#f59e0b",delete:"#ef4444",login:"#6366f1",logout:"#8b5cf6"})[ue]||"#6366f1";q.innerHTML=`
|
|
927
927
|
<div class="audit-detail" style="padding: 0; background: linear-gradient(135deg, rgba(99, 102, 241, 0.03) 0%, rgba(168, 85, 247, 0.03) 100%);">
|
|
928
928
|
|
|
929
929
|
<!-- 操作信息 -->
|
|
@@ -1042,7 +1042,7 @@
|
|
|
1042
1042
|
${r.group?`<span class="result-group">群组: ${r.group}</span>`:""}
|
|
1043
1043
|
${r.status?`<span class="result-status">状态: ${E(r.status)}</span>`:""}
|
|
1044
1044
|
</div>
|
|
1045
|
-
`).join("")}catch(g){b.innerHTML=`<div class="empty-state">搜索失败: ${g.message}</div>`}};u.addEventListener("click",k),m.addEventListener("keypress",B=>{B.key==="Enter"&&k()})}function re(h,m){if(!m)return h;const u=new RegExp(`(${m})`,"gi");return h.replace(u,"<mark>$1</mark>")}function T(h){return{document_create:"创建文档",document_update:"更新文档",document_delete:"删除文档",content_edit:"编辑内容",title_edit:"修改标题",document_permission_change:"权限修改"}[h]||h}function E(h){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[h]||h}async function F(h){var m;if(!i){h.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const u=localStorage.getItem("token"),b=await fetch(`http://localhost:
|
|
1045
|
+
`).join("")}catch(g){b.innerHTML=`<div class="empty-state">搜索失败: ${g.message}</div>`}};u.addEventListener("click",k),m.addEventListener("keypress",B=>{B.key==="Enter"&&k()})}function re(h,m){if(!m)return h;const u=new RegExp(`(${m})`,"gi");return h.replace(u,"<mark>$1</mark>")}function T(h){return{document_create:"创建文档",document_update:"更新文档",document_delete:"删除文档",content_edit:"编辑内容",title_edit:"修改标题",document_permission_change:"权限修改"}[h]||h}function E(h){return{pending:"待处理",in_progress:"进行中",completed:"已完成",terminated:"已终止"}[h]||h}async function F(h){var m;if(!i){h.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const u=localStorage.getItem("token"),b=await fetch(`http://localhost:3000/api/knowledge/group/${i._id}`,{headers:{Authorization:`Bearer ${u}`}});if(!b.ok)throw new Error(`HTTP ${b.status}: ${b.statusText}`);const k=await b.json();console.log("知识库数据:",k);const B=((m=k.data)==null?void 0:m.knowledgeList)||[];console.log("知识库条目数量:",B.length),h.innerHTML=`
|
|
1046
1046
|
<div class="view-header">
|
|
1047
1047
|
<h2>📚 知识库管理 - ${i.name}</h2>
|
|
1048
1048
|
<button class="btn-primary" id="createKnowledgeBtn">➕ 创建知识条目</button>
|
|
@@ -1098,7 +1098,7 @@
|
|
|
1098
1098
|
<button class="btn-secondary btn-sm" data-id="${g._id}" data-action="edit" style="flex: 1;">✏️ 编辑</button>
|
|
1099
1099
|
<button class="btn-danger btn-sm" data-id="${g._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
|
|
1100
1100
|
</div>
|
|
1101
|
-
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="edit"]').forEach(g=>{g.addEventListener("click",async()=>{var d;const r=B.find(s=>s._id===g.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=r.title,document.querySelector('[name="content"]').value=r.content,document.querySelector('[name="tags"]').value=((d=r.tags)==null?void 0:d.join(", "))||"",document.getElementById("isSharedCheckbox").checked=r.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=r._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="download"]').forEach(g=>{g.addEventListener("click",async()=>{try{const r=await fetch(`http://localhost:
|
|
1101
|
+
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="edit"]').forEach(g=>{g.addEventListener("click",async()=>{var d;const r=B.find(s=>s._id===g.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=r.title,document.querySelector('[name="content"]').value=r.content,document.querySelector('[name="tags"]').value=((d=r.tags)==null?void 0:d.join(", "))||"",document.getElementById("isSharedCheckbox").checked=r.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=r._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="download"]').forEach(g=>{g.addEventListener("click",async()=>{try{const r=await fetch(`http://localhost:3000/api/backup/download/${g.dataset.filename}`,{method:"GET",headers:{Authorization:`Bearer ${u}`}});if(!r.ok)throw new Error("下载失败");const d=await r.blob(),s=window.URL.createObjectURL(d),c=document.createElement("a");c.href=s,c.download=g.dataset.filename,document.body.appendChild(c),c.click(),window.URL.revokeObjectURL(s),document.body.removeChild(c)}catch(r){alert("下载失败: "+r.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(g=>{g.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${g.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${u}`}}),alert("删除成功!"),await F(h)}catch(r){alert("删除失败: "+r.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async g=>{g.preventDefault();const r=new FormData(g.target),d={title:r.get("title"),content:r.get("content"),tags:r.get("tags").split(",").map(s=>s.trim()).filter(s=>s),groupId:i._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const s=g.target.dataset.editId,c=s?`http://localhost:3000/api/knowledge/${s}`:"http://localhost:3000/api/knowledge",w=await fetch(c,{method:s?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify(d)});if(!w.ok){const p=await w.json();throw new Error(p.message||"操作失败")}const P=await w.json();console.log("知识库操作结果:",P),alert(s?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await F(h)}catch(s){console.error("知识库操作错误:",s),alert("操作失败: "+s.message)}})}catch(u){h.innerHTML=`<div class="empty-state">加载失败: ${u.message}</div>`}}function x(h){if(!h)return"未设置";if(typeof h=="string")return{document_create:"📄 文档创建时",document_update:"✏️ 文档更新时",document_delete:"🗑️ 文档删除时",task_create:"📋 任务创建时",task_complete:"✅ 任务完成时",task_overdue:"⏰ 任务逾期时",member_join:"👥 成员加入时",group_create:"🏢 群组创建时",scheduled:"⏱️ 定时触发",manual:"🖱️ 手动触发"}[h]||h;const m=[];if(h.event){const u={document_created:"📄 文档创建",document_updated:"✏️ 文档更新",document_deleted:"🗑️ 文档删除",task_created:"📋 任务创建",task_completed:"✅ 任务完成",task_overdue:"⏰ 任务逾期",member_joined:"👥 成员加入",group_created:"🏢 群组创建",message_sent:"💬 消息发送",file_uploaded:"📎 文件上传"};m.push(u[h.event]||h.event)}if(h.conditions&&Object.keys(h.conditions).length>0){const u=[];for(const[b,k]of Object.entries(h.conditions)){const y={group:"群组",user:"用户",keyword:"关键词",status:"状态",priority:"优先级"}[b]||b;u.push(`${y}=${k}`)}u.length>0&&m.push(`(条件: ${u.join(", ")})`)}return h.schedule&&m.push(`⏱️ 定时: ${h.schedule}`),m.length>0?m.join(" "):"自定义触发条件"}async function f(h){var m;if(!i){h.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}try{const u=localStorage.getItem("token"),B=((m=(await(await fetch(`http://localhost:3000/api/workflows/group/${i._id}`,{headers:{Authorization:`Bearer ${u}`}})).json()).data)==null?void 0:m.workflows)||[];h.innerHTML=`
|
|
1102
1102
|
<div class="view-header">
|
|
1103
1103
|
<h2>⚙️ 工作流管理 - ${i.name}</h2>
|
|
1104
1104
|
<button class="btn-primary" id="createWorkflowBtn">➕ 创建工作流</button>
|
|
@@ -1178,7 +1178,7 @@
|
|
|
1178
1178
|
</button>
|
|
1179
1179
|
<button class="btn-danger btn-sm" data-id="${g._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
|
|
1180
1180
|
</div>
|
|
1181
|
-
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="toggle"]').forEach(g=>{g.addEventListener("click",async()=>{try{await fetch(`http://localhost:
|
|
1181
|
+
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="toggle"]').forEach(g=>{g.addEventListener("click",async()=>{try{await fetch(`http://localhost:3000/api/workflows/${g.dataset.id}/toggle`,{method:"POST",headers:{Authorization:`Bearer ${u}`}}),await f(h)}catch(r){alert("操作失败: "+r.message)}})}),document.querySelectorAll('[data-action="delete"]').forEach(g=>{g.addEventListener("click",async()=>{if(confirm("确定要删除这个工作流吗?"))try{await fetch(`http://localhost:3000/api/workflows/${g.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${u}`}}),alert("删除成功!"),await f(h)}catch(r){alert("删除失败: "+r.message)}})})),document.getElementById("createWorkflowBtn").addEventListener("click",()=>{document.getElementById("workflowModal").classList.remove("hidden")}),document.getElementById("closeWorkflowModal").addEventListener("click",()=>{document.getElementById("workflowModal").classList.add("hidden")}),document.getElementById("workflowForm").addEventListener("submit",async g=>{g.preventDefault();const r=new FormData(g.target),d={name:r.get("name"),description:r.get("description"),trigger:r.get("trigger"),groupId:i._id,actions:[]};try{await fetch("http://localhost:3000/api/workflows",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${u}`},body:JSON.stringify(d)}),alert("创建成功!"),document.getElementById("workflowModal").classList.add("hidden"),await f(h)}catch(s){alert("创建失败: "+s.message)}})}catch(u){h.innerHTML=`<div class="empty-state">加载失败: ${u.message}</div>`}}async function M(h){var m;try{const u=localStorage.getItem("token"),B=((m=(await(await fetch("http://localhost:3000/api/backup/list",{headers:{Authorization:`Bearer ${u}`}})).json()).data)==null?void 0:m.backups)||[];h.innerHTML=`
|
|
1182
1182
|
<div class="view-header">
|
|
1183
1183
|
<h2>💾 备份管理</h2>
|
|
1184
1184
|
<button class="btn-primary" id="createBackupBtn">➕ 创建备份</button>
|
|
@@ -1199,7 +1199,7 @@
|
|
|
1199
1199
|
<button class="btn-primary btn-sm" data-backup-name="${g.name}" data-filename="${g.filename}" data-action="download" style="flex: 1;">⬇️ 下载</button>
|
|
1200
1200
|
<button class="btn-danger btn-sm" data-backup-name="${g.name}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
|
|
1201
1201
|
</div>
|
|
1202
|
-
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="download"]').forEach(g=>{g.addEventListener("click",async()=>{try{const r=g.dataset.backupName,d=g.dataset.filename,s=localStorage.getItem("token");console.log("开始下载备份:",{backupName:r,filename:d});const c=await fetch(`http://localhost:
|
|
1202
|
+
`,r.onmouseenter=()=>{r.style.transform="translateY(-4px)",r.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},r.onmouseleave=()=>{r.style.transform="translateY(0)",r.style.boxShadow="none"},y.appendChild(r)}),document.querySelectorAll('[data-action="download"]').forEach(g=>{g.addEventListener("click",async()=>{try{const r=g.dataset.backupName,d=g.dataset.filename,s=localStorage.getItem("token");console.log("开始下载备份:",{backupName:r,filename:d});const c=await fetch(`http://localhost:3000/api/backup/download/${r}`,{method:"GET",headers:{Authorization:`Bearer ${s}`}});if(!c.ok)throw new Error(`下载失败: ${c.status} ${c.statusText}`);const v=await c.blob();console.log("文件下载成功,大小:",v.size,"bytes");const w=window.URL.createObjectURL(v),P=document.createElement("a");P.href=w,P.download=d,P.style.display="none",document.body.appendChild(P),P.click(),setTimeout(()=>{document.body.removeChild(P),window.URL.revokeObjectURL(w)},100);const p=g.textContent;g.textContent="✅ 下载成功",g.disabled=!0,setTimeout(()=>{g.textContent=p,g.disabled=!1},2e3)}catch(r){console.error("下载失败:",r),alert("下载失败: "+r.message),g.textContent="⬇️ 下载",g.disabled=!1}})}),document.querySelectorAll('[data-action="delete"]').forEach(g=>{g.addEventListener("click",async()=>{if(confirm("确定要删除这个备份吗?"))try{const r=g.dataset.backupName;console.log("删除备份:",r);const d=await fetch(`http://localhost:3000/api/backup/${r}`,{method:"DELETE",headers:{Authorization:`Bearer ${u}`}});if(!d.ok)throw new Error(`删除失败: ${d.status}`);alert("删除成功!"),await M(h)}catch(r){console.error("删除失败:",r),alert("删除失败: "+r.message)}})})),document.getElementById("createBackupBtn").addEventListener("click",async()=>{if(confirm("确定要创建新备份吗?这可能需要一些时间。")){const g=document.getElementById("createBackupBtn");g.disabled=!0,g.textContent="⏳ 创建中...";try{await fetch("http://localhost:3000/api/backup/create",{method:"POST",headers:{Authorization:`Bearer ${u}`}}),alert("备份创建成功!"),await M(h)}catch(r){alert("创建失败: "+r.message)}finally{g.disabled=!1,g.textContent="➕ 创建备份"}}})}catch(u){h.innerHTML=`<div class="empty-state">加载失败: ${u.message}</div>`}}async function A(h){h.innerHTML='<div class="empty-state">AI助手功能开发中...</div>'}async function I(h){h.innerHTML=`
|
|
1203
1203
|
<div class="view-header">
|
|
1204
1204
|
<h2>📤 数据导出</h2>
|
|
1205
1205
|
</div>
|
|
@@ -1244,15 +1244,15 @@
|
|
|
1244
1244
|
<div id="historyList">加载中...</div>
|
|
1245
1245
|
</div>
|
|
1246
1246
|
</div>
|
|
1247
|
-
`;try{const m=localStorage.getItem("token"),b=await(await fetch("http://localhost:
|
|
1247
|
+
`;try{const m=localStorage.getItem("token"),b=await(await fetch("http://localhost:3000/api/export/history",{headers:{Authorization:`Bearer ${m}`}})).json(),k=document.getElementById("historyList");b.exports&&b.exports.length>0?k.innerHTML=b.exports.map(B=>`
|
|
1248
1248
|
<div class="export-item" style="display: flex; justify-content: space-between; align-items: center; padding: 15px; background: var(--bg); border-radius: 8px; margin-bottom: 10px;">
|
|
1249
1249
|
<div>
|
|
1250
1250
|
<div style="font-weight: 600; margin-bottom: 5px;">📦 ${B.format.toUpperCase()} 导出</div>
|
|
1251
1251
|
<div style="font-size: 12px; color: var(--text-secondary);">📅 ${new Date(B.createdAt).toLocaleString()}</div>
|
|
1252
1252
|
</div>
|
|
1253
|
-
<a href="http://localhost:
|
|
1253
|
+
<a href="http://localhost:3000/api/export/download/${B.filename}" class="btn-sm btn-primary" download style="text-decoration: none;">⬇️ 下载</a>
|
|
1254
1254
|
</div>
|
|
1255
|
-
`).join(""):k.innerHTML='<div class="empty-state">暂无导出记录</div>'}catch{document.getElementById("historyList").innerHTML='<div class="empty-state">加载失败</div>'}document.getElementById("exportBtn").addEventListener("click",async()=>{const m={groups:document.getElementById("exportGroups").checked,documents:document.getElementById("exportDocuments").checked,tasks:document.getElementById("exportTasks").checked,messages:document.getElementById("exportMessages").checked,files:document.getElementById("exportFiles").checked,format:document.getElementById("exportFormat").value},u=document.getElementById("exportBtn");u.disabled=!0,u.textContent="⏳ 导出中...";try{const b=localStorage.getItem("token"),k=await fetch("http://localhost:
|
|
1255
|
+
`).join(""):k.innerHTML='<div class="empty-state">暂无导出记录</div>'}catch{document.getElementById("historyList").innerHTML='<div class="empty-state">加载失败</div>'}document.getElementById("exportBtn").addEventListener("click",async()=>{const m={groups:document.getElementById("exportGroups").checked,documents:document.getElementById("exportDocuments").checked,tasks:document.getElementById("exportTasks").checked,messages:document.getElementById("exportMessages").checked,files:document.getElementById("exportFiles").checked,format:document.getElementById("exportFormat").value},u=document.getElementById("exportBtn");u.disabled=!0,u.textContent="⏳ 导出中...";try{const b=localStorage.getItem("token"),k=await fetch("http://localhost:3000/api/export",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${b}`},body:JSON.stringify(m)});if(k.ok){const B=await k.blob(),y=window.URL.createObjectURL(B),g=document.createElement("a");g.href=y,g.download=`export-${Date.now()}.${m.format}`,g.click(),alert("导出成功!"),await I(h)}else throw new Error("导出失败")}catch(b){alert("导出失败: "+b.message)}finally{u.disabled=!1,u.textContent="🚀 开始导出"}})}async function z(h){if(!i){h.innerHTML='<div class="empty-state">请先选择一个群组</div>';return}h.innerHTML=`
|
|
1256
1256
|
<div class="view-header">
|
|
1257
1257
|
<h2>🎨 协作白板 - ${i.name}</h2>
|
|
1258
1258
|
<div style="display: flex; gap: 10px;">
|
|
@@ -1891,7 +1891,7 @@
|
|
|
1891
1891
|
前往我的群组
|
|
1892
1892
|
</button>
|
|
1893
1893
|
</div>
|
|
1894
|
-
`;return}try{let h=function(d,s,c="💬"){"Notification"in window&&Notification.permission==="granted"&&new Notification(d,{body:s,icon:"/icon.png",badge:"/icon.png",tag:"chat-message"})},k=function(){const d=document.getElementById("whiteboard");if(!d||d.dataset.initialized)return;d.dataset.initialized="true";const s=d.getContext("2d");d.width=d.offsetWidth,d.height=d.offsetHeight;let c=!1,v="pen",w="#667eea",P=3;document.querySelectorAll(".tool-btn").forEach(p=>{p.addEventListener("click",()=>{v=p.dataset.tool,document.querySelectorAll(".tool-btn").forEach(L=>{L.style.background="var(--bg-secondary)",L.style.color="var(--text-primary)",L.style.border="1px solid var(--border)"}),p.style.background="var(--primary)",p.style.color="white",p.style.border="none"})}),document.getElementById("colorPicker").addEventListener("change",p=>{w=p.target.value}),document.getElementById("brushSize").addEventListener("input",p=>{P=p.target.value}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&(s.clearRect(0,0,d.width,d.height),e.sendWhiteboardClear(i._id))}),document.getElementById("sendWhiteboardBtn").addEventListener("click",async()=>{try{const p=d.toDataURL("image/png"),L=document.createElement("canvas");L.width=d.width,L.height=d.height;const j=L.toDataURL("image/png");if(p===j){alert("画布是空的,请先绘制内容!");return}if(p.length*.75/1024/1024<1)e.sendChatMessage(i._id,t.username,`[白板作品]${p}`),alert("白板作品已发送到群聊!");else{const G=await fetch(p).then(te=>te.blob()),q=new FormData;q.append("file",G,`whiteboard-${Date.now()}.png`),q.append("groupId",i._id),q.append("description","协作白板作品");const Y=localStorage.getItem("token"),X=await fetch("http://localhost:
|
|
1894
|
+
`;return}try{let h=function(d,s,c="💬"){"Notification"in window&&Notification.permission==="granted"&&new Notification(d,{body:s,icon:"/icon.png",badge:"/icon.png",tag:"chat-message"})},k=function(){const d=document.getElementById("whiteboard");if(!d||d.dataset.initialized)return;d.dataset.initialized="true";const s=d.getContext("2d");d.width=d.offsetWidth,d.height=d.offsetHeight;let c=!1,v="pen",w="#667eea",P=3;document.querySelectorAll(".tool-btn").forEach(p=>{p.addEventListener("click",()=>{v=p.dataset.tool,document.querySelectorAll(".tool-btn").forEach(L=>{L.style.background="var(--bg-secondary)",L.style.color="var(--text-primary)",L.style.border="1px solid var(--border)"}),p.style.background="var(--primary)",p.style.color="white",p.style.border="none"})}),document.getElementById("colorPicker").addEventListener("change",p=>{w=p.target.value}),document.getElementById("brushSize").addEventListener("input",p=>{P=p.target.value}),document.getElementById("clearCanvas").addEventListener("click",()=>{confirm("确定要清空画布吗?")&&(s.clearRect(0,0,d.width,d.height),e.sendWhiteboardClear(i._id))}),document.getElementById("sendWhiteboardBtn").addEventListener("click",async()=>{try{const p=d.toDataURL("image/png"),L=document.createElement("canvas");L.width=d.width,L.height=d.height;const j=L.toDataURL("image/png");if(p===j){alert("画布是空的,请先绘制内容!");return}if(p.length*.75/1024/1024<1)e.sendChatMessage(i._id,t.username,`[白板作品]${p}`),alert("白板作品已发送到群聊!");else{const G=await fetch(p).then(te=>te.blob()),q=new FormData;q.append("file",G,`whiteboard-${Date.now()}.png`),q.append("groupId",i._id),q.append("description","协作白板作品");const Y=localStorage.getItem("token"),X=await fetch("http://localhost:3000/api/files/upload",{method:"POST",headers:{Authorization:`Bearer ${Y}`},body:q});if(X.ok){const ie=`http://localhost:3000/api/files/${(await X.json()).file._id}/download?token=${Y}`;e.sendChatMessage(i._id,t.username,`[白板作品]${ie}`),alert("白板作品已发送到群聊!")}else throw new Error("上传失败")}}catch(p){console.error("发送白板失败:",p),alert("发送失败,请重试!")}}),d.addEventListener("mousedown",p=>{c=!0;const L=d.getBoundingClientRect(),j=p.clientX-L.left,C=p.clientY-L.top;s.beginPath(),s.moveTo(j,C)}),d.addEventListener("mousemove",p=>{if(!c)return;const L=d.getBoundingClientRect(),j=p.clientX-L.left,C=p.clientY-L.top;s.lineWidth=P,s.lineCap="round",v==="pen"?(s.strokeStyle=w,s.globalCompositeOperation="source-over"):v==="eraser"&&(s.globalCompositeOperation="destination-out"),s.lineTo(j,C),s.stroke(),e.sendWhiteboardDraw(i._id,{tool:v,color:w,size:P,x:j,y:C})}),d.addEventListener("mouseup",()=>{c=!1}),d.addEventListener("mouseleave",()=>{c=!1}),e.on("whiteboard_draw",p=>{p.groupId===i._id&&(s.lineWidth=p.size,s.lineCap="round",p.tool==="pen"?(s.strokeStyle=p.color,s.globalCompositeOperation="source-over"):p.tool==="eraser"&&(s.globalCompositeOperation="destination-out"),s.lineTo(p.x,p.y),s.stroke())}),e.on("whiteboard_clear",p=>{p.groupId===i._id&&s.clearRect(0,0,d.width,d.height)})};var E=h,F=k;const f=(await a.getGroup(i._id)).group,M=!!f.mutedAll,A=(f.mutedUsers||[]).map(String).includes(String(o)),I=!M&&!A;T.innerHTML=`
|
|
1895
1895
|
<div class="view-header" style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px; margin-bottom: 20px;">
|
|
1896
1896
|
<h2 style="margin: 0; display: flex; align-items: center; gap: 12px;">
|
|
1897
1897
|
<span style="font-size: 32px;">💬</span>
|
|
@@ -1956,7 +1956,7 @@
|
|
|
1956
1956
|
</div>
|
|
1957
1957
|
</div>
|
|
1958
1958
|
<div class="ai-input" style="display: flex; gap: 10px; padding: 16px; background: var(--bg-tertiary); border-top: 1px solid var(--border);">
|
|
1959
|
-
<textarea id="aiInput" placeholder="向AI助手提问..." rows="2" style="flex: 1; padding: 10px 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); resize: none;"></textarea>
|
|
1959
|
+
<textarea id="aiInput" placeholder="向AI助手提问..." rows="2" style="flex: 1; padding: 10px 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); resize: none; color: white;"></textarea>
|
|
1960
1960
|
<button class="btn-primary" id="aiSendBtn" style="padding: 10px 24px; border-radius: 8px; align-self: flex-end;">发送</button>
|
|
1961
1961
|
</div>
|
|
1962
1962
|
</div>
|
|
@@ -2027,7 +2027,7 @@
|
|
|
2027
2027
|
margin-bottom: 16px;
|
|
2028
2028
|
max-width: 80%;
|
|
2029
2029
|
font-style: italic;
|
|
2030
|
-
`,c.textContent="🤔 思考中...",B.appendChild(c),B.scrollTop=B.scrollHeight;try{const v=localStorage.getItem("token"),P=await(await fetch("http://localhost:
|
|
2030
|
+
`,c.textContent="🤔 思考中...",B.appendChild(c),B.scrollTop=B.scrollHeight;try{const v=localStorage.getItem("token"),P=await(await fetch("http://localhost:3000/api/ai/ask",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v}`},body:JSON.stringify({question:d,groupId:i==null?void 0:i._id})})).json();c.remove();const p=document.createElement("div");p.style.cssText=`
|
|
2031
2031
|
background: var(--bg-tertiary);
|
|
2032
2032
|
color: var(--text-primary);
|
|
2033
2033
|
padding: 12px 16px;
|
|
@@ -2092,7 +2092,7 @@
|
|
|
2092
2092
|
前往我的群组
|
|
2093
2093
|
</button>
|
|
2094
2094
|
</div>
|
|
2095
|
-
`;return}try{const E=localStorage.getItem("token"),F=await fetch(`http://localhost:
|
|
2095
|
+
`;return}try{const E=localStorage.getItem("token"),F=await fetch(`http://localhost:3000/api/knowledge/group/${i._id}`,{headers:{Authorization:`Bearer ${E}`}});if(!F.ok)throw new Error(`HTTP ${F.status}: ${F.statusText}`);const x=await F.json();let f=[];Array.isArray(x)?f=x:x.data&&Array.isArray(x.data)?f=x.data:x.data&&x.data.knowledgeList&&Array.isArray(x.data.knowledgeList)?f=x.data.knowledgeList:x.items&&Array.isArray(x.items)?f=x.items:x.knowledge&&Array.isArray(x.knowledge)&&(f=x.knowledge),T.innerHTML=`
|
|
2096
2096
|
<div class="view-header">
|
|
2097
2097
|
<h2>📚 知识库 - ${i.name}</h2>
|
|
2098
2098
|
<button class="btn-primary" id="createKnowledgeBtn">📝 创建知识条目</button>
|
|
@@ -2153,7 +2153,7 @@
|
|
|
2153
2153
|
<button class="btn-secondary btn-sm" data-id="${A._id}" data-action="edit" style="flex: 1;">✏️ 编辑</button>
|
|
2154
2154
|
<button class="btn-danger btn-sm" data-id="${A._id}" data-action="delete" style="flex: 1;">🗑️ 删除</button>
|
|
2155
2155
|
</div>
|
|
2156
|
-
`,I.onmouseenter=()=>{I.style.transform="translateY(-4px)",I.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},I.onmouseleave=()=>{I.style.transform="translateY(0)",I.style.boxShadow="none"},M.appendChild(I)}),document.querySelectorAll('[data-action="edit"]').forEach(A=>{A.addEventListener("click",async()=>{var z;const I=f.find(W=>W._id===A.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=I.title,document.querySelector('[name="content"]').value=I.content,document.querySelector('[name="tags"]').value=((z=I.tags)==null?void 0:z.join(", "))||"",document.getElementById("isSharedCheckbox").checked=I.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=I._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="delete"]').forEach(A=>{A.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:
|
|
2156
|
+
`,I.onmouseenter=()=>{I.style.transform="translateY(-4px)",I.style.boxShadow="0 8px 16px rgba(0,0,0,0.1)"},I.onmouseleave=()=>{I.style.transform="translateY(0)",I.style.boxShadow="none"},M.appendChild(I)}),document.querySelectorAll('[data-action="edit"]').forEach(A=>{A.addEventListener("click",async()=>{var z;const I=f.find(W=>W._id===A.dataset.id);document.getElementById("modalTitle").textContent="编辑知识条目",document.querySelector('[name="title"]').value=I.title,document.querySelector('[name="content"]').value=I.content,document.querySelector('[name="tags"]').value=((z=I.tags)==null?void 0:z.join(", "))||"",document.getElementById("isSharedCheckbox").checked=I.isShared||!1,document.getElementById("knowledgeForm").dataset.editId=I._id,document.getElementById("knowledgeModal").classList.remove("hidden")})}),document.querySelectorAll('[data-action="delete"]').forEach(A=>{A.addEventListener("click",async()=>{if(confirm("确定要删除这个知识条目吗?"))try{await fetch(`http://localhost:3000/api/knowledge/${A.dataset.id}`,{method:"DELETE",headers:{Authorization:`Bearer ${E}`}}),alert("删除成功!"),await re(T)}catch(I){alert("删除失败: "+I.message)}})})),document.getElementById("createKnowledgeBtn").addEventListener("click",()=>{document.getElementById("modalTitle").textContent="创建知识条目",document.getElementById("knowledgeForm").reset(),delete document.getElementById("knowledgeForm").dataset.editId,document.getElementById("knowledgeModal").classList.remove("hidden")}),document.getElementById("closeKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("cancelKnowledgeModal").addEventListener("click",()=>{document.getElementById("knowledgeModal").classList.add("hidden")}),document.getElementById("knowledgeForm").addEventListener("submit",async A=>{A.preventDefault();const I=new FormData(A.target),z={title:I.get("title"),content:I.get("content"),tags:I.get("tags").split(",").map(W=>W.trim()).filter(W=>W),groupId:i._id,isShared:document.getElementById("isSharedCheckbox").checked};try{const W=A.target.dataset.editId,O=W?`http://localhost:3000/api/knowledge/${W}`:"http://localhost:3000/api/knowledge";if(!(await fetch(O,{method:W?"PUT":"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${E}`},body:JSON.stringify(z)})).ok)throw new Error("操作失败");alert(W?"更新成功!":"创建成功!"),document.getElementById("knowledgeModal").classList.add("hidden"),await re(T)}catch(W){alert("操作失败: "+W.message)}})}catch(E){console.error("加载知识库失败:",E),T.innerHTML=`
|
|
2157
2157
|
<div class="view-header">
|
|
2158
2158
|
<h2>📚 知识库 - ${i.name}</h2>
|
|
2159
2159
|
</div>
|
package/dist/index.html
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<title>CollabDocChat - 协作文档聊天平台</title>
|
|
7
7
|
<link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
|
|
8
8
|
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-CNzBYLJL.js"></script>
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/assets/index-D8ZqeoaM.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
package/package.json
CHANGED
|
@@ -1481,7 +1481,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1481
1481
|
btn.disabled = true;
|
|
1482
1482
|
|
|
1483
1483
|
const token = localStorage.getItem('token');
|
|
1484
|
-
const response = await fetch(`http://localhost:
|
|
1484
|
+
const response = await fetch(`http://localhost:3000/api/messages/group/${currentGroup._id}/clear`, {
|
|
1485
1485
|
method: 'DELETE',
|
|
1486
1486
|
headers: {
|
|
1487
1487
|
'Authorization': `Bearer ${token}`,
|
|
@@ -1725,7 +1725,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1725
1725
|
|
|
1726
1726
|
try {
|
|
1727
1727
|
const token = localStorage.getItem('token');
|
|
1728
|
-
const response = await fetch('http://localhost:
|
|
1728
|
+
const response = await fetch('http://localhost:3000/api/ai/ask', {
|
|
1729
1729
|
method: 'POST',
|
|
1730
1730
|
headers: {
|
|
1731
1731
|
'Content-Type': 'application/json',
|
|
@@ -1914,7 +1914,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1914
1914
|
formData.append('description', '协作白板作品');
|
|
1915
1915
|
|
|
1916
1916
|
const token = localStorage.getItem('token');
|
|
1917
|
-
const response = await fetch('http://localhost:
|
|
1917
|
+
const response = await fetch('http://localhost:3000/api/files/upload', {
|
|
1918
1918
|
method: 'POST',
|
|
1919
1919
|
headers: {
|
|
1920
1920
|
'Authorization': `Bearer ${token}`
|
|
@@ -1925,7 +1925,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
1925
1925
|
if (response.ok) {
|
|
1926
1926
|
const result = await response.json();
|
|
1927
1927
|
const fileId = result.file._id;
|
|
1928
|
-
const fileUrl = `http://localhost:
|
|
1928
|
+
const fileUrl = `http://localhost:3000/api/files/${fileId}/download?token=${token}`;
|
|
1929
1929
|
|
|
1930
1930
|
// 发送包含图片的消息到群聊
|
|
1931
1931
|
wsService.sendChatMessage(currentGroup._id, user.username, `[白板作品]${fileUrl}`);
|
|
@@ -2249,7 +2249,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2249
2249
|
window.showAuditDetail = async (logId) => {
|
|
2250
2250
|
try {
|
|
2251
2251
|
const token = localStorage.getItem('token');
|
|
2252
|
-
const response = await fetch(`http://localhost:
|
|
2252
|
+
const response = await fetch(`http://localhost:3000/api/audit/${logId}`, {
|
|
2253
2253
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2254
2254
|
});
|
|
2255
2255
|
const result = await response.json();
|
|
@@ -2702,7 +2702,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2702
2702
|
|
|
2703
2703
|
try {
|
|
2704
2704
|
const token = localStorage.getItem('token');
|
|
2705
|
-
const response = await fetch(`http://localhost:
|
|
2705
|
+
const response = await fetch(`http://localhost:3000/api/knowledge/group/${currentGroup._id}`, {
|
|
2706
2706
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2707
2707
|
});
|
|
2708
2708
|
|
|
@@ -2811,7 +2811,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2811
2811
|
document.querySelectorAll('[data-action="download"]').forEach(btn => {
|
|
2812
2812
|
btn.addEventListener('click', async () => {
|
|
2813
2813
|
try {
|
|
2814
|
-
const response = await fetch(`http://localhost:
|
|
2814
|
+
const response = await fetch(`http://localhost:3000/api/backup/download/${btn.dataset.filename}`, {
|
|
2815
2815
|
method: 'GET',
|
|
2816
2816
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2817
2817
|
});
|
|
@@ -2839,7 +2839,7 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2839
2839
|
btn.addEventListener('click', async () => {
|
|
2840
2840
|
if (confirm('确定要删除这个知识条目吗?')) {
|
|
2841
2841
|
try {
|
|
2842
|
-
await fetch(`http://localhost:
|
|
2842
|
+
await fetch(`http://localhost:3000/api/knowledge/${btn.dataset.id}`, {
|
|
2843
2843
|
method: 'DELETE',
|
|
2844
2844
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2845
2845
|
});
|
|
@@ -2878,8 +2878,8 @@ export function renderAdminDashboard(user, wsService) {
|
|
|
2878
2878
|
try {
|
|
2879
2879
|
const editId = e.target.dataset.editId;
|
|
2880
2880
|
const url = editId
|
|
2881
|
-
? `http://localhost:
|
|
2882
|
-
: 'http://localhost:
|
|
2881
|
+
? `http://localhost:3000/api/knowledge/${editId}`
|
|
2882
|
+
: 'http://localhost:3000/api/knowledge';
|
|
2883
2883
|
const method = editId ? 'PUT' : 'POST';
|
|
2884
2884
|
|
|
2885
2885
|
const response = await fetch(url, {
|
|
@@ -2989,7 +2989,7 @@ async function renderWorkflowView(container) {
|
|
|
2989
2989
|
|
|
2990
2990
|
try {
|
|
2991
2991
|
const token = localStorage.getItem('token');
|
|
2992
|
-
const response = await fetch(`http://localhost:
|
|
2992
|
+
const response = await fetch(`http://localhost:3000/api/workflows/group/${currentGroup._id}`, {
|
|
2993
2993
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
2994
2994
|
});
|
|
2995
2995
|
const result = await response.json();
|
|
@@ -3101,7 +3101,7 @@ async function renderWorkflowView(container) {
|
|
|
3101
3101
|
document.querySelectorAll('[data-action="toggle"]').forEach(btn => {
|
|
3102
3102
|
btn.addEventListener('click', async () => {
|
|
3103
3103
|
try {
|
|
3104
|
-
await fetch(`http://localhost:
|
|
3104
|
+
await fetch(`http://localhost:3000/api/workflows/${btn.dataset.id}/toggle`, {
|
|
3105
3105
|
method: 'POST',
|
|
3106
3106
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3107
3107
|
});
|
|
@@ -3116,7 +3116,7 @@ async function renderWorkflowView(container) {
|
|
|
3116
3116
|
btn.addEventListener('click', async () => {
|
|
3117
3117
|
if (confirm('确定要删除这个工作流吗?')) {
|
|
3118
3118
|
try {
|
|
3119
|
-
await fetch(`http://localhost:
|
|
3119
|
+
await fetch(`http://localhost:3000/api/workflows/${btn.dataset.id}`, {
|
|
3120
3120
|
method: 'DELETE',
|
|
3121
3121
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3122
3122
|
});
|
|
@@ -3150,7 +3150,7 @@ async function renderWorkflowView(container) {
|
|
|
3150
3150
|
};
|
|
3151
3151
|
|
|
3152
3152
|
try {
|
|
3153
|
-
await fetch('http://localhost:
|
|
3153
|
+
await fetch('http://localhost:3000/api/workflows', {
|
|
3154
3154
|
method: 'POST',
|
|
3155
3155
|
headers: {
|
|
3156
3156
|
'Content-Type': 'application/json',
|
|
@@ -3174,7 +3174,7 @@ async function renderWorkflowView(container) {
|
|
|
3174
3174
|
async function renderBackupView(container) {
|
|
3175
3175
|
try {
|
|
3176
3176
|
const token = localStorage.getItem('token');
|
|
3177
|
-
const response = await fetch('http://localhost:
|
|
3177
|
+
const response = await fetch('http://localhost:3000/api/backup/list', {
|
|
3178
3178
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3179
3179
|
});
|
|
3180
3180
|
const result = await response.json();
|
|
@@ -3236,7 +3236,7 @@ async function renderWorkflowView(container) {
|
|
|
3236
3236
|
console.log('开始下载备份:', { backupName, filename });
|
|
3237
3237
|
|
|
3238
3238
|
// 使用 fetch 下载,带 Authorization header
|
|
3239
|
-
const response = await fetch(`http://localhost:
|
|
3239
|
+
const response = await fetch(`http://localhost:3000/api/backup/download/${backupName}`, {
|
|
3240
3240
|
method: 'GET',
|
|
3241
3241
|
headers: {
|
|
3242
3242
|
'Authorization': `Bearer ${token}`
|
|
@@ -3293,7 +3293,7 @@ async function renderWorkflowView(container) {
|
|
|
3293
3293
|
const backupName = btn.dataset.backupName; // 使用 name 而不是 filename
|
|
3294
3294
|
console.log('删除备份:', backupName);
|
|
3295
3295
|
|
|
3296
|
-
const response = await fetch(`http://localhost:
|
|
3296
|
+
const response = await fetch(`http://localhost:3000/api/backup/${backupName}`, {
|
|
3297
3297
|
method: 'DELETE',
|
|
3298
3298
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3299
3299
|
});
|
|
@@ -3319,7 +3319,7 @@ async function renderWorkflowView(container) {
|
|
|
3319
3319
|
btn.disabled = true;
|
|
3320
3320
|
btn.textContent = '⏳ 创建中...';
|
|
3321
3321
|
try {
|
|
3322
|
-
await fetch('http://localhost:
|
|
3322
|
+
await fetch('http://localhost:3000/api/backup/create', {
|
|
3323
3323
|
method: 'POST',
|
|
3324
3324
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3325
3325
|
});
|
|
@@ -3395,7 +3395,7 @@ async function renderWorkflowView(container) {
|
|
|
3395
3395
|
// 加载导出历史
|
|
3396
3396
|
try {
|
|
3397
3397
|
const token = localStorage.getItem('token');
|
|
3398
|
-
const response = await fetch('http://localhost:
|
|
3398
|
+
const response = await fetch('http://localhost:3000/api/export/history', {
|
|
3399
3399
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
3400
3400
|
});
|
|
3401
3401
|
const result = await response.json();
|
|
@@ -3408,7 +3408,7 @@ async function renderWorkflowView(container) {
|
|
|
3408
3408
|
<div style="font-weight: 600; margin-bottom: 5px;">📦 ${exp.format.toUpperCase()} 导出</div>
|
|
3409
3409
|
<div style="font-size: 12px; color: var(--text-secondary);">📅 ${new Date(exp.createdAt).toLocaleString()}</div>
|
|
3410
3410
|
</div>
|
|
3411
|
-
<a href="http://localhost:
|
|
3411
|
+
<a href="http://localhost:3000/api/export/download/${exp.filename}" class="btn-sm btn-primary" download style="text-decoration: none;">⬇️ 下载</a>
|
|
3412
3412
|
</div>
|
|
3413
3413
|
`).join('');
|
|
3414
3414
|
} else {
|
|
@@ -3434,7 +3434,7 @@ async function renderWorkflowView(container) {
|
|
|
3434
3434
|
|
|
3435
3435
|
try {
|
|
3436
3436
|
const token = localStorage.getItem('token');
|
|
3437
|
-
const response = await fetch('http://localhost:
|
|
3437
|
+
const response = await fetch('http://localhost:3000/api/export', {
|
|
3438
3438
|
method: 'POST',
|
|
3439
3439
|
headers: {
|
|
3440
3440
|
'Content-Type': 'application/json',
|
|
@@ -968,7 +968,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
968
968
|
</div>
|
|
969
969
|
</div>
|
|
970
970
|
<div class="ai-input" style="display: flex; gap: 10px; padding: 16px; background: var(--bg-tertiary); border-top: 1px solid var(--border);">
|
|
971
|
-
<textarea id="aiInput" placeholder="向AI助手提问..." rows="2" style="flex: 1; padding: 10px 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); resize: none;"></textarea>
|
|
971
|
+
<textarea id="aiInput" placeholder="向AI助手提问..." rows="2" style="flex: 1; padding: 10px 16px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg-primary); resize: none; color: white;"></textarea>
|
|
972
972
|
<button class="btn-primary" id="aiSendBtn" style="padding: 10px 24px; border-radius: 8px; align-self: flex-end;">发送</button>
|
|
973
973
|
</div>
|
|
974
974
|
</div>
|
|
@@ -1294,7 +1294,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1294
1294
|
formData.append('description', '协作白板作品');
|
|
1295
1295
|
|
|
1296
1296
|
const token = localStorage.getItem('token');
|
|
1297
|
-
const response = await fetch('http://localhost:
|
|
1297
|
+
const response = await fetch('http://localhost:3000/api/files/upload', {
|
|
1298
1298
|
method: 'POST',
|
|
1299
1299
|
headers: {
|
|
1300
1300
|
'Authorization': `Bearer ${token}`
|
|
@@ -1305,7 +1305,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1305
1305
|
if (response.ok) {
|
|
1306
1306
|
const result = await response.json();
|
|
1307
1307
|
const fileId = result.file._id;
|
|
1308
|
-
const fileUrl = `http://localhost:
|
|
1308
|
+
const fileUrl = `http://localhost:3000/api/files/${fileId}/download?token=${token}`;
|
|
1309
1309
|
|
|
1310
1310
|
// 发送包含图片链接的消息到群聊
|
|
1311
1311
|
wsService.sendChatMessage(currentGroup._id, user.username, `[白板作品]${fileUrl}`);
|
|
@@ -1437,7 +1437,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1437
1437
|
|
|
1438
1438
|
try {
|
|
1439
1439
|
const token = localStorage.getItem('token');
|
|
1440
|
-
const response = await fetch('http://localhost:
|
|
1440
|
+
const response = await fetch('http://localhost:3000/api/ai/ask', {
|
|
1441
1441
|
method: 'POST',
|
|
1442
1442
|
headers: {
|
|
1443
1443
|
'Content-Type': 'application/json',
|
|
@@ -1692,7 +1692,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1692
1692
|
|
|
1693
1693
|
try {
|
|
1694
1694
|
const token = localStorage.getItem('token');
|
|
1695
|
-
const response = await fetch(`http://localhost:
|
|
1695
|
+
const response = await fetch(`http://localhost:3000/api/knowledge/group/${currentGroup._id}`, {
|
|
1696
1696
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
1697
1697
|
});
|
|
1698
1698
|
|
|
@@ -1819,7 +1819,7 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1819
1819
|
btn.addEventListener('click', async () => {
|
|
1820
1820
|
if (confirm('确定要删除这个知识条目吗?')) {
|
|
1821
1821
|
try {
|
|
1822
|
-
await fetch(`http://localhost:
|
|
1822
|
+
await fetch(`http://localhost:3000/api/knowledge/${btn.dataset.id}`, {
|
|
1823
1823
|
method: 'DELETE',
|
|
1824
1824
|
headers: { 'Authorization': `Bearer ${token}` }
|
|
1825
1825
|
});
|
|
@@ -1865,8 +1865,8 @@ export function renderUserDashboard(user, wsService) {
|
|
|
1865
1865
|
try {
|
|
1866
1866
|
const editId = e.target.dataset.editId;
|
|
1867
1867
|
const url = editId
|
|
1868
|
-
? `http://localhost:
|
|
1869
|
-
: 'http://localhost:
|
|
1868
|
+
? `http://localhost:3000/api/knowledge/${editId}`
|
|
1869
|
+
: 'http://localhost:3000/api/knowledge';
|
|
1870
1870
|
const method = editId ? 'PUT' : 'POST';
|
|
1871
1871
|
|
|
1872
1872
|
const response = await fetch(url, {
|