From d744e00c6652c963588f5cfb22131f36e39a35b7 Mon Sep 17 00:00:00 2001
From: jinchao <383321154@qq.com>
Date: Wed, 7 May 2025 16:02:39 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9EQ&A=E9=A1=B5=E9=9D=A2?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Release/database/XNSim.db | Bin 163840 -> 172032 bytes
XNSimHtml/assets/icons/png/question.png | Bin 0 -> 5573 bytes
XNSimHtml/assets/icons/png/question_b.png | Bin 0 -> 6307 bytes
XNSimHtml/components/content-area.js | 3 +
XNSimHtml/components/qa-component.js | 846 ++++++++++++++++++++++
XNSimHtml/components/sub-toolbar.js | 4 +
XNSimHtml/main.html | 9 +
XNSimHtml/routes/qa.js | 102 +++
XNSimHtml/server.js | 5 +-
XNSimHtml/utils/db-utils.js | 207 +++++-
10 files changed, 1174 insertions(+), 2 deletions(-)
create mode 100644 XNSimHtml/assets/icons/png/question.png
create mode 100644 XNSimHtml/assets/icons/png/question_b.png
create mode 100644 XNSimHtml/components/qa-component.js
create mode 100644 XNSimHtml/routes/qa.js
diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db
index 55db87ac3826d3dc3b54d42ac533f20b035b9a11..39e9d65b2e360b65a9bb3c0576b61eb8cab09119 100644
GIT binary patch
delta 1617
zcmcJPUu@e%9LIfe^UsNW6rn{`m~sdqlF}8&aS|3Zp)9$k5vdzFj>cXVvN?>1B^`;Y
zJs^>$n>Hkbv{maeC_-!u4TRP$l&NJ}ftS5(F9@Ux?Gd%vow7AW;sMzw
zpMSsK=Xbx~S9dox#Z3LgoOSn)Q4}>u#%?l9WQ?C13V^ZZo0nc@;W|abdldW&-h=lS
z`q47XvL@OC-kmH|wc
YT?`5SA?v#rMGt%cdO4^D4fy4kw;!}^t5>z|z3Xv}Y1zWATw
zZ3M`xrDA#EVRFFYbiy+fd<6f1Gw{p;mp%a<3_SogD|4Ql$t}+0KsmkG&x2KX?(Fks
zK$?Hn_L^dowx{WR-+bge$BSlzFA
zY}5O+O7ZB?LS^!}n%4?BL&}_1ED^!;rQ?RB8k2EU!AOyli3FC>jsRk!BMJ$~rsM7S
zaS3%(F#B;LDKQAukm2t7PzEb{QZ<*?&^{E)$}*OeoRS>F86`TFMh8Z*j8Rb~P6;0v
zE~>9GSc*^c8LP|f2B*SW{_wGazBTmEpiy>oe+nbrh%8=G1VW9cuY(tAovBerj$}_t
z3U0S3jVnmXrcy(lh$9natx(pGg5MzK$6WbI?d^$5FVB%mfymlvsI5l36%@xK(QHaF
z`m1dj6(dizJMrnt>{2??bnR%HHd;|TR_NK?|0GFQkx+V5lFiNbuQGO-G~-*0
ztpLSjvi;up_&1R3gLlA6v;GTMT)GcNzkG%z=f=X_rr=$89v*^T?oaM^v;GxV6B#Q7
zp(_vwg*wM_>pDPuI1&^h{3|_7qFtwg!CsU<5)3^-wN0W;r$o`9YWm&NS&YQ++c93W
z>R2FPV2@K`cpD{#MT<@e!VZ*3DEWy@qG;AJzkdfz*uI$1mKVSk3a-Gb970>Ox|cMy2Z77BP=0c-2p7pqI3wk~|%YxTVmf9P+>
CxaBSY
delta 587
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
R$b6Rtpo?hp8dJA~{{zPDQ%V2;
literal 0
HcmV?d00001
diff --git a/XNSimHtml/assets/icons/png/question_b.png b/XNSimHtml/assets/icons/png/question_b.png
new file mode 100644
index 0000000000000000000000000000000000000000..c3d7e5b52a4ce5064de5544faa2743052e8c2fc8
GIT binary patch
literal 6307
zcmb7J`9DH8
z+Fd=j>lJMPJ;H0N1C>KOKLLQ#28+3QE5LT$=6t%1W`^=|Tb2*Nw&X;?vUlAf&s7`=
z>~wsRxWfrO(CC0#N9fZ36UbBJX_K7q#S73m5F;KxCNe)2U<&7za7Gg%+Mwpb*Sa}FZuh@eVLMn*wkPkF_wJFZsqeYS%TgVXgkC^W
z^&=o9AxVc~ZBx&V6oXL2QyUr@UW`}Sse)iv9yVl0-UJix3^sW$j*HuneVnGtF(Ryj
z6ji#88bBhF_*PT|h~Vh<^iJ#8V;k&H1gc|*9Ur@f_D}r`^R?KWREn?PWo?e1K1#oL>Fj-7a7-
zml{PDm`75#Hy+vS`#VUn8VCcoSFPfSlC*D_qH3j2#^_L^*97k}d#MIQ>9Jn8%
zQq_fK1N@i<(A^H;Rr~o+psBgB(SN8v?bA`ucWWUS6lKID#WJ;eZu>t(->zXXARYOQfQ6}`?}q7a5wq+u^afG
zq`k%X4!(3}-sm`%Jr3%~1n_*H0QQ~0k{un}xYDT5I1HmV2>9m@e*6QP9r+4kU6M|A
zIl4JDjXf9L`I6Yg4pY6z{^CfA?yg$|(N?IS;bHT?tO}>ETC^juizQ|iDVy)*ag}6%
z;N)4~nSmJgzK-X;cv?)9f%tkL&JmINnJ)DiIFd_L&Hd&yMnUl^#_zFQjHw#-;8jNe
zcB+9ph|0(OVF!3@F9oefy@PqzEC(jD8Y{wAXPh^iD$B0AJQ$FpqdA`9{?5*?jlfyH
zOqWn*z<@4d(Ge0HhhMd8gkg1c2W*?IJt?Ju8qDoDjBFC0a?tFbrGYs~=O_o0-iSrH
zL5zl$!Xckb|h-hj*hu&hDgfxUV6E?CdZ%#4MZJ?+SYKIXI}
zeF59gNE{+F3DRrAgkZd-@iY0*g*D*!qYqlLJG;B}mF6`I!XNxN+d!P00fuo4mLt(Z
z8|ppYmGFX7>Aq_)eSaJO-iw(c>ymzcTn~7bMd3l6&V;CK;Y07WVv#jB!3AYJPF%o2
z^4Wza*9f2DVTqx;@B&5aiQ}TM=^zN8HJxLs%{;3?iRvsLu#CN~B<%!&DEYPCdBC^i
zO&Y7QL=1rJ?KJ*{+97=t1@FhWfYliDtE$Q_7!T*C=N9lc&Z<+C^*FbbHai|RmuCzm
za!GVXKpn*ZC8smbiQ~=thT*hIKRj^+-G}ADi;g6!&w9
ze!9U)jd6<$J~>y5dPeO2nb)7g&CmCD#zua5$p#Z*b}CX}`dTY7sI9K<(G50vX*zYH
z6=>d??H}hwCiqY)e%85jOWL8~?b{HgtbzJ75h_v-RWbJ~LT(%sze2CrJj!(Wd90#~
z8nFEG^=m1W`TJgSee9*R=vt9p2{Bgc_7Ey-pk3ly0JlUm^a`j00?2hmv|k1fou|db
z$TC>Q=PLU-yE@dGCmVuh5XQSn_S7(aHIZy=#U%8mAdGsZgXZY`L8?X?GE)u78We3k
zdaqju;K7}1Za1?T$E1s(>Qt$piZLf#PLs0|f9u}8dsnr-x@yUvcKqdI?!V41c&SuH
zm!tP3>UJ9oP`64r=N@ntZi^&IldXkNZXY@wQV3nny>fJA#k;wUbm}q8bQ`(-?GctO
z7lzFdeY$nRgii}il7W>Tiz#i-Ld=l$@NZ$`>wNKrp65Q$aenbXPV0wkUh34i5qs;a
z2bl+!d_4o_{?Q_iKSz@_ocU0hQ#7;Y)4YPLNs9Q;^7g2Lg2IVszuI&YDz!-p0B9>~
zSq=afgPJ#&1t@6vM{2Svklq7V3|}hArC-$U+zB;DabOYBEFP4G^=4v#ZGt$#
zBgj-dOA+P1)@F`yuoF?)@+l=*ix*$j1KTF7jAE>3Ht@I?7qh(C{45Y6=DU%1r}p}Y
z*?kKaiE{e5()KZzf*Ku1+-s=%_3Ze%J9T}%jkm5y-$jVs=fK|5^K$E%Pa4dIPrm=f
zg)6la?#c=JXP+|m!IszQvKr#LC~0!_l_*-n0)ZwKfG`C)gOnM9W+xoo*U{2{MyEAc
z@^hjltH~kvcY{A5K-x@­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
+ :host {
+ display: block;
+ height: 100%;
+ overflow: auto;
+ padding: 20px;
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
+ background-color: #f5f7fa;
+ --primary-color: #1890ff;
+ --primary-hover: #40a9ff;
+ --danger-color: #ff4d4f;
+ --danger-hover: #ff7875;
+ --success-color: #52c41a;
+ --success-hover: #73d13d;
+ }
+
+ .qa-container {
+ background-color: white;
+ border-radius: 12px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
+ padding: 24px;
+ min-height: calc(100% - 40px);
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .qa-header {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ margin-bottom: 24px;
+ }
+
+ .ask-question-btn {
+ background-color: var(--primary-color);
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 15px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ transition: all 0.3s ease;
+ box-shadow: 0 2px 8px rgba(24, 144, 255, 0.2);
+ }
+
+ .ask-question-btn:hover {
+ background-color: var(--primary-hover);
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3);
+ }
+
+ .qa-item {
+ background-color: white;
+ border-radius: 10px;
+ padding: 20px;
+ box-shadow: 0 2px 12px rgba(0,0,0,0.06);
+ transition: all 0.3s ease;
+ border: 1px solid #eef2f7;
+ }
+
+ .qa-item:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 4px 16px rgba(0,0,0,0.08);
+ }
+
+ .qa-question {
+ font-weight: 600;
+ color: #2c3e50;
+ margin-bottom: 12px;
+ font-size: 18px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .qa-answer {
+ color: #4a5568;
+ line-height: 1.7;
+ margin-top: 15px;
+ padding-top: 15px;
+ border-top: 1px solid #edf2f7;
+ }
+
+ .answer-btn {
+ background-color: var(--primary-color);
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ margin-top: 12px;
+ transition: all 0.3s ease;
+ }
+
+ .answer-btn:hover {
+ background-color: var(--primary-hover);
+ transform: translateY(-1px);
+ }
+
+ .delete-btn {
+ background-color: var(--danger-color);
+ color: white;
+ border: none;
+ padding: 6px 12px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 13px;
+ transition: all 0.3s ease;
+ }
+
+ .delete-btn:hover {
+ background-color: var(--danger-hover);
+ transform: translateY(-1px);
+ }
+
+ .question-meta {
+ font-size: 13px;
+ color: #718096;
+ margin-top: 8px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .form-group input,
+ .form-group textarea {
+ width: 100%;
+ padding: 12px;
+ border: 1px solid #e2e8f0;
+ border-radius: 8px;
+ font-size: 15px;
+ transition: all 0.3s ease;
+ box-sizing: border-box;
+ }
+
+ .form-group input:focus,
+ .form-group textarea:focus {
+ border-color: var(--primary-color);
+ box-shadow: 0 0 0 3px rgba(24, 144, 255, 0.1);
+ outline: none;
+ }
+
+ .form-group textarea {
+ min-height: 120px;
+ max-height: 300px;
+ resize: vertical;
+ }
+
+ .submit-btn {
+ background-color: var(--success-color);
+ color: white;
+ padding: 10px 20px;
+ border-radius: 8px;
+ transition: all 0.3s ease;
+ }
+
+ .submit-btn:hover {
+ background-color: var(--success-hover);
+ transform: translateY(-1px);
+ }
+
+ .cancel-btn {
+ background-color: var(--danger-color);
+ color: white;
+ padding: 10px 20px;
+ border-radius: 8px;
+ transition: all 0.3s ease;
+ }
+
+ .cancel-btn:hover {
+ background-color: var(--danger-hover);
+ transform: translateY(-1px);
+ }
+
+ .qa-content {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .qa-list {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+ }
+
+ .question-form {
+ display: none;
+ background-color: #f8f9fa;
+ border-radius: 8px;
+ padding: 20px;
+ margin-bottom: 20px;
+ }
+
+ .question-form.active {
+ display: block;
+ }
+
+ .form-actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 12px;
+ margin-top: 24px;
+ }
+
+ .form-actions button {
+ padding: 10px 20px;
+ border: none;
+ border-radius: 8px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ outline: none;
+ }
+
+ .form-actions .submit-btn {
+ background-color: var(--primary-color);
+ color: white;
+ }
+
+ .form-actions .submit-btn:hover {
+ background-color: var(--primary-hover);
+ transform: translateY(-1px);
+ }
+
+ .form-actions .cancel-btn {
+ background-color: var(--danger-color);
+ color: white;
+ }
+
+ .form-actions .cancel-btn:hover {
+ background-color: var(--danger-hover);
+ transform: translateY(-1px);
+ }
+
+ .answer-form {
+ display: none;
+ margin-top: 10px;
+ }
+
+ .answer-form.active {
+ display: block;
+ }
+
+ .answer-btn.hidden {
+ display: none;
+ }
+
+ .modal-overlay {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 1000;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .modal-overlay.active {
+ display: flex;
+ }
+
+ .modal-content {
+ background-color: white;
+ border-radius: 12px;
+ padding: 24px;
+ width: 90%;
+ max-width: 500px;
+ max-height: 90vh;
+ overflow-y: auto;
+ position: relative;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .modal-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20px;
+ }
+
+ .modal-title {
+ font-size: 20px;
+ font-weight: 600;
+ color: #2c3e50;
+ }
+
+ .modal-close {
+ background: none;
+ border: none;
+ font-size: 24px;
+ color: #718096;
+ cursor: pointer;
+ padding: 4px;
+ line-height: 1;
+ transition: color 0.3s ease;
+ outline: none;
+ }
+
+ .modal-close:hover {
+ color: var(--primary-color);
+ }
+
+ .question-form {
+ display: block;
+ background-color: transparent;
+ padding: 0;
+ margin: 0;
+ }
+
+ .form-group {
+ margin-bottom: 20px;
+ }
+
+ .form-group label {
+ display: block;
+ margin-bottom: 8px;
+ color: #4a5568;
+ font-weight: 500;
+ }
+
+ .confirm-modal {
+ display: none;
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.5);
+ z-index: 1001;
+ justify-content: center;
+ align-items: center;
+ }
+
+ .confirm-modal.active {
+ display: flex;
+ }
+
+ .confirm-content {
+ background-color: white;
+ border-radius: 12px;
+ padding: 24px;
+ width: 90%;
+ max-width: 400px;
+ position: relative;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
+ }
+
+ .confirm-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #2c3e50;
+ margin-bottom: 16px;
+ }
+
+ .confirm-message {
+ color: #4a5568;
+ margin-bottom: 24px;
+ line-height: 1.5;
+ }
+
+ .confirm-actions {
+ display: flex;
+ justify-content: flex-end;
+ gap: 12px;
+ }
+
+ .confirm-actions button {
+ padding: 8px 16px;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ transition: all 0.3s ease;
+ outline: none;
+ }
+
+ .confirm-actions .confirm-btn {
+ background-color: var(--danger-color);
+ color: white;
+ }
+
+ .confirm-actions .confirm-btn:hover {
+ background-color: var(--danger-hover);
+ }
+
+ .confirm-actions .cancel-btn {
+ background-color: #e2e8f0;
+ color: #4a5568;
+ }
+
+ .confirm-actions .cancel-btn:hover {
+ background-color: #cbd5e0;
+ }
+
+ .pagination {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 30px;
+ gap: 15px;
+ padding: 15px 0;
+ }
+
+ .pagination-btn {
+ padding: 8px 16px;
+ border: 1px solid #ddd;
+ border-radius: 6px;
+ background-color: white;
+ color: #2d3748;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ min-width: 80px;
+ }
+
+ .pagination-btn:hover:not(:disabled) {
+ background-color: #f8f9fa;
+ border-color: var(--primary-color);
+ color: var(--primary-color);
+ }
+
+ .pagination-btn:disabled {
+ background-color: #f8f9fa;
+ color: #a0aec0;
+ cursor: not-allowed;
+ }
+
+ .page-info {
+ color: #4a5568;
+ font-size: 14px;
+ }
+
+
+
+
+
+
+
+
确认删除
+
确定要删除这个内容吗?此操作不可恢复。
+
+
+
+
+
+
+ `;
+ }
+
+ setupEventListeners() {
+ const askQuestionBtn = this.shadowRoot.querySelector('.ask-question-btn');
+ const modal = this.shadowRoot.querySelector('.modal-overlay');
+ const modalClose = this.shadowRoot.querySelector('.modal-close');
+ const cancelBtn = this.shadowRoot.querySelector('.cancel-btn');
+ const submitBtn = this.shadowRoot.querySelector('.submit-btn');
+
+ const closeModal = () => {
+ modal.classList.remove('active');
+ this.shadowRoot.getElementById('questionTitle').value = '';
+ this.shadowRoot.getElementById('questionContent').value = '';
+ };
+
+ askQuestionBtn.addEventListener('click', () => {
+ modal.classList.add('active');
+ });
+
+ modalClose.addEventListener('click', closeModal);
+ cancelBtn.addEventListener('click', closeModal);
+
+ // 点击模态框外部关闭
+ modal.addEventListener('click', (e) => {
+ if (e.target === modal) {
+ closeModal();
+ }
+ });
+
+ submitBtn.addEventListener('click', async () => {
+ const title = this.shadowRoot.getElementById('questionTitle').value.trim();
+ const content = this.shadowRoot.getElementById('questionContent').value.trim();
+
+ if (!title || !content) {
+ alert('请填写完整的问题信息');
+ return;
+ }
+
+ try {
+ const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+ const response = await fetch('/api/qa/questions', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ title,
+ content,
+ userInfo
+ })
+ });
+
+ const data = await response.json();
+ if (data.success) {
+ closeModal();
+ await this.loadQuestions();
+ } else {
+ alert(data.message || '创建问题失败');
+ }
+ } catch (error) {
+ console.error('创建问题失败:', error);
+ alert('创建问题失败,请稍后重试');
+ }
+ });
+ }
+
+ async addAnswer(questionId, content) {
+ try {
+ const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+ const response = await fetch(`/api/qa/questions/${questionId}/answers`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ content,
+ userInfo
+ })
+ });
+
+ const data = await response.json();
+ if (data.success) {
+ await this.loadQuestions();
+ } else {
+ alert(data.message || '添加回答失败');
+ }
+ } catch (error) {
+ console.error('添加回答失败:', error);
+ alert('添加回答失败,请稍后重试');
+ }
+ }
+
+ async deleteQuestion(questionId) {
+ try {
+ const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+ const response = await fetch(`/api/qa/questions/${questionId}`, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ userInfo })
+ });
+
+ const data = await response.json();
+ if (data.success) {
+ await this.loadQuestions();
+ } else {
+ alert(data.message || '删除问题失败');
+ }
+ } catch (error) {
+ console.error('删除问题失败:', error);
+ alert('删除问题失败,请稍后重试');
+ }
+ }
+
+ async deleteAnswer(answerId) {
+ try {
+ const userInfo = JSON.parse(localStorage.getItem('userInfo') || '{}');
+ const response = await fetch(`/api/qa/answers/${answerId}`, {
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({ userInfo })
+ });
+
+ const data = await response.json();
+ if (data.success) {
+ await this.loadQuestions();
+ } else {
+ alert(data.message || '删除回答失败');
+ }
+ } catch (error) {
+ console.error('删除回答失败:', error);
+ alert('删除回答失败,请稍后重试');
+ }
+ }
+
+ showConfirmDialog(type, id) {
+ const modal = this.shadowRoot.querySelector('.confirm-modal');
+ const confirmBtn = modal.querySelector('.confirm-btn');
+ const cancelBtn = modal.querySelector('.cancel-btn');
+ const message = modal.querySelector('.confirm-message');
+
+ message.textContent = type === 'question' ?
+ '确定要删除这个问题吗?此操作不可恢复。' :
+ '确定要删除这个回答吗?此操作不可恢复。';
+
+ const closeModal = () => {
+ modal.classList.remove('active');
+ };
+
+ const handleConfirm = async () => {
+ if (type === 'question') {
+ await this.deleteQuestion(id);
+ } else {
+ await this.deleteAnswer(id);
+ }
+ closeModal();
+ };
+
+ // 移除旧的事件监听器
+ const newConfirmBtn = confirmBtn.cloneNode(true);
+ const newCancelBtn = cancelBtn.cloneNode(true);
+ confirmBtn.parentNode.replaceChild(newConfirmBtn, confirmBtn);
+ cancelBtn.parentNode.replaceChild(newCancelBtn, cancelBtn);
+
+ // 添加新的事件监听器
+ newConfirmBtn.addEventListener('click', handleConfirm);
+ newCancelBtn.addEventListener('click', closeModal);
+
+ modal.classList.add('active');
+ }
+
+ renderQuestions() {
+ const qaList = this.shadowRoot.getElementById('qaList');
+
+ if (this.questions.length === 0) {
+ qaList.innerHTML = '暂无问题
';
+ return;
+ }
+
+ this.totalPages = Math.ceil(this.questions.length / this.pageSize);
+ const startIndex = (this.currentPage - 1) * this.pageSize;
+ const endIndex = Math.min(startIndex + this.pageSize, this.questions.length);
+ const currentPageQuestions = this.questions.slice(startIndex, endIndex);
+
+ qaList.innerHTML = currentPageQuestions.map(question => `
+
+
+ ${question.title}
+
+
+
+ 提问者:${question.author} | 时间:${question.created_at}
+
+
${question.content}
+ ${question.answers.map(answer => `
+
+
${answer.content}
+
+ 回答者:${answer.author} | 时间:${answer.created_at}
+
+
+
+ `).join('')}
+
+
+
+ `).join('');
+
+ // 添加分页
+ const pagination = this.shadowRoot.getElementById('pagination');
+ pagination.innerHTML = `
+
+ 第 ${this.currentPage} 页 / 共 ${this.totalPages} 页
+
+ `;
+
+ // 添加分页按钮事件监听
+ this.addPaginationListeners();
+
+ // 重新绑定回答按钮的事件监听器
+ const answerBtns = qaList.querySelectorAll('.answer-btn');
+ answerBtns.forEach(btn => {
+ btn.addEventListener('click', () => {
+ const questionId = parseInt(btn.dataset.questionId);
+ const answerForm = qaList.querySelector(`.answer-form[data-question-id="${questionId}"]`);
+ answerForm.classList.add('active');
+ });
+ });
+
+ // 绑定回答表单的事件监听器
+ const answerForms = qaList.querySelectorAll('.answer-form');
+ answerForms.forEach(form => {
+ const questionId = parseInt(form.dataset.questionId);
+ const cancelBtn = form.querySelector('.cancel-btn');
+ const submitBtn = form.querySelector('.submit-btn');
+ const textarea = form.querySelector('textarea');
+
+ cancelBtn.addEventListener('click', () => {
+ form.classList.remove('active');
+ textarea.value = '';
+ });
+
+ submitBtn.addEventListener('click', () => {
+ const content = textarea.value.trim();
+ if (!content) {
+ alert('请输入回答内容');
+ return;
+ }
+ this.addAnswer(questionId, content);
+ form.classList.remove('active');
+ textarea.value = '';
+ });
+ });
+ }
+
+ // 添加分页按钮事件监听
+ addPaginationListeners() {
+ const prevButton = this.shadowRoot.getElementById('prevPage');
+ const nextButton = this.shadowRoot.getElementById('nextPage');
+
+ if (prevButton) {
+ prevButton.addEventListener('click', () => {
+ if (this.currentPage > 1) {
+ this.currentPage--;
+ this.renderQuestions();
+ }
+ });
+ }
+
+ if (nextButton) {
+ nextButton.addEventListener('click', () => {
+ if (this.currentPage < this.totalPages) {
+ this.currentPage++;
+ this.renderQuestions();
+ }
+ });
+ }
+ }
+}
+
+customElements.define('qa-component', QAComponent);
\ No newline at end of file
diff --git a/XNSimHtml/components/sub-toolbar.js b/XNSimHtml/components/sub-toolbar.js
index ddfd19b..0bc1a4b 100644
--- a/XNSimHtml/components/sub-toolbar.js
+++ b/XNSimHtml/components/sub-toolbar.js
@@ -166,6 +166,10 @@ class SubToolbar extends HTMLElement {
帮助
+
+

+ Q&A
+
+