灵越智报_完整交互版.html 157 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>灵越智报 - 智能报告生成平台</title>
  7. <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;600;700&display=swap" rel="stylesheet">
  8. <style>
  9. :root {
  10. --primary: #1890ff;
  11. --primary-dark: #096dd9;
  12. --primary-light: #e6f7ff;
  13. --primary-gradient: linear-gradient(135deg, #1890ff 0%, #096dd9 100%);
  14. --white: #ffffff;
  15. --bg: #f5f7fa;
  16. --border: #e8e8e8;
  17. --text1: #262626;
  18. --text2: #595959;
  19. --text3: #8c8c8c;
  20. --success: #52c41a;
  21. --warning: #faad14;
  22. --danger: #ff4d4f;
  23. --ai-gradient: linear-gradient(135deg, #1890ff 0%, #722ed1 100%);
  24. --data-gradient: linear-gradient(135deg, #52c41a 0%, #13c2c2 100%);
  25. }
  26. * { margin: 0; padding: 0; box-sizing: border-box; }
  27. body { font-family: 'Noto Sans SC', sans-serif; background: var(--bg); color: var(--text1); font-size: 14px; line-height: 1.6; height: 100vh; overflow: hidden; }
  28. /* 全局头部 */
  29. .header { position: fixed; top: 0; left: 0; right: 0; height: 56px; background: var(--white); border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; padding: 0 20px; z-index: 1000; }
  30. .header-left { display: flex; align-items: center; gap: 20px; }
  31. .logo { display: flex; align-items: center; gap: 8px; font-size: 17px; font-weight: 600; color: var(--primary); cursor: pointer; }
  32. .logo-icon { width: 32px; height: 32px; background: var(--primary-gradient); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: white; font-size: 18px; }
  33. .search-box { position: relative; width: 320px; }
  34. .search-input { width: 100%; height: 36px; padding: 0 14px 0 36px; border: 1px solid var(--border); border-radius: 18px; font-size: 13px; background: var(--bg); outline: none; transition: all 0.2s; }
  35. .search-input:focus { background: var(--white); border-color: var(--primary); }
  36. .search-icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--text3); }
  37. .header-right { display: flex; align-items: center; gap: 10px; }
  38. .hd-btn { position: relative; width: 36px; height: 36px; border: none; background: transparent; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; color: var(--text2); transition: all 0.2s; }
  39. .hd-btn:hover { background: var(--bg); color: var(--primary); }
  40. .badge { position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; background: var(--danger); color: white; border-radius: 8px; font-size: 10px; display: flex; align-items: center; justify-content: center; }
  41. .user-menu { display: flex; align-items: center; gap: 6px; padding: 4px 8px 4px 4px; border-radius: 20px; cursor: pointer; }
  42. .user-menu:hover { background: var(--bg); }
  43. .avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--primary-gradient); color: white; display: flex; align-items: center; justify-content: center; font-weight: 600; font-size: 12px; }
  44. .user-name { font-size: 13px; font-weight: 500; }
  45. /* 侧边栏 */
  46. .sidebar { position: fixed; top: 56px; left: 0; width: 200px; height: calc(100vh - 56px); background: var(--white); border-right: 1px solid var(--border); display: flex; flex-direction: column; transition: width 0.3s; z-index: 900; }
  47. .sidebar.hidden { display: none; }
  48. .sidebar-menu { flex: 1; padding: 10px; overflow-y: auto; }
  49. .menu-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border-radius: 8px; cursor: pointer; transition: all 0.2s; margin-bottom: 2px; position: relative; }
  50. .menu-item:hover { background: var(--primary-light); color: var(--primary); }
  51. .menu-item.active { background: var(--primary-light); color: var(--primary); }
  52. .menu-item.active::before { content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 3px; height: 18px; background: var(--primary); border-radius: 0 2px 2px 0; }
  53. .menu-icon { font-size: 16px; }
  54. .menu-text { font-size: 13px; font-weight: 500; }
  55. .menu-badge { min-width: 18px; height: 18px; padding: 0 5px; background: var(--primary); color: white; border-radius: 9px; font-size: 10px; display: flex; align-items: center; justify-content: center; }
  56. .menu-divider { height: 1px; background: var(--border); margin: 10px 0; }
  57. /* 主内容 */
  58. .main { margin-left: 200px; margin-top: 56px; height: calc(100vh - 56px); overflow-y: auto; }
  59. .page { display: none; padding: 20px; }
  60. .page.active { display: block; }
  61. /* 通用组件 */
  62. .card { background: var(--white); border-radius: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
  63. .btn { display: inline-flex; align-items: center; gap: 4px; padding: 7px 14px; border: 1px solid var(--border); background: var(--white); border-radius: 6px; cursor: pointer; font-size: 12px; transition: all 0.2s; }
  64. .btn:hover { border-color: var(--primary); color: var(--primary); }
  65. .btn-primary { background: var(--primary-gradient); color: white; border: none; }
  66. .btn-primary:hover { box-shadow: 0 4px 12px rgba(24,144,255,0.4); }
  67. /* 首页样式 */
  68. .welcome h1 { font-size: 24px; font-weight: 600; margin-bottom: 4px; }
  69. .welcome h1 span { background: var(--ai-gradient); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
  70. .welcome p { color: var(--text2); }
  71. .stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin: 20px 0; }
  72. .stat-card { padding: 18px; cursor: pointer; transition: all 0.3s; }
  73. .stat-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0,0,0,0.1); }
  74. .stat-icon { width: 40px; height: 40px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 20px; margin-bottom: 10px; }
  75. .stat-icon.blue { background: linear-gradient(135deg, #e6f7ff, #bae7ff); }
  76. .stat-icon.purple { background: linear-gradient(135deg, #f9f0ff, #efdbff); }
  77. .stat-icon.green { background: linear-gradient(135deg, #f6ffed, #d9f7be); }
  78. .stat-icon.orange { background: linear-gradient(135deg, #fff7e6, #ffe7ba); }
  79. .stat-value { font-size: 26px; font-weight: 700; }
  80. .stat-label { font-size: 13px; color: var(--text2); margin-bottom: 6px; }
  81. .stat-trend { font-size: 12px; }
  82. .stat-trend.up { color: var(--success); }
  83. /* AI对话入口 */
  84. .ai-card { padding: 20px; margin-bottom: 20px; }
  85. .ai-welcome { background: linear-gradient(135deg, #f0f7ff, #f5f0ff); border-radius: 10px; padding: 16px; margin-bottom: 16px; }
  86. .ai-avatar { width: 44px; height: 44px; background: var(--ai-gradient); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 22px; margin-bottom: 10px; }
  87. .ai-title { font-size: 14px; font-weight: 600; margin-bottom: 8px; }
  88. .ai-list { list-style: none; margin-bottom: 10px; }
  89. .ai-list li { color: var(--text2); padding: 3px 0; font-size: 13px; }
  90. .ai-list li::before { content: '•'; color: var(--primary); margin-right: 8px; }
  91. .ai-tip { font-size: 12px; color: var(--text3); padding: 8px 12px; background: rgba(255,255,255,0.7); border-radius: 6px; border-left: 3px solid var(--primary); }
  92. .ai-input-wrap { position: relative; margin-bottom: 14px; }
  93. .ai-input { width: 100%; height: 46px; padding: 0 100px 0 18px; border: 2px solid var(--border); border-radius: 23px; font-size: 14px; outline: none; transition: all 0.3s; }
  94. .ai-input:focus { border-color: var(--primary); }
  95. .ai-input-btns { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: flex; gap: 4px; }
  96. .ai-input-btn { width: 32px; height: 32px; border: none; background: transparent; border-radius: 50%; cursor: pointer; font-size: 16px; color: var(--text3); }
  97. .ai-input-btn:hover { background: var(--bg); color: var(--primary); }
  98. .ai-input-btn.send { background: var(--primary-gradient); color: white; display: none; }
  99. .ai-input-btn.send.show { display: flex; align-items: center; justify-content: center; }
  100. .thinking-modes { display: flex; gap: 8px; flex-wrap: wrap; }
  101. .mode-btn { padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 18px; font-size: 12px; cursor: pointer; }
  102. .mode-btn:hover { border-color: var(--primary); background: var(--primary-light); }
  103. .mode-btn.active { background: var(--primary-light); border-color: var(--primary); color: var(--primary); }
  104. /* 模板区 */
  105. .section-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 14px; }
  106. .section-title { font-size: 15px; font-weight: 600; }
  107. .section-link { font-size: 13px; color: var(--primary); cursor: pointer; }
  108. .tpl-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 14px; }
  109. .tpl-card { overflow: hidden; cursor: pointer; transition: all 0.3s; }
  110. .tpl-card:hover { transform: translateY(-4px); box-shadow: 0 8px 20px rgba(0,0,0,0.1); }
  111. .tpl-preview { height: 100px; background: linear-gradient(135deg, #f5f7fa, #e8ecf0); display: flex; align-items: center; justify-content: center; font-size: 36px; }
  112. .tpl-info { padding: 14px; }
  113. .tpl-name { font-weight: 600; margin-bottom: 6px; }
  114. .tpl-meta { display: flex; gap: 12px; font-size: 11px; color: var(--text3); margin-bottom: 10px; }
  115. .tpl-tags { display: flex; gap: 4px; margin-bottom: 10px; }
  116. .tpl-tag { padding: 2px 6px; background: var(--primary-light); color: var(--primary); border-radius: 3px; font-size: 10px; }
  117. .tpl-tag.hot { background: #fff1f0; color: var(--danger); }
  118. .tpl-btn { width: 100%; padding: 8px; background: var(--primary-gradient); color: white; border: none; border-radius: 6px; font-size: 12px; cursor: pointer; }
  119. .quick-actions { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
  120. .quick-action { display: flex; align-items: center; gap: 12px; padding: 16px; border: 2px dashed var(--border); border-radius: 10px; cursor: pointer; }
  121. .quick-action:hover { border-color: var(--primary); background: var(--primary-light); }
  122. .quick-action-icon { width: 40px; height: 40px; background: var(--bg); border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 20px; }
  123. </style>
  124. </head>
  125. <body>
  126. <!-- 头部 -->
  127. <header class="header" id="mainHeader">
  128. <div class="header-left">
  129. <div class="logo" onclick="goHome()">
  130. <div class="logo-icon">📊</div>
  131. <span>灵越智报</span>
  132. </div>
  133. <div class="search-box">
  134. <span class="search-icon">🔍</span>
  135. <input type="text" class="search-input" placeholder="搜索报告、模板...">
  136. </div>
  137. </div>
  138. <div class="header-right">
  139. <button class="hd-btn" onclick="toggleNotif()">🔔<span class="badge">3</span></button>
  140. <div class="user-menu" onclick="showToast('个人中心', 'info')">
  141. <div class="avatar">张</div>
  142. <span class="user-name">张三</span>
  143. </div>
  144. </div>
  145. </header>
  146. <!-- 侧边栏 -->
  147. <aside class="sidebar" id="sidebar">
  148. <nav class="sidebar-menu">
  149. <div class="menu-item active" data-page="home" onclick="navTo('home')">
  150. <span class="menu-icon">🏠</span>
  151. <span class="menu-text">首页</span>
  152. </div>
  153. <div class="menu-item" onclick="openEditor()">
  154. <span class="menu-icon">➕</span>
  155. <span class="menu-text">新建报告</span>
  156. </div>
  157. <div class="menu-item" data-page="reports" onclick="navTo('reports')">
  158. <span class="menu-icon">📋</span>
  159. <span class="menu-text">报告记录</span>
  160. <span class="menu-badge">12</span>
  161. </div>
  162. <div class="menu-item" data-page="templates" onclick="navTo('templates')">
  163. <span class="menu-icon">🎨</span>
  164. <span class="menu-text">模板管理</span>
  165. </div>
  166. <div class="menu-item" data-page="datasources" onclick="navTo('datasources')">
  167. <span class="menu-icon">🔗</span>
  168. <span class="menu-text">数据源</span>
  169. </div>
  170. <div class="menu-divider"></div>
  171. <div class="menu-item" onclick="showToast('帮助中心', 'info')">
  172. <span class="menu-icon">❓</span>
  173. <span class="menu-text">帮助中心</span>
  174. </div>
  175. </nav>
  176. </aside>
  177. <!-- 主内容区 -->
  178. <main class="main" id="mainContent">
  179. <!-- 首页 -->
  180. <div class="page active" id="page-home">
  181. <div class="welcome">
  182. <h1>早上好,张三!<span>智能报告,洞察未来。</span></h1>
  183. <p>今天是个创作的好日子,开始您的智能报告之旅吧</p>
  184. </div>
  185. <div class="stats-grid">
  186. <div class="stat-card card" onclick="navTo('reports')">
  187. <div class="stat-icon blue">📄</div>
  188. <div class="stat-value">12</div>
  189. <div class="stat-label">我的报告</div>
  190. <div class="stat-trend up">↑ 3 本周新增</div>
  191. </div>
  192. <div class="stat-card card" onclick="navTo('templates')">
  193. <div class="stat-icon purple">🎨</div>
  194. <div class="stat-value">15</div>
  195. <div class="stat-label">可用模板</div>
  196. <div class="stat-trend up">↑ 2 新增</div>
  197. </div>
  198. <div class="stat-card card">
  199. <div class="stat-icon green">📚</div>
  200. <div class="stat-value">48</div>
  201. <div class="stat-label">知识文档</div>
  202. <div class="stat-trend">📁 1.2GB</div>
  203. </div>
  204. <div class="stat-card card" onclick="toggleFab()">
  205. <div class="stat-icon orange">💰</div>
  206. <div class="stat-value">¥127.50</div>
  207. <div class="stat-label">本月消耗</div>
  208. <div class="stat-trend">↓ 12%</div>
  209. </div>
  210. </div>
  211. <div class="ai-card card">
  212. <div class="ai-welcome">
  213. <div class="ai-avatar">🤖</div>
  214. <div class="ai-title">你好!我是灵越AI助手,可以帮你:</div>
  215. <ul class="ai-list">
  216. <li>快速生成各类报告</li>
  217. <li>分析和解读数据</li>
  218. <li>回答业务相关问题</li>
  219. </ul>
  220. <div class="ai-tip">试试输入:"帮我生成一份智慧园区建设项目可行性研究报告"</div>
  221. </div>
  222. <div class="ai-input-wrap">
  223. <input type="text" class="ai-input" placeholder="输入您的需求,或 @知识库 引用资料..." id="homeAiInput" oninput="toggleSendBtn()">
  224. <div class="ai-input-btns">
  225. <button class="ai-input-btn">🎤</button>
  226. <button class="ai-input-btn">📎</button>
  227. <button class="ai-input-btn send" id="homeSendBtn" onclick="handleHomeAi()">➤</button>
  228. </div>
  229. </div>
  230. <div class="thinking-modes">
  231. <div class="mode-btn active" onclick="setMode(this)">🧠 深度思考</div>
  232. <div class="mode-btn" onclick="setMode(this)">⚡ 快速回答</div>
  233. <div class="mode-btn" onclick="setMode(this)">🌐 联网搜索</div>
  234. <div class="mode-btn" onclick="setMode(this)">📊 数据分析</div>
  235. </div>
  236. </div>
  237. <div class="section-header">
  238. <h2 class="section-title">📋 推荐模板</h2>
  239. <span class="section-link" onclick="navTo('templates')">查看全部 →</span>
  240. </div>
  241. <div class="tpl-grid">
  242. <div class="tpl-card card" onclick="openEditor()">
  243. <div class="tpl-preview">📊</div>
  244. <div class="tpl-info">
  245. <div class="tpl-name">市场分析报告</div>
  246. <div class="tpl-meta"><span>📊 128次</span><span>⭐ 4.8</span></div>
  247. <div class="tpl-tags"><span class="tpl-tag">官方</span><span class="tpl-tag hot">热门</span></div>
  248. <button class="tpl-btn">使用此模板</button>
  249. </div>
  250. </div>
  251. <div class="tpl-card card" onclick="openEditor()">
  252. <div class="tpl-preview">🏢</div>
  253. <div class="tpl-info">
  254. <div class="tpl-name">可行性研究报告</div>
  255. <div class="tpl-meta"><span>📊 96次</span><span>⭐ 4.9</span></div>
  256. <div class="tpl-tags"><span class="tpl-tag">官方</span><span class="tpl-tag hot">热门</span></div>
  257. <button class="tpl-btn">使用此模板</button>
  258. </div>
  259. </div>
  260. <div class="tpl-card card" onclick="openEditor()">
  261. <div class="tpl-preview">📅</div>
  262. <div class="tpl-info">
  263. <div class="tpl-name">项目周报</div>
  264. <div class="tpl-meta"><span>📊 256次</span><span>⭐ 4.9</span></div>
  265. <div class="tpl-tags"><span class="tpl-tag">官方</span></div>
  266. <button class="tpl-btn">使用此模板</button>
  267. </div>
  268. </div>
  269. </div>
  270. <div class="quick-actions">
  271. <div class="quick-action" onclick="showToast('上传模板', 'info')">
  272. <div class="quick-action-icon">📤</div>
  273. <span>上传新模板</span>
  274. </div>
  275. <div class="quick-action" onclick="showToast('创建模板', 'info')">
  276. <div class="quick-action-icon">🛠️</div>
  277. <span>创建新模板</span>
  278. </div>
  279. </div>
  280. </div>
  281. <!-- 报告记录页 -->
  282. <div class="page" id="page-reports">
  283. <h2 style="margin-bottom:16px">📋 报告记录</h2>
  284. <div style="display:flex;gap:12px;margin-bottom:16px;">
  285. <select style="padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:13px;background:var(--white);"><option>全部状态</option><option>初稿</option><option>审核中</option><option>已定稿</option></select>
  286. <input type="text" placeholder="🔍 搜索报告..." style="flex:1;max-width:280px;padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:13px;">
  287. <div style="margin-left:auto;display:flex;gap:6px;">
  288. <button class="btn" style="background:var(--primary-light);border-color:var(--primary);color:var(--primary)">全部</button>
  289. <button class="btn">本周</button>
  290. <button class="btn">本月</button>
  291. </div>
  292. </div>
  293. <div style="display:flex;flex-direction:column;gap:12px;">
  294. <div class="card" style="padding:18px;">
  295. <div style="display:flex;align-items:center;gap:12px;margin-bottom:10px;">
  296. <span style="font-size:22px;">📄</span>
  297. <span style="flex:1;font-size:15px;font-weight:600;">智慧园区建设项目可行性研究报告</span>
  298. <span style="padding:4px 10px;background:#f6ffed;color:var(--success);border-radius:12px;font-size:11px;">已定稿</span>
  299. </div>
  300. <div style="display:flex;gap:20px;font-size:12px;color:var(--text2);margin-bottom:12px;">
  301. <span>📅 2025-12-30</span><span>👤 张三</span><span>🏢 华南事业部</span>
  302. </div>
  303. <div style="display:flex;gap:8px;">
  304. <button class="btn btn-primary" onclick="openEditor()">查看</button>
  305. <button class="btn" onclick="openEditor()">编辑</button>
  306. <button class="btn" onclick="showToast('导出PDF成功', 'success')">导出</button>
  307. </div>
  308. </div>
  309. <div class="card" style="padding:18px;">
  310. <div style="display:flex;align-items:center;gap:12px;margin-bottom:10px;">
  311. <span style="font-size:22px;">📄</span>
  312. <span style="flex:1;font-size:15px;font-weight:600;">Q4市场分析报告</span>
  313. <span style="padding:4px 10px;background:#fffbe6;color:var(--warning);border-radius:12px;font-size:11px;">审核中</span>
  314. </div>
  315. <div style="display:flex;gap:20px;font-size:12px;color:var(--text2);margin-bottom:12px;">
  316. <span>📅 2025-12-28</span><span>👤 张三</span>
  317. </div>
  318. <div style="display:flex;gap:8px;">
  319. <button class="btn btn-primary" onclick="openEditor()">查看</button>
  320. <button class="btn" onclick="showToast('已发送催办', 'success')">催办</button>
  321. </div>
  322. </div>
  323. </div>
  324. </div>
  325. <!-- 模板管理页 -->
  326. <div class="page" id="page-templates">
  327. <h2 style="margin-bottom:16px">🎨 模板管理</h2>
  328. <div style="display:flex;gap:12px;margin-bottom:16px;">
  329. <input type="text" placeholder="🔍 搜索模板..." style="width:280px;padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:13px;">
  330. <div style="display:flex;gap:6px;">
  331. <span style="padding:8px 16px;background:var(--primary);color:white;border-radius:18px;font-size:12px;cursor:pointer;">全部</span>
  332. <span style="padding:8px 16px;background:var(--bg);border-radius:18px;font-size:12px;cursor:pointer;">官方模板</span>
  333. <span style="padding:8px 16px;background:var(--bg);border-radius:18px;font-size:12px;cursor:pointer;">我的模板</span>
  334. </div>
  335. <button class="btn btn-primary" style="margin-left:auto;">➕ 创建模板</button>
  336. </div>
  337. <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;">
  338. <div class="tpl-card card" onclick="openEditor()"><div class="tpl-preview">📊</div><div class="tpl-info"><div class="tpl-name">市场分析报告</div><div class="tpl-meta"><span>📊 128次</span></div><div class="tpl-tags"><span class="tpl-tag">官方</span><span class="tpl-tag hot">热门</span></div><button class="tpl-btn">使用</button></div></div>
  339. <div class="tpl-card card" onclick="openEditor()"><div class="tpl-preview">🏢</div><div class="tpl-info"><div class="tpl-name">可行性研究报告</div><div class="tpl-meta"><span>📊 96次</span></div><div class="tpl-tags"><span class="tpl-tag">官方</span></div><button class="tpl-btn">使用</button></div></div>
  340. <div class="tpl-card card" onclick="openEditor()"><div class="tpl-preview">📅</div><div class="tpl-info"><div class="tpl-name">项目周报</div><div class="tpl-meta"><span>📊 256次</span></div><div class="tpl-tags"><span class="tpl-tag">官方</span></div><button class="tpl-btn">使用</button></div></div>
  341. <div class="tpl-card card" onclick="openEditor()"><div class="tpl-preview">💼</div><div class="tpl-info"><div class="tpl-name">尽职调查报告</div><div class="tpl-meta"><span>📊 45次</span></div><div class="tpl-tags"><span class="tpl-tag">行业</span></div><button class="tpl-btn">使用</button></div></div>
  342. </div>
  343. </div>
  344. <!-- 数据源管理页 -->
  345. <div class="page" id="page-datasources">
  346. <h2 style="margin-bottom:16px">🔗 数据源管理</h2>
  347. <div style="display:flex;gap:12px;margin-bottom:16px;">
  348. <input type="text" placeholder="🔍 搜索数据源..." style="width:280px;padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:13px;">
  349. <button class="btn btn-primary" style="margin-left:auto;">➕ 添加数据源</button>
  350. </div>
  351. <div style="display:flex;flex-direction:column;gap:12px;">
  352. <div class="card" style="padding:18px;">
  353. <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
  354. <div style="width:44px;height:44px;background:var(--primary-light);border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:22px;">🗄️</div>
  355. <div style="flex:1;"><div style="font-size:15px;font-weight:600;">销售数据库</div><div style="font-size:12px;color:var(--text3);">MySQL · db.company.com:3306</div></div>
  356. <div style="font-size:12px;color:var(--success);">● 已连接</div>
  357. </div>
  358. <div style="display:flex;gap:8px;"><button class="btn">测试连接</button><button class="btn">同步数据</button><button class="btn">查看数据表</button></div>
  359. </div>
  360. <div class="card" style="padding:18px;">
  361. <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
  362. <div style="width:44px;height:44px;background:#f6ffed;border-radius:10px;display:flex;align-items:center;justify-content:center;font-size:22px;">🌐</div>
  363. <div style="flex:1;"><div style="font-size:15px;font-weight:600;">市场数据API</div><div style="font-size:12px;color:var(--text3);">REST API · api.marketdata.com</div></div>
  364. <div style="font-size:12px;color:var(--success);">● 已连接</div>
  365. </div>
  366. <div style="display:flex;gap:8px;"><button class="btn">测试接口</button><button class="btn">查看文档</button></div>
  367. </div>
  368. </div>
  369. </div>
  370. </main>
  371. <style>
  372. /* === 编辑器专用样式 === */
  373. .editor-page { display: none; position: fixed; top: 56px; left: 0; right: 0; bottom: 0; flex-direction: column; background: var(--bg); z-index: 800; }
  374. .editor-page.active { display: flex; }
  375. /* 编辑器工具栏 */
  376. .editor-toolbar { height: 56px; background: var(--white); border-bottom: 1px solid var(--border); display: flex; align-items: center; padding: 0 16px; gap: 16px; flex-shrink: 0; }
  377. .back-btn { display: flex; align-items: center; gap: 4px; padding: 8px 12px; border: none; background: transparent; border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--text2); }
  378. .back-btn:hover { background: var(--bg); color: var(--primary); }
  379. .report-title-input { border: none; background: transparent; font-size: 15px; font-weight: 600; padding: 8px 12px; border-radius: 6px; min-width: 300px; outline: none; }
  380. .report-title-input:hover { background: var(--bg); }
  381. .report-title-input:focus { background: var(--white); box-shadow: 0 0 0 2px var(--primary-light); }
  382. .save-status { display: flex; align-items: center; gap: 4px; font-size: 13px; color: var(--success); }
  383. .toolbar-right { margin-left: auto; display: flex; gap: 10px; align-items: center; }
  384. .toolbar-btn { display: flex; align-items: center; gap: 6px; padding: 8px 16px; border: 1px solid var(--border); background: var(--white); border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--text1); transition: all 0.2s; }
  385. .toolbar-btn:hover { border-color: var(--primary); color: var(--primary); background: var(--primary-light); }
  386. .toolbar-btn.primary { background: var(--primary); color: white; border: none; }
  387. .toolbar-btn.primary:hover { background: var(--primary-dark); }
  388. .toolbar-btn .icon { font-size: 14px; }
  389. .toolbar-divider { width: 1px; height: 24px; background: var(--border); }
  390. /* 编辑器主体 */
  391. .editor-body { flex: 1; display: flex; overflow: hidden; }
  392. /* 左侧项目文件面板 */
  393. .left-panel { width: 260px; background: var(--white); border-right: 1px solid var(--border); display: flex; flex-direction: column; }
  394. .panel-header { padding: 14px 16px; border-bottom: 1px solid var(--border); font-size: 13px; font-weight: 600; color: var(--text1); display: flex; align-items: center; justify-content: space-between; }
  395. .file-count { font-size: 12px; color: var(--text3); font-weight: normal; }
  396. .panel-body { flex: 1; overflow-y: auto; padding: 12px; }
  397. /* 上传区 */
  398. .upload-zone { border: 2px dashed var(--border); border-radius: 10px; padding: 24px 16px; text-align: center; cursor: pointer; margin-bottom: 16px; transition: all 0.2s; }
  399. .upload-zone:hover { border-color: var(--primary); background: var(--primary-light); }
  400. .upload-icon { font-size: 32px; margin-bottom: 8px; color: var(--text3); }
  401. .upload-text { font-size: 13px; color: var(--text2); margin-bottom: 4px; }
  402. .upload-hint { font-size: 11px; color: var(--text3); }
  403. /* 文件分组 */
  404. .file-group { margin-bottom: 16px; }
  405. .file-group-header { display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text3); margin-bottom: 8px; padding: 0 4px; }
  406. .file-group-header .count { background: var(--bg); padding: 1px 6px; border-radius: 8px; font-size: 10px; }
  407. /* 文件项 - 解析中状态 */
  408. .file-item { display: flex; align-items: center; gap: 10px; padding: 10px 12px; background: var(--white); border: 1px solid var(--border); border-radius: 8px; margin-bottom: 8px; cursor: pointer; transition: all 0.2s; }
  409. .file-item:hover { border-color: var(--primary); background: var(--primary-light); }
  410. .file-item.active { border-color: var(--primary); background: var(--primary-light); }
  411. .file-icon { font-size: 28px; flex-shrink: 0; }
  412. .file-icon.pdf { color: #ff4d4f; }
  413. .file-icon.docx { color: #1890ff; }
  414. .file-icon.xlsx { color: #52c41a; }
  415. .file-icon.md { color: #8c8c8c; }
  416. .file-info { flex: 1; min-width: 0; }
  417. .file-name { font-size: 12px; font-weight: 500; margin-bottom: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  418. .file-meta { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--text3); }
  419. .file-status { font-size: 11px; white-space: nowrap; }
  420. .file-status.parsing { color: var(--primary); }
  421. .file-status.done { color: var(--success); }
  422. /* 中间编辑区 */
  423. .center-panel { flex: 1; display: flex; flex-direction: column; background: var(--white); overflow: hidden; }
  424. /* 编辑器顶部标题栏 */
  425. .editor-title-bar { padding: 16px 24px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; }
  426. .editor-main-title { font-size: 18px; font-weight: 600; flex: 1; }
  427. .view-toggle { display: flex; align-items: center; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; }
  428. .view-btn { padding: 8px 16px; border: none; background: var(--white); font-size: 13px; cursor: pointer; color: var(--text2); display: flex; align-items: center; gap: 6px; transition: all 0.2s; }
  429. .view-btn:first-child { border-right: 1px solid var(--border); }
  430. .view-btn:hover { background: var(--bg); }
  431. .view-btn.active { background: var(--primary-light); color: var(--primary); font-weight: 500; }
  432. .graph-btn { width: 36px; height: 36px; border: 1px solid var(--border); background: var(--white); border-radius: 6px; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 18px; margin-left: 8px; transition: all 0.2s; }
  433. .graph-btn:hover { border-color: var(--primary); background: var(--primary-light); }
  434. /* 图谱弹窗 */
  435. .graph-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.5); display: none; align-items: center; justify-content: center; z-index: 2000; }
  436. .graph-modal.show { display: flex; }
  437. .graph-container { width: 900px; height: 600px; background: var(--white); border-radius: 16px; overflow: hidden; display: flex; flex-direction: column; }
  438. .graph-header { padding: 16px 20px; border-bottom: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; }
  439. .graph-title { font-size: 16px; font-weight: 600; display: flex; align-items: center; gap: 8px; }
  440. .graph-close { width: 32px; height: 32px; border: none; background: var(--bg); border-radius: 50%; cursor: pointer; font-size: 16px; display: flex; align-items: center; justify-content: center; }
  441. .graph-close:hover { background: var(--danger); color: white; }
  442. .graph-body { flex: 1; position: relative; background: linear-gradient(135deg, #f8fafc 0%, #f0f4f8 100%); }
  443. .graph-legend { position: absolute; top: 16px; left: 16px; background: var(--white); border-radius: 8px; padding: 12px 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
  444. .legend-title { font-size: 12px; font-weight: 600; margin-bottom: 8px; color: var(--text2); }
  445. .legend-item { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--text2); margin-bottom: 4px; }
  446. .legend-dot { width: 12px; height: 12px; border-radius: 50%; }
  447. .legend-dot.entity { background: var(--primary); }
  448. .legend-dot.concept { background: #722ed1; }
  449. .legend-dot.data { background: var(--success); }
  450. .legend-dot.location { background: var(--warning); }
  451. /* 图谱节点 */
  452. .graph-node { position: absolute; display: flex; flex-direction: column; align-items: center; cursor: pointer; transition: transform 0.2s; }
  453. .graph-node:hover { transform: scale(1.1); }
  454. .node-circle { width: 60px; height: 60px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24px; color: white; box-shadow: 0 4px 12px rgba(0,0,0,0.15); }
  455. .node-circle.primary { background: linear-gradient(135deg, #1890ff, #096dd9); }
  456. .node-circle.purple { background: linear-gradient(135deg, #722ed1, #531dab); }
  457. .node-circle.green { background: linear-gradient(135deg, #52c41a, #389e0d); }
  458. .node-circle.orange { background: linear-gradient(135deg, #faad14, #d48806); }
  459. .node-circle.center { width: 80px; height: 80px; font-size: 32px; }
  460. .node-label { margin-top: 6px; font-size: 11px; font-weight: 500; color: var(--text1); white-space: nowrap; background: var(--white); padding: 2px 8px; border-radius: 10px; box-shadow: 0 1px 4px rgba(0,0,0,0.1); }
  461. /* 连接线 SVG */
  462. .graph-lines { position: absolute; inset: 0; pointer-events: none; }
  463. /* 图谱视图切换按钮 */
  464. .graph-view-btn { padding: 8px 14px; border: none; background: var(--white); font-size: 12px; cursor: pointer; color: var(--text2); display: flex; align-items: center; gap: 4px; transition: all 0.2s; }
  465. .graph-view-btn:first-child { border-right: 1px solid var(--border); }
  466. .graph-view-btn:hover { background: var(--bg); }
  467. .graph-view-btn.active { background: var(--primary-light); color: var(--primary); font-weight: 500; }
  468. /* 列表视图 */
  469. .graph-list-body { flex: 1; display: flex; flex-direction: column; background: var(--white); overflow: hidden; }
  470. .list-filter-tag { padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 14px; font-size: 11px; cursor: pointer; transition: all 0.2s; }
  471. .list-filter-tag:hover { border-color: var(--primary); }
  472. .list-filter-tag.active { background: var(--primary); color: white; border-color: var(--primary); }
  473. .list-group { margin-bottom: 20px; }
  474. .list-group-header { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; margin-bottom: 10px; color: var(--text1); }
  475. .list-group-dot { width: 10px; height: 10px; border-radius: 50%; }
  476. .list-group-count { font-size: 11px; color: var(--text3); font-weight: normal; background: var(--bg); padding: 2px 8px; border-radius: 10px; }
  477. .list-item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; background: var(--bg); border-radius: 10px; margin-bottom: 8px; cursor: pointer; transition: all 0.2s; }
  478. .list-item:hover { background: var(--primary-light); transform: translateX(4px); }
  479. .list-item-icon { width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
  480. .list-item-info { flex: 1; min-width: 0; }
  481. .list-item-name { font-size: 13px; font-weight: 600; margin-bottom: 2px; }
  482. .list-item-desc { font-size: 11px; color: var(--text3); }
  483. .list-item-relations { display: flex; gap: 6px; flex-wrap: wrap; }
  484. .relation-tag { padding: 3px 8px; background: var(--white); border-radius: 4px; font-size: 10px; color: var(--text2); }
  485. /* 编辑器内容区 */
  486. .editor-scroll { flex: 1; overflow-y: auto; padding: 24px 32px; }
  487. .editor-content { max-width: 800px; margin: 0 auto; }
  488. .editor-content h1 { font-size: 24px; font-weight: 700; margin-bottom: 24px; color: var(--text1); }
  489. .editor-content h2 { font-size: 18px; font-weight: 600; margin: 28px 0 16px; color: var(--text1); }
  490. .editor-content h3 { font-size: 15px; font-weight: 600; margin: 20px 0 12px; color: var(--text1); }
  491. .editor-content p { margin-bottom: 16px; line-height: 1.8; color: var(--text1); }
  492. /* 实体高亮标记 - 蓝色边框样式 */
  493. /* 正文实体高亮标签 - 基础样式 */
  494. .entity-highlight { display: inline; padding: 2px 8px; border-radius: 4px; cursor: pointer; transition: all 0.2s; font-weight: 500; }
  495. /* 实体类型颜色 - 与右侧要素管理对应 */
  496. .entity-highlight { border: 1px solid var(--primary); color: var(--primary); background: rgba(24,144,255,0.1); } /* 默认蓝色-核心实体 */
  497. .entity-highlight:hover { background: var(--primary); color: white; }
  498. .entity-highlight.entity { border-color: var(--primary); color: var(--primary); background: rgba(24,144,255,0.1); }
  499. .entity-highlight.entity:hover { background: var(--primary); color: white; }
  500. .entity-highlight.concept { border-color: #722ed1; color: #722ed1; background: rgba(114,46,209,0.1); }
  501. .entity-highlight.concept:hover { background: #722ed1; color: white; }
  502. .entity-highlight.data { border-color: #52c41a; color: #52c41a; background: rgba(82,196,26,0.1); }
  503. .entity-highlight.data:hover { background: #52c41a; color: white; }
  504. .entity-highlight.location { border-color: #faad14; color: #d48806; background: rgba(250,173,20,0.1); }
  505. .entity-highlight.location:hover { background: #faad14; color: white; }
  506. .entity-highlight.asset { border-color: #eb2f96; color: #eb2f96; background: rgba(235,47,150,0.1); }
  507. .entity-highlight.asset:hover { background: #eb2f96; color: white; }
  508. /* AI优化建议卡片 */
  509. .ai-suggestion-card { background: #fffbf0; border: 1px solid #ffe7ba; border-radius: 10px; padding: 16px; margin: 16px 0; }
  510. .ai-suggestion-header { display: flex; align-items: center; gap: 8px; margin-bottom: 12px; }
  511. .ai-suggestion-icon { font-size: 18px; }
  512. .ai-suggestion-title { font-size: 14px; font-weight: 600; color: var(--warning); }
  513. .ai-suggestion-content { font-size: 13px; line-height: 1.7; color: var(--text1); margin-bottom: 12px; }
  514. .ai-suggestion-actions { display: flex; gap: 8px; }
  515. .suggest-btn { padding: 6px 14px; border-radius: 6px; font-size: 12px; cursor: pointer; transition: all 0.2s; }
  516. .suggest-btn.accept { background: var(--primary); color: white; border: none; }
  517. .suggest-btn.accept:hover { background: var(--primary-dark); }
  518. .suggest-btn.ignore { background: var(--white); color: var(--text2); border: 1px solid var(--border); }
  519. .suggest-btn.ignore:hover { border-color: var(--text2); }
  520. /* 数据表格 */
  521. .data-table-card { background: var(--white); border: 1px solid var(--border); border-radius: 10px; margin: 16px 0; overflow: hidden; }
  522. .data-table-header { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--border); }
  523. .data-table-title { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600; }
  524. .data-table-source { font-size: 11px; color: var(--text3); }
  525. .data-table { width: 100%; border-collapse: collapse; }
  526. .data-table th { background: var(--bg); padding: 10px 16px; text-align: left; font-size: 12px; font-weight: 600; color: var(--text2); border-bottom: 1px solid var(--border); }
  527. .data-table td { padding: 10px 16px; font-size: 13px; border-bottom: 1px solid var(--border); }
  528. .data-table tr:last-child td { border-bottom: none; }
  529. .data-table tr:hover td { background: var(--primary-light); }
  530. /* 右侧AI助手面板 */
  531. .right-panel { width: 380px; background: var(--white); border-left: 1px solid var(--border); display: flex; flex-direction: column; }
  532. /* 要素管理区 */
  533. .element-section { padding: 16px; border-bottom: 1px solid var(--border); }
  534. .element-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
  535. .element-title { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
  536. .element-count { font-size: 11px; color: var(--text3); font-weight: normal; }
  537. /* 要素标签容器 - 固定高度可滚动 */
  538. .element-tags-wrap { display: flex; flex-wrap: wrap; gap: 8px; max-height: 180px; overflow-y: auto; padding-right: 4px; }
  539. .element-tags-wrap::-webkit-scrollbar { width: 4px; }
  540. .element-tags-wrap::-webkit-scrollbar-track { background: var(--bg); border-radius: 2px; }
  541. .element-tags-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
  542. .element-tags-wrap::-webkit-scrollbar-thumb:hover { background: var(--text3); }
  543. /* 要素标签样式 */
  544. .element-tag { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 16px; font-size: 12px; cursor: grab; transition: all 0.2s; user-select: none; }
  545. .element-tag:hover { border-color: var(--primary); background: var(--primary-light); transform: translateY(-1px); }
  546. .element-tag:active { cursor: grabbing; }
  547. .element-tag.dragging { opacity: 0.5; }
  548. .element-tag .tag-icon { font-size: 12px; }
  549. .element-tag .tag-name { font-weight: 500; }
  550. .element-tag.entity { border-left: 3px solid var(--primary); }
  551. .element-tag.concept { border-left: 3px solid #722ed1; }
  552. .element-tag.data { border-left: 3px solid var(--success); }
  553. .element-tag.location { border-left: 3px solid var(--warning); }
  554. .element-tag.asset { border-left: 3px solid #eb2f96; }
  555. .element-hint { font-size: 11px; color: var(--text3); margin-top: 10px; text-align: center; }
  556. /* 要素详情弹出框 */
  557. .element-popover { position: fixed; width: 280px; background: var(--white); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); z-index: 2000; display: none; }
  558. .element-popover.show { display: block; }
  559. .popover-header { padding: 12px 14px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; }
  560. .popover-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 16px; }
  561. .popover-icon.entity { background: linear-gradient(135deg, #e6f7ff, #bae7ff); }
  562. .popover-icon.data { background: linear-gradient(135deg, #f6ffed, #d9f7be); }
  563. .popover-icon.location { background: linear-gradient(135deg, #fff7e6, #ffe7ba); }
  564. .popover-icon.asset { background: linear-gradient(135deg, #fff0f6, #ffd6e7); }
  565. .popover-title { font-size: 14px; font-weight: 600; flex: 1; }
  566. .popover-close { width: 24px; height: 24px; border: none; background: var(--bg); border-radius: 50%; cursor: pointer; font-size: 12px; }
  567. .popover-close:hover { background: var(--danger); color: white; }
  568. .popover-body { padding: 14px; }
  569. .popover-section { margin-bottom: 10px; }
  570. .popover-label { font-size: 10px; color: var(--text3); margin-bottom: 4px; text-transform: uppercase; }
  571. .popover-value { font-size: 12px; color: var(--text1); }
  572. .popover-relations { display: flex; flex-wrap: wrap; gap: 6px; }
  573. .popover-relation { padding: 4px 8px; background: var(--bg); border-radius: 4px; font-size: 11px; cursor: pointer; }
  574. .popover-relation:hover { background: var(--primary-light); color: var(--primary); }
  575. .popover-actions { display: flex; gap: 8px; margin-top: 12px; }
  576. .popover-actions .btn { flex: 1; justify-content: center; font-size: 12px; }
  577. /* 拖拽放置提示 */
  578. .editor-content.drag-over { background: linear-gradient(135deg, rgba(24,144,255,0.05), rgba(24,144,255,0.1)); }
  579. .editor-content.drag-over::after { content: '释放鼠标插入要素'; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); padding: 12px 24px; background: var(--primary); color: white; border-radius: 8px; font-size: 14px; z-index: 100; }
  580. /* AI助手区 */
  581. .ai-assistant { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-height: 0; }
  582. .ai-header { padding: 12px 16px; border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
  583. .ai-avatar-sm { width: 36px; height: 36px; background: var(--ai-gradient); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 18px; flex-shrink: 0; }
  584. .ai-info { flex: 1; }
  585. .ai-name { font-size: 14px; font-weight: 600; }
  586. .ai-status { font-size: 11px; color: var(--success); }
  587. /* AI Tab切换 */
  588. .ai-tabs { display: flex; border-bottom: 1px solid var(--border); flex-shrink: 0; }
  589. .ai-tab { flex: 1; padding: 10px; text-align: center; font-size: 12px; cursor: pointer; color: var(--text2); border-bottom: 2px solid transparent; transition: all 0.2s; display: flex; align-items: center; justify-content: center; gap: 4px; }
  590. .ai-tab:hover { color: var(--primary); }
  591. .ai-tab.active { color: var(--primary); border-bottom-color: var(--primary); }
  592. /* AI消息区 */
  593. .ai-messages { flex: 1; overflow-y: auto; padding: 16px; min-height: 0; }
  594. .msg { display: flex; gap: 10px; margin-bottom: 16px; }
  595. .msg.user { flex-direction: row-reverse; }
  596. .msg-avatar { width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 12px; flex-shrink: 0; }
  597. .msg.ai .msg-avatar { background: var(--ai-gradient); color: white; }
  598. .msg.user .msg-avatar { background: var(--primary); color: white; }
  599. .msg-bubble { max-width: 85%; padding: 10px 14px; border-radius: 12px; font-size: 13px; line-height: 1.6; }
  600. .msg.ai .msg-bubble { background: var(--bg); border-radius: 4px 12px 12px 12px; }
  601. .msg.user .msg-bubble { background: var(--primary); color: white; border-radius: 12px 4px 12px 12px; }
  602. /* 内容建议卡片 */
  603. .content-suggestion { background: linear-gradient(135deg, #f0f7ff, #f5f0ff); border: 1px solid #d6e4ff; border-radius: 10px; padding: 14px; margin: 12px 0; }
  604. .content-suggestion-header { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; }
  605. .content-suggestion-title { font-size: 13px; font-weight: 600; color: var(--primary); }
  606. .content-suggestion-body { font-size: 12px; line-height: 1.7; color: var(--text1); margin-bottom: 12px; }
  607. .content-suggestion-list { list-style: none; margin-bottom: 12px; }
  608. .content-suggestion-list li { padding: 4px 0; font-size: 12px; color: var(--text2); }
  609. .content-suggestion-list li::before { content: '•'; color: var(--primary); margin-right: 8px; }
  610. .content-suggestion-actions { display: flex; gap: 8px; }
  611. /* AI输入区 - 底部固定 */
  612. .ai-input-area { padding: 12px 16px; border-top: 1px solid var(--border); background: var(--white); flex-shrink: 0; }
  613. .ai-input-box { background: var(--bg); border: 1px solid var(--border); border-radius: 20px; transition: all 0.2s; }
  614. .ai-input-box:focus-within { border-color: var(--primary); background: var(--white); box-shadow: 0 0 0 3px rgba(24,144,255,0.1); }
  615. .ai-input-box textarea { width: 100%; border: none; background: transparent; resize: none; outline: none; font-size: 13px; line-height: 1.5; padding: 10px 16px; min-height: 40px; max-height: 80px; font-family: inherit; border-radius: 20px; display: block; }
  616. .ai-input-box textarea::placeholder { color: var(--text3); }
  617. .ai-input-hint { display: flex; align-items: center; justify-content: space-between; padding: 8px 4px 0; font-size: 10px; color: var(--text3); }
  618. /* 要素标签容器 */
  619. .element-section { border-bottom: 1px solid var(--border); }
  620. .element-header { padding: 14px 16px; display: flex; align-items: center; justify-content: space-between; }
  621. .element-title { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 6px; }
  622. .element-count { font-size: 11px; color: var(--text3); font-weight: normal; }
  623. .element-body { padding: 0 16px 14px; }
  624. /* 动画 */
  625. @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } }
  626. .parsing-anim { animation: pulse 1.5s infinite; }
  627. /* 可编辑内容区 */
  628. .editor-content[contenteditable="true"] { outline: none; }
  629. .editor-content[contenteditable="true"]:focus { background: #fafbfc; }
  630. .editor-content[contenteditable="true"] ::selection { background: rgba(24,144,255,0.2); }
  631. /* 段落编辑效果 */
  632. .editor-content p, .editor-content h1, .editor-content h2, .editor-content h3, .editor-content li {
  633. position: relative; border-radius: 6px; transition: all 0.2s; padding: 4px 8px; margin-left: -8px; margin-right: -8px;
  634. }
  635. .editor-content p:focus, .editor-content h1:focus, .editor-content h2:focus, .editor-content h3:focus, .editor-content li:focus,
  636. .editor-content p.editing, .editor-content h1.editing, .editor-content h2.editing, .editor-content h3.editing, .editor-content li.editing {
  637. background: linear-gradient(135deg, rgba(24,144,255,0.08), rgba(24,144,255,0.04));
  638. box-shadow: inset 0 0 0 1px rgba(24,144,255,0.2);
  639. }
  640. .editor-content p:hover, .editor-content h1:hover, .editor-content h2:hover, .editor-content h3:hover, .editor-content li:hover {
  641. background: rgba(0,0,0,0.02);
  642. }
  643. /* 右键菜单 */
  644. .context-menu { position: fixed; min-width: 180px; background: var(--white); border-radius: 10px; box-shadow: 0 8px 24px rgba(0,0,0,0.15); z-index: 3000; display: none; overflow: hidden; }
  645. .context-menu.show { display: block; }
  646. .context-menu-item { display: flex; align-items: center; gap: 10px; padding: 10px 14px; font-size: 13px; cursor: pointer; transition: all 0.15s; }
  647. .context-menu-item:hover { background: var(--primary-light); color: var(--primary); }
  648. .context-menu-item .icon { font-size: 14px; width: 20px; text-align: center; }
  649. .context-menu-item .shortcut { margin-left: auto; font-size: 11px; color: var(--text3); }
  650. .context-menu-divider { height: 1px; background: var(--border); margin: 4px 0; }
  651. /* AI结果确认弹窗 */
  652. .ai-confirm-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: none; align-items: center; justify-content: center; z-index: 3500; }
  653. .ai-confirm-modal.show { display: flex; }
  654. .ai-confirm-card { width: 520px; background: var(--white); border-radius: 14px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.2); }
  655. .ai-confirm-header { padding: 16px 20px; background: linear-gradient(135deg, #f0f7ff, #e6fffb); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; }
  656. .ai-confirm-icon { width: 40px; height: 40px; background: var(--white); border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
  657. .ai-confirm-title { flex: 1; }
  658. .ai-confirm-title h3 { font-size: 15px; font-weight: 600; margin-bottom: 2px; }
  659. .ai-confirm-title span { font-size: 11px; color: var(--text3); }
  660. .ai-confirm-close { width: 28px; height: 28px; border: none; background: rgba(0,0,0,0.05); border-radius: 50%; cursor: pointer; font-size: 14px; }
  661. .ai-confirm-close:hover { background: var(--danger); color: white; }
  662. .ai-confirm-body { padding: 20px; }
  663. .ai-confirm-section { margin-bottom: 16px; }
  664. .ai-confirm-label { font-size: 12px; font-weight: 500; color: var(--text2); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
  665. .ai-confirm-text { padding: 12px 14px; border-radius: 8px; font-size: 13px; line-height: 1.7; }
  666. .ai-confirm-text.original { background: var(--bg); color: var(--text2); text-decoration: line-through; }
  667. .ai-confirm-text.result { background: linear-gradient(135deg, #f6ffed, #e6fffb); border: 1px solid #b7eb8f; color: var(--text1); }
  668. .ai-confirm-diff { display: flex; align-items: center; justify-content: center; padding: 8px 0; color: var(--success); font-size: 20px; }
  669. .ai-confirm-footer { padding: 16px 20px; border-top: 1px solid var(--border); display: flex; gap: 10px; justify-content: flex-end; background: var(--bg); }
  670. .ai-confirm-footer .btn { min-width: 100px; justify-content: center; }
  671. /* 标记为要素弹窗 */
  672. .mark-entity-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: none; align-items: center; justify-content: center; z-index: 3500; }
  673. .mark-entity-modal.show { display: flex; }
  674. .mark-entity-card { width: 400px; background: var(--white); border-radius: 14px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.2); }
  675. .mark-entity-header { padding: 16px 20px; background: linear-gradient(135deg, #f9f0ff, #fff0f6); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; }
  676. .mark-entity-body { padding: 20px; }
  677. .mark-entity-preview { padding: 12px 16px; background: var(--primary-light); border: 1px dashed var(--primary); border-radius: 8px; font-size: 14px; font-weight: 500; color: var(--primary); text-align: center; margin-bottom: 16px; }
  678. .mark-entity-types { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 16px; }
  679. .mark-entity-type { flex: 1; min-width: 45%; padding: 12px; border: 1px solid var(--border); border-radius: 8px; cursor: pointer; transition: all 0.2s; text-align: center; }
  680. .mark-entity-type:hover { border-color: var(--primary); background: var(--primary-light); }
  681. .mark-entity-type.selected { border-color: var(--primary); background: var(--primary-light); box-shadow: 0 0 0 2px rgba(24,144,255,0.2); }
  682. .mark-entity-type .type-icon { font-size: 24px; margin-bottom: 4px; }
  683. .mark-entity-type .type-name { font-size: 12px; font-weight: 500; }
  684. .mark-entity-footer { padding: 16px 20px; border-top: 1px solid var(--border); display: flex; gap: 10px; justify-content: flex-end; background: var(--bg); }
  685. /* 实体标签编辑弹窗 */
  686. .entity-edit-modal { position: fixed; inset: 0; background: rgba(0,0,0,0.4); display: none; align-items: center; justify-content: center; z-index: 2500; }
  687. .entity-edit-modal.show { display: flex; }
  688. .entity-edit-card { width: 420px; background: var(--white); border-radius: 14px; overflow: hidden; box-shadow: 0 12px 40px rgba(0,0,0,0.2); }
  689. .entity-edit-header { padding: 16px 20px; background: linear-gradient(135deg, #f0f7ff, #f5f0ff); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; }
  690. .entity-edit-icon { width: 40px; height: 40px; background: var(--white); border-radius: 10px; display: flex; align-items: center; justify-content: center; font-size: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
  691. .entity-edit-title { flex: 1; }
  692. .entity-edit-title h3 { font-size: 15px; font-weight: 600; margin-bottom: 2px; }
  693. .entity-edit-title span { font-size: 11px; color: var(--text3); }
  694. .entity-edit-close { width: 28px; height: 28px; border: none; background: rgba(0,0,0,0.05); border-radius: 50%; cursor: pointer; font-size: 14px; }
  695. .entity-edit-close:hover { background: var(--danger); color: white; }
  696. .entity-edit-body { padding: 20px; }
  697. .entity-edit-section { margin-bottom: 16px; }
  698. .entity-edit-section:last-child { margin-bottom: 0; }
  699. .entity-edit-label { font-size: 12px; font-weight: 500; color: var(--text2); margin-bottom: 8px; display: flex; align-items: center; gap: 6px; }
  700. .entity-edit-input { width: 100%; padding: 10px 14px; border: 1px solid var(--border); border-radius: 8px; font-size: 14px; outline: none; transition: all 0.2s; }
  701. .entity-edit-input:focus { border-color: var(--primary); box-shadow: 0 0 0 3px rgba(24,144,255,0.1); }
  702. .entity-edit-input:disabled { background: var(--bg); color: var(--text3); }
  703. .entity-edit-row { display: flex; gap: 12px; }
  704. .entity-edit-row .entity-edit-section { flex: 1; }
  705. /* 数据关系表格 */
  706. .entity-relation-table { width: 100%; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
  707. .entity-relation-table th { background: var(--bg); padding: 10px 12px; text-align: left; font-size: 12px; font-weight: 500; color: var(--text2); border-bottom: 1px solid var(--border); }
  708. .entity-relation-table td { padding: 10px 12px; font-size: 13px; border-bottom: 1px solid var(--border); }
  709. .entity-relation-table tr:last-child td { border-bottom: none; }
  710. .entity-relation-table .original { color: var(--text3); }
  711. .entity-relation-table .current { color: var(--primary); font-weight: 500; }
  712. .entity-relation-table .editable { background: var(--primary-light); border-radius: 4px; padding: 4px 8px; }
  713. .entity-edit-footer { padding: 16px 20px; border-top: 1px solid var(--border); display: flex; gap: 10px; justify-content: flex-end; background: var(--bg); }
  714. .entity-edit-footer .btn { min-width: 80px; justify-content: center; }
  715. </style>
  716. <!-- 编辑器页面 -->
  717. <div class="editor-page" id="page-editor">
  718. <!-- 编辑器工具栏 -->
  719. <div class="editor-toolbar">
  720. <button class="back-btn" onclick="closeEditor()">← 返回</button>
  721. <input type="text" class="report-title-input" value="智慧园区建设项目可行性研究报告">
  722. <span class="save-status">✓ 已保存</span>
  723. <div class="toolbar-right">
  724. <button class="toolbar-btn" onclick="showToast('查看版本历史', 'info')">
  725. <span class="icon">🕐</span>
  726. <span>版本</span>
  727. </button>
  728. <button class="toolbar-btn" onclick="showToast('协作设置', 'info')">
  729. <span class="icon">👥</span>
  730. <span>协作</span>
  731. </button>
  732. <button class="toolbar-btn" onclick="showToast('分享链接已复制', 'success')">
  733. <span class="icon">🔗</span>
  734. <span>分享</span>
  735. </button>
  736. <button class="toolbar-btn" onclick="showExportMenu(this)">
  737. <span class="icon">📤</span>
  738. <span>导出</span>
  739. <span style="font-size:10px;margin-left:2px;">▾</span>
  740. </button>
  741. <div class="toolbar-divider"></div>
  742. <button class="toolbar-btn primary" onclick="showToast('保存成功', 'success')">
  743. <span class="icon">💾</span>
  744. <span>保存</span>
  745. </button>
  746. </div>
  747. </div>
  748. <!-- 编辑器主体 -->
  749. <div class="editor-body">
  750. <!-- 左侧项目文件面板 -->
  751. <div class="left-panel">
  752. <div class="panel-header">
  753. <span>📁 项目文件</span>
  754. <span class="file-count">5个文件</span>
  755. </div>
  756. <div class="panel-body">
  757. <!-- 上传区 -->
  758. <div class="upload-zone" onclick="simulateUpload()">
  759. <div class="upload-icon">📄</div>
  760. <div class="upload-text">拖拽或点击上传</div>
  761. <div class="upload-hint">支持 PDF / Word / Excel / MD</div>
  762. </div>
  763. <!-- 解析中文件组 -->
  764. <div class="file-group">
  765. <div class="file-group-header">
  766. <span>📥 解析中</span>
  767. <span class="count">2</span>
  768. </div>
  769. <div class="file-item" id="parsingFile1">
  770. <span class="file-icon pdf">📕</span>
  771. <div class="file-info">
  772. <div class="file-name">市场调研数据.pdf</div>
  773. <div class="file-meta">
  774. <span>5.8 MB</span>
  775. <span class="file-status parsing parsing-anim">📊 解析中 65%</span>
  776. </div>
  777. </div>
  778. </div>
  779. <div class="file-item">
  780. <span class="file-icon pdf">📕</span>
  781. <div class="file-info">
  782. <div class="file-name">技术方案说明.pdf</div>
  783. <div class="file-meta">
  784. <span>3.6 MB</span>
  785. <span class="file-status parsing parsing-anim">📊 解析中 30%</span>
  786. </div>
  787. </div>
  788. </div>
  789. </div>
  790. <!-- 已完成文件组 -->
  791. <div class="file-group">
  792. <div class="file-group-header">
  793. <span style="color:var(--success)">✅ 已完成</span>
  794. <span class="count">3</span>
  795. </div>
  796. <div class="file-item active" onclick="highlightFile(this)">
  797. <span class="file-icon docx">📘</span>
  798. <div class="file-info">
  799. <div class="file-name">项目可行性研究报告.docx</div>
  800. <div class="file-meta">
  801. <span>2.4 MB</span>
  802. <span class="file-status done">✓ 已完成</span>
  803. </div>
  804. </div>
  805. </div>
  806. <div class="file-item" onclick="highlightFile(this)">
  807. <span class="file-icon xlsx">📗</span>
  808. <div class="file-info">
  809. <div class="file-name">财务预测表.xlsx</div>
  810. <div class="file-meta">
  811. <span>1.2 MB</span>
  812. <span class="file-status done">✓ 已完成</span>
  813. </div>
  814. </div>
  815. </div>
  816. <div class="file-item" onclick="highlightFile(this)">
  817. <span class="file-icon md">📄</span>
  818. <div class="file-info">
  819. <div class="file-name">会议纪要.md</div>
  820. <div class="file-meta">
  821. <span>48 KB</span>
  822. <span class="file-status done">✓ 已完成</span>
  823. </div>
  824. </div>
  825. </div>
  826. </div>
  827. </div>
  828. </div>
  829. <!-- 中间编辑区 -->
  830. <div class="center-panel">
  831. <div class="editor-title-bar">
  832. <div class="editor-main-title">智慧园区建设项目可行性研究报告</div>
  833. <div class="view-toggle">
  834. <button class="view-btn active" id="viewOriginal" onclick="switchView('original')">📄 原文</button>
  835. <button class="view-btn" id="viewMarked" onclick="switchView('marked')">🏷️ 标记</button>
  836. </div>
  837. <button class="graph-btn" onclick="showGraphModal()" title="查看知识图谱">🔗</button>
  838. </div>
  839. <div class="editor-scroll">
  840. <!-- 原文视图 -->
  841. <div class="editor-content" id="contentOriginal" contenteditable="true" oncontextmenu="showContextMenu(event)">
  842. <h1>智慧园区建设项目可行性研究报告</h1>
  843. <h2>一、项目背景</h2>
  844. <p>随着数字经济的快速发展,智慧园区已成为推动产业升级和城市现代化的重要载体。本项目旨在构建集智能化管理、低碳绿色、产业协同于一体的新型智慧园区。</p>
  845. <h3>1.1 行业现状</h3>
  846. <p>根据最新市场调研数据显示,2024年中国智慧园区市场规模已达到1,789亿元,同比增长18%,预计2025年将突破2,100亿元。</p>
  847. <!-- 数据表格 -->
  848. <div class="data-table-card">
  849. <div class="data-table-header">
  850. <div class="data-table-title">
  851. <span>📊</span>
  852. <span>市场规模数据</span>
  853. </div>
  854. <div class="data-table-source">来源: 市场调研数据.pdf</div>
  855. </div>
  856. <table class="data-table">
  857. <thead>
  858. <tr>
  859. <th>年份</th>
  860. <th>市场规模(亿元)</th>
  861. <th>同比增长</th>
  862. </tr>
  863. </thead>
  864. <tbody>
  865. <tr><td>2022</td><td>1,280</td><td>15.2%</td></tr>
  866. <tr><td>2023</td><td>1,516</td><td>18.4%</td></tr>
  867. <tr><td>2024</td><td>1,789</td><td>18.0%</td></tr>
  868. <tr><td>2025E</td><td>2,100</td><td>17.4%</td></tr>
  869. </tbody>
  870. </table>
  871. </div>
  872. <h2>二、项目概述</h2>
  873. <p>本项目位于华南地区核心区域,规划总面积约50万平方米,预计总投资12.5亿元。项目将分三期建设,首期重点打造智能制造产业集群和数字服务中心。</p>
  874. <h3>2.1 建设目标</h3>
  875. <p>通过三年建设周期,实现以下核心目标:</p>
  876. <ul style="margin-left:20px;margin-bottom:16px;line-height:2;">
  877. <li>入驻企业数量达到200家以上</li>
  878. <li>年产值突破50亿元</li>
  879. <li>创造就业岗位8000个</li>
  880. <li>获得国家级智慧园区认证</li>
  881. </ul>
  882. </div>
  883. <!-- 标记视图 -->
  884. <div class="editor-content" id="contentMarked" style="display:none;" contenteditable="true" oncontextmenu="showContextMenu(event)">
  885. <h1>智慧园区建设项目可行性研究报告</h1>
  886. <h2>一、项目背景</h2>
  887. <p>随着数字经济的快速发展,<span class="entity-highlight entity" onclick="showEntityEditModal(event, 'smartpark')" contenteditable="false">智慧园区</span>已成为推动<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'upgrade')" contenteditable="false">产业升级</span>和<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'modern')" contenteditable="false">城市现代化</span>的重要载体。本项目旨在构建集<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'ai')" contenteditable="false">智能化管理</span>、<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'green')" contenteditable="false">低碳绿色</span>、产业协同于一体的新型智慧园区。</p>
  888. <!-- AI优化建议卡片 - 只在标记视图显示 -->
  889. <div class="ai-suggestion-card" id="aiSuggestionCard" contenteditable="false">
  890. <div class="ai-suggestion-header">
  891. <span class="ai-suggestion-icon">💡</span>
  892. <span class="ai-suggestion-title">AI 优化建议</span>
  893. </div>
  894. <div class="ai-suggestion-content">
  895. 此处可补充具体的政策文件引用,增强论述的权威性。已从《市场调研数据.pdf》中提取到《"十四五"数字经济发展规划》等相关政策信息。
  896. </div>
  897. <div class="ai-suggestion-actions">
  898. <button class="suggest-btn accept" onclick="acceptSuggestion()">✓ 采纳建议</button>
  899. <button class="suggest-btn ignore" onclick="ignoreSuggestion()">✕ 忽略</button>
  900. </div>
  901. </div>
  902. <h3>1.1 行业现状</h3>
  903. <p>根据最新市场调研数据显示,2024年中国<span class="entity-highlight entity" onclick="showEntityEditModal(event, 'smartpark')" contenteditable="false">智慧园区</span>市场规模已达到<span class="entity-highlight data" onclick="showEntityEditModal(event, 'data1')" contenteditable="false">1,789亿元</span>,同比增长<span class="entity-highlight data" onclick="showEntityEditModal(event, 'data2')" contenteditable="false">18%</span>,预计2025年将突破2,100亿元。</p>
  904. <!-- 数据表格 -->
  905. <div class="data-table-card" contenteditable="false">
  906. <div class="data-table-header">
  907. <div class="data-table-title">
  908. <span>📊</span>
  909. <span>市场规模数据</span>
  910. </div>
  911. <div class="data-table-source">来源: 市场调研数据.pdf</div>
  912. </div>
  913. <table class="data-table">
  914. <thead>
  915. <tr>
  916. <th>年份</th>
  917. <th>市场规模(亿元)</th>
  918. <th>同比增长</th>
  919. </tr>
  920. </thead>
  921. <tbody>
  922. <tr><td>2022</td><td>1,280</td><td>15.2%</td></tr>
  923. <tr><td>2023</td><td>1,516</td><td>18.4%</td></tr>
  924. <tr><td>2024</td><td>1,789</td><td>18.0%</td></tr>
  925. <tr><td>2025E</td><td>2,100</td><td>17.4%</td></tr>
  926. </tbody>
  927. </table>
  928. </div>
  929. <h2>二、项目概述</h2>
  930. <p>本项目位于<span class="entity-highlight location" onclick="showEntityEditModal(event, 'location')" contenteditable="false">华南地区</span>核心区域,规划总面积约<span class="entity-highlight data" onclick="showEntityEditModal(event, 'data4')" contenteditable="false">50万平方米</span>,预计总投资<span class="entity-highlight data" onclick="showEntityEditModal(event, 'data3')" contenteditable="false">12.5亿元</span>。项目将分三期建设,首期重点打造<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'manufacture')" contenteditable="false">智能制造产业集群</span>和<span class="entity-highlight concept" onclick="showEntityEditModal(event, 'digital')" contenteditable="false">数字服务中心</span>。</p>
  931. <h3>2.1 建设目标</h3>
  932. <p>通过三年建设周期,实现以下核心目标:</p>
  933. <ul style="margin-left:20px;margin-bottom:16px;line-height:2;">
  934. <li>入驻企业数量达到<span class="entity-highlight" onclick="showEntityInfo('200家')">200家</span>以上</li>
  935. <li>年产值突破<span class="entity-highlight" onclick="showEntityInfo('50亿元')">50亿元</span></li>
  936. <li>创造就业岗位<span class="entity-highlight" onclick="showEntityInfo('8000个')">8000个</span></li>
  937. <li>获得<span class="entity-highlight" onclick="showEntityInfo('国家级智慧园区认证')">国家级智慧园区认证</span></li>
  938. </ul>
  939. </div>
  940. </div>
  941. </div>
  942. <!-- 右侧AI助手面板 -->
  943. <div class="right-panel">
  944. <!-- 要素管理区 -->
  945. <div class="element-section">
  946. <div class="element-header">
  947. <div class="element-title">
  948. <span>🏷️</span>
  949. <span>要素管理</span>
  950. <span class="element-count">(15个)</span>
  951. </div>
  952. <span style="font-size:11px;color:var(--primary);cursor:pointer;" onclick="showGraphModal()">查看图谱 →</span>
  953. </div>
  954. <!-- 要素标签容器 - 固定高度可滚动 -->
  955. <div class="element-tags-wrap" id="elementTagsWrap">
  956. <span class="element-tag entity" draggable="true" ondragstart="handleTagDragStart(event, '智慧园区')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'smartpark')">
  957. <span class="tag-icon">🏢</span>
  958. <span class="tag-name">智慧园区</span>
  959. </span>
  960. <span class="element-tag concept" draggable="true" ondragstart="handleTagDragStart(event, '产业升级')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'upgrade')">
  961. <span class="tag-icon">📈</span>
  962. <span class="tag-name">产业升级</span>
  963. </span>
  964. <span class="element-tag concept" draggable="true" ondragstart="handleTagDragStart(event, '城市现代化')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'modern')">
  965. <span class="tag-icon">🌆</span>
  966. <span class="tag-name">城市现代化</span>
  967. </span>
  968. <span class="element-tag concept" draggable="true" ondragstart="handleTagDragStart(event, '智能化管理')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'ai')">
  969. <span class="tag-icon">🤖</span>
  970. <span class="tag-name">智能化管理</span>
  971. </span>
  972. <span class="element-tag concept" draggable="true" ondragstart="handleTagDragStart(event, '低碳绿色')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'green')">
  973. <span class="tag-icon">🌱</span>
  974. <span class="tag-name">低碳绿色</span>
  975. </span>
  976. <span class="element-tag location" draggable="true" ondragstart="handleTagDragStart(event, '华南地区')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'location')">
  977. <span class="tag-icon">📍</span>
  978. <span class="tag-name">华南地区</span>
  979. </span>
  980. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '1,789亿元')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data1')">
  981. <span class="tag-icon">💰</span>
  982. <span class="tag-name">1,789亿元</span>
  983. </span>
  984. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '18%')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data2')">
  985. <span class="tag-icon">📊</span>
  986. <span class="tag-name">18%</span>
  987. </span>
  988. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '12.5亿元')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data3')">
  989. <span class="tag-icon">💵</span>
  990. <span class="tag-name">12.5亿元</span>
  991. </span>
  992. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '50万平方米')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data4')">
  993. <span class="tag-icon">📐</span>
  994. <span class="tag-name">50万m²</span>
  995. </span>
  996. <!-- 更多标签(滚动可见) -->
  997. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '200家')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data5')">
  998. <span class="tag-icon">🏭</span>
  999. <span class="tag-name">200家</span>
  1000. </span>
  1001. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '50亿元')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data6')">
  1002. <span class="tag-icon">💎</span>
  1003. <span class="tag-name">50亿元</span>
  1004. </span>
  1005. <span class="element-tag data" draggable="true" ondragstart="handleTagDragStart(event, '8000个')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'data7')">
  1006. <span class="tag-icon">👥</span>
  1007. <span class="tag-name">8000个岗位</span>
  1008. </span>
  1009. <span class="element-tag asset" draggable="true" ondragstart="handleTagDragStart(event, '[柱状图]')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'chart')">
  1010. <span class="tag-icon">📊</span>
  1011. <span class="tag-name">趋势图</span>
  1012. </span>
  1013. <span class="element-tag asset" draggable="true" ondragstart="handleTagDragStart(event, '[结论模板]')" ondragend="handleTagDragEnd(event)" onclick="showTagPopover(event, 'template')">
  1014. <span class="tag-icon">📝</span>
  1015. <span class="tag-name">结论模板</span>
  1016. </span>
  1017. </div>
  1018. <div class="element-hint">💡 点击查看详情,拖拽插入正文</div>
  1019. </div>
  1020. <!-- 要素详情弹出框 -->
  1021. <div class="element-popover" id="elementPopover">
  1022. <div class="popover-header">
  1023. <div class="popover-icon entity" id="popoverIcon">🏢</div>
  1024. <div class="popover-title" id="popoverTitle">智慧园区</div>
  1025. <button class="popover-close" onclick="hideTagPopover()">×</button>
  1026. </div>
  1027. <div class="popover-body">
  1028. <div class="popover-section">
  1029. <div class="popover-label">类型</div>
  1030. <div class="popover-value" id="popoverType">核心实体</div>
  1031. </div>
  1032. <div class="popover-section">
  1033. <div class="popover-label">来源</div>
  1034. <div class="popover-value" id="popoverSource">项目可行性研究报告.docx</div>
  1035. </div>
  1036. <div class="popover-section">
  1037. <div class="popover-label">关联要素</div>
  1038. <div class="popover-relations" id="popoverRelations">
  1039. <span class="popover-relation">→ 产业升级</span>
  1040. <span class="popover-relation">→ 城市现代化</span>
  1041. </div>
  1042. </div>
  1043. <div class="popover-actions">
  1044. <button class="btn" onclick="showToast('已定位到文档', 'info');hideTagPopover();">📍 定位</button>
  1045. <button class="btn btn-primary" onclick="insertTagToEditor();hideTagPopover();">➕ 插入</button>
  1046. </div>
  1047. </div>
  1048. </div>
  1049. <!-- AI助手区 -->
  1050. <div class="ai-assistant">
  1051. <div class="ai-header">
  1052. <div class="ai-avatar-sm">🤖</div>
  1053. <div class="ai-info">
  1054. <div class="ai-name">灵越 AI 助手</div>
  1055. <div class="ai-status">● 已加载项目上下文</div>
  1056. </div>
  1057. </div>
  1058. <!-- AI Tab切换 -->
  1059. <div class="ai-tabs">
  1060. <div class="ai-tab active" onclick="switchAiTab(this, 'chat')">💬 对话</div>
  1061. <div class="ai-tab" onclick="switchAiTab(this, 'suggest')">💡 建议</div>
  1062. <div class="ai-tab" onclick="switchAiTab(this, 'memory')">🧠 记忆</div>
  1063. </div>
  1064. <!-- 消息区 -->
  1065. <div class="ai-messages" id="aiMessages">
  1066. <div class="msg ai">
  1067. <div class="msg-avatar">🤖</div>
  1068. <div class="msg-bubble">您好!我已分析上传的5份文档,构建了项目知识图谱。有什么可以帮您的?</div>
  1069. </div>
  1070. <div class="msg user">
  1071. <div class="msg-avatar">张</div>
  1072. <div class="msg-bubble">帮我补充市场分析部分的竞争格局内容</div>
  1073. </div>
  1074. <div class="msg ai">
  1075. <div class="msg-avatar">🤖</div>
  1076. <div class="msg-bubble">好的,我已从《市场调研数据.pdf》中提取了竞争格局相关数据。建议如下:</div>
  1077. </div>
  1078. <!-- 内容建议卡片 -->
  1079. <div class="content-suggestion">
  1080. <div class="content-suggestion-header">
  1081. <span>✨</span>
  1082. <span class="content-suggestion-title">内容建议</span>
  1083. </div>
  1084. <div class="content-suggestion-body">建议在市场分析部分增加竞争格局分析章节:</div>
  1085. <ul class="content-suggestion-list">
  1086. <li>主要竞争对手市占率对比</li>
  1087. <li>竞争优势SWOT分析</li>
  1088. <li>差异化竞争策略</li>
  1089. </ul>
  1090. <div class="content-suggestion-actions">
  1091. <button class="suggest-btn accept" onclick="acceptContentSuggestion()">✓ 采纳</button>
  1092. <button class="suggest-btn ignore" onclick="showToast('已忽略', 'info')">✕ 忽略</button>
  1093. </div>
  1094. </div>
  1095. </div>
  1096. <!-- 输入区 - 底部固定 -->
  1097. <div class="ai-input-area">
  1098. <div class="ai-input-box">
  1099. <textarea id="aiTextarea" placeholder="输入指令,按 Enter 发送..." rows="1" onkeydown="handleAiKey(event)" oninput="autoResizeTextarea(this)"></textarea>
  1100. </div>
  1101. <div class="ai-input-hint">
  1102. <span>按 Enter 发送,Shift+Enter 换行</span>
  1103. <span>@引用上下文</span>
  1104. </div>
  1105. </div>
  1106. </div>
  1107. </div>
  1108. </div>
  1109. </div>
  1110. <!-- 知识图谱弹窗 -->
  1111. <div class="graph-modal" id="graphModal">
  1112. <div class="graph-container">
  1113. <div class="graph-header">
  1114. <div class="graph-title">
  1115. <span>🔗</span>
  1116. <span>标记要素关系图谱</span>
  1117. <span style="font-size:12px;color:var(--text3);font-weight:normal;margin-left:8px;">共 15 个实体 · 23 条关系</span>
  1118. </div>
  1119. <div style="display:flex;align-items:center;gap:12px;">
  1120. <!-- 视图切换 -->
  1121. <div style="display:flex;border:1px solid var(--border);border-radius:6px;overflow:hidden;">
  1122. <button class="graph-view-btn active" id="graphViewBtn" onclick="switchGraphView('graph')">
  1123. <span>🔗</span> 图谱
  1124. </button>
  1125. <button class="graph-view-btn" id="listViewBtn" onclick="switchGraphView('list')">
  1126. <span>📋</span> 列表
  1127. </button>
  1128. </div>
  1129. <button class="graph-close" onclick="closeGraphModal()">×</button>
  1130. </div>
  1131. </div>
  1132. <!-- 图谱视图 -->
  1133. <div class="graph-body" id="graphViewBody">
  1134. <!-- 图例 -->
  1135. <div class="graph-legend">
  1136. <div class="legend-title">图例说明</div>
  1137. <div class="legend-item"><span class="legend-dot entity"></span>核心实体</div>
  1138. <div class="legend-item"><span class="legend-dot concept"></span>概念/技术</div>
  1139. <div class="legend-item"><span class="legend-dot data"></span>数据/指标</div>
  1140. <div class="legend-item"><span class="legend-dot location"></span>地点/组织</div>
  1141. </div>
  1142. <!-- 连接线 -->
  1143. <svg class="graph-lines" width="100%" height="100%">
  1144. <line x1="450" y1="280" x2="250" y2="150" stroke="#1890ff" stroke-width="2" stroke-opacity="0.3"/>
  1145. <line x1="450" y1="280" x2="650" y2="150" stroke="#1890ff" stroke-width="2" stroke-opacity="0.3"/>
  1146. <line x1="450" y1="280" x2="200" y2="320" stroke="#722ed1" stroke-width="2" stroke-opacity="0.3"/>
  1147. <line x1="450" y1="280" x2="700" y2="320" stroke="#722ed1" stroke-width="2" stroke-opacity="0.3"/>
  1148. <line x1="450" y1="280" x2="280" y2="450" stroke="#52c41a" stroke-width="2" stroke-opacity="0.3"/>
  1149. <line x1="450" y1="280" x2="620" y2="450" stroke="#52c41a" stroke-width="2" stroke-opacity="0.3"/>
  1150. <line x1="450" y1="280" x2="450" y2="480" stroke="#faad14" stroke-width="2" stroke-opacity="0.3"/>
  1151. <line x1="250" y1="150" x2="200" y2="320" stroke="#e8e8e8" stroke-width="1.5"/>
  1152. <line x1="650" y1="150" x2="700" y2="320" stroke="#e8e8e8" stroke-width="1.5"/>
  1153. <line x1="200" y1="320" x2="280" y2="450" stroke="#e8e8e8" stroke-width="1.5"/>
  1154. <line x1="700" y1="320" x2="620" y2="450" stroke="#e8e8e8" stroke-width="1.5"/>
  1155. </svg>
  1156. <!-- 节点 -->
  1157. <div class="graph-node" style="left:410px;top:240px;" onclick="showToast('智慧园区 - 核心实体', 'info')">
  1158. <div class="node-circle primary center">🏢</div>
  1159. <div class="node-label">智慧园区</div>
  1160. </div>
  1161. <div class="graph-node" style="left:220px;top:110px;" onclick="showToast('产业升级 - 概念', 'info')">
  1162. <div class="node-circle purple">📈</div>
  1163. <div class="node-label">产业升级</div>
  1164. </div>
  1165. <div class="graph-node" style="left:620px;top:110px;" onclick="showToast('城市现代化 - 概念', 'info')">
  1166. <div class="node-circle purple">🌆</div>
  1167. <div class="node-label">城市现代化</div>
  1168. </div>
  1169. <div class="graph-node" style="left:160px;top:280px;" onclick="showToast('智能化管理 - 技术', 'info')">
  1170. <div class="node-circle purple">🤖</div>
  1171. <div class="node-label">智能化管理</div>
  1172. </div>
  1173. <div class="graph-node" style="left:670px;top:280px;" onclick="showToast('低碳绿色 - 概念', 'info')">
  1174. <div class="node-circle green">🌱</div>
  1175. <div class="node-label">低碳绿色</div>
  1176. </div>
  1177. <div class="graph-node" style="left:240px;top:410px;" onclick="showToast('1,789亿元 - 市场规模数据', 'info')">
  1178. <div class="node-circle green">💰</div>
  1179. <div class="node-label">1,789亿元</div>
  1180. </div>
  1181. <div class="graph-node" style="left:580px;top:410px;" onclick="showToast('18% - 增长率数据', 'info')">
  1182. <div class="node-circle green">📊</div>
  1183. <div class="node-label">18%增长率</div>
  1184. </div>
  1185. <div class="graph-node" style="left:410px;top:440px;" onclick="showToast('华南地区 - 地点', 'info')">
  1186. <div class="node-circle orange">📍</div>
  1187. <div class="node-label">华南地区</div>
  1188. </div>
  1189. <div class="graph-node" style="left:100px;top:180px;" onclick="showToast('50万平方米 - 面积数据', 'info')">
  1190. <div class="node-circle green" style="width:45px;height:45px;font-size:16px;">📐</div>
  1191. <div class="node-label">50万m²</div>
  1192. </div>
  1193. <div class="graph-node" style="left:780px;top:200px;" onclick="showToast('12.5亿元 - 投资额', 'info')">
  1194. <div class="node-circle green" style="width:45px;height:45px;font-size:16px;">💵</div>
  1195. <div class="node-label">12.5亿元</div>
  1196. </div>
  1197. </div>
  1198. <!-- 列表视图 -->
  1199. <div class="graph-list-body" id="listViewBody" style="display:none;">
  1200. <!-- 筛选栏 -->
  1201. <div style="padding:16px 20px;border-bottom:1px solid var(--border);display:flex;gap:12px;align-items:center;">
  1202. <input type="text" placeholder="🔍 搜索实体..." style="flex:1;max-width:280px;padding:8px 12px;border:1px solid var(--border);border-radius:6px;font-size:13px;outline:none;">
  1203. <div style="display:flex;gap:6px;">
  1204. <span class="list-filter-tag active" onclick="filterListType(this, 'all')">全部</span>
  1205. <span class="list-filter-tag" onclick="filterListType(this, 'entity')">核心实体</span>
  1206. <span class="list-filter-tag" onclick="filterListType(this, 'concept')">概念/技术</span>
  1207. <span class="list-filter-tag" onclick="filterListType(this, 'data')">数据/指标</span>
  1208. <span class="list-filter-tag" onclick="filterListType(this, 'location')">地点/组织</span>
  1209. </div>
  1210. </div>
  1211. <!-- 列表内容 -->
  1212. <div style="flex:1;overflow-y:auto;padding:16px 20px;">
  1213. <!-- 核心实体组 -->
  1214. <div class="list-group">
  1215. <div class="list-group-header">
  1216. <span class="list-group-dot" style="background:var(--primary);"></span>
  1217. <span>核心实体</span>
  1218. <span class="list-group-count">1</span>
  1219. </div>
  1220. <div class="list-item" onclick="showToast('定位到: 智慧园区', 'info')">
  1221. <div class="list-item-icon" style="background:linear-gradient(135deg, #e6f7ff, #bae7ff);color:var(--primary);">🏢</div>
  1222. <div class="list-item-info">
  1223. <div class="list-item-name">智慧园区</div>
  1224. <div class="list-item-desc">出现 5 次 · 关联 8 个实体</div>
  1225. </div>
  1226. <div class="list-item-relations">
  1227. <span class="relation-tag">→ 产业升级</span>
  1228. <span class="relation-tag">→ 城市现代化</span>
  1229. <span class="relation-tag">+6</span>
  1230. </div>
  1231. </div>
  1232. </div>
  1233. <!-- 概念/技术组 -->
  1234. <div class="list-group">
  1235. <div class="list-group-header">
  1236. <span class="list-group-dot" style="background:#722ed1;"></span>
  1237. <span>概念/技术</span>
  1238. <span class="list-group-count">4</span>
  1239. </div>
  1240. <div class="list-item" onclick="showToast('定位到: 产业升级', 'info')">
  1241. <div class="list-item-icon" style="background:linear-gradient(135deg, #f9f0ff, #efdbff);color:#722ed1;">📈</div>
  1242. <div class="list-item-info">
  1243. <div class="list-item-name">产业升级</div>
  1244. <div class="list-item-desc">出现 2 次 · 关联 3 个实体</div>
  1245. </div>
  1246. <div class="list-item-relations">
  1247. <span class="relation-tag">→ 智慧园区</span>
  1248. <span class="relation-tag">→ 智能化管理</span>
  1249. </div>
  1250. </div>
  1251. <div class="list-item" onclick="showToast('定位到: 城市现代化', 'info')">
  1252. <div class="list-item-icon" style="background:linear-gradient(135deg, #f9f0ff, #efdbff);color:#722ed1;">🌆</div>
  1253. <div class="list-item-info">
  1254. <div class="list-item-name">城市现代化</div>
  1255. <div class="list-item-desc">出现 1 次 · 关联 2 个实体</div>
  1256. </div>
  1257. <div class="list-item-relations">
  1258. <span class="relation-tag">→ 智慧园区</span>
  1259. </div>
  1260. </div>
  1261. <div class="list-item" onclick="showToast('定位到: 智能化管理', 'info')">
  1262. <div class="list-item-icon" style="background:linear-gradient(135deg, #f9f0ff, #efdbff);color:#722ed1;">🤖</div>
  1263. <div class="list-item-info">
  1264. <div class="list-item-name">智能化管理</div>
  1265. <div class="list-item-desc">出现 3 次 · 关联 4 个实体</div>
  1266. </div>
  1267. <div class="list-item-relations">
  1268. <span class="relation-tag">→ 智慧园区</span>
  1269. <span class="relation-tag">→ 低碳绿色</span>
  1270. </div>
  1271. </div>
  1272. <div class="list-item" onclick="showToast('定位到: 低碳绿色', 'info')">
  1273. <div class="list-item-icon" style="background:linear-gradient(135deg, #f6ffed, #d9f7be);color:var(--success);">🌱</div>
  1274. <div class="list-item-info">
  1275. <div class="list-item-name">低碳绿色</div>
  1276. <div class="list-item-desc">出现 2 次 · 关联 2 个实体</div>
  1277. </div>
  1278. <div class="list-item-relations">
  1279. <span class="relation-tag">→ 智慧园区</span>
  1280. </div>
  1281. </div>
  1282. </div>
  1283. <!-- 数据/指标组 -->
  1284. <div class="list-group">
  1285. <div class="list-group-header">
  1286. <span class="list-group-dot" style="background:var(--success);"></span>
  1287. <span>数据/指标</span>
  1288. <span class="list-group-count">6</span>
  1289. </div>
  1290. <div class="list-item" onclick="showToast('定位到: 1,789亿元', 'info')">
  1291. <div class="list-item-icon" style="background:linear-gradient(135deg, #f6ffed, #d9f7be);color:var(--success);">💰</div>
  1292. <div class="list-item-info">
  1293. <div class="list-item-name">1,789亿元</div>
  1294. <div class="list-item-desc">市场规模 · 来源: 市场调研数据.pdf</div>
  1295. </div>
  1296. <div class="list-item-relations">
  1297. <span class="relation-tag">→ 智慧园区</span>
  1298. </div>
  1299. </div>
  1300. <div class="list-item" onclick="showToast('定位到: 18%增长率', 'info')">
  1301. <div class="list-item-icon" style="background:linear-gradient(135deg, #f6ffed, #d9f7be);color:var(--success);">📊</div>
  1302. <div class="list-item-info">
  1303. <div class="list-item-name">18%</div>
  1304. <div class="list-item-desc">同比增长率 · 来源: 市场调研数据.pdf</div>
  1305. </div>
  1306. <div class="list-item-relations">
  1307. <span class="relation-tag">→ 1,789亿元</span>
  1308. </div>
  1309. </div>
  1310. <div class="list-item" onclick="showToast('定位到: 50万平方米', 'info')">
  1311. <div class="list-item-icon" style="background:linear-gradient(135deg, #f6ffed, #d9f7be);color:var(--success);">📐</div>
  1312. <div class="list-item-info">
  1313. <div class="list-item-name">50万平方米</div>
  1314. <div class="list-item-desc">规划面积 · 来源: 项目可行性研究报告.docx</div>
  1315. </div>
  1316. <div class="list-item-relations">
  1317. <span class="relation-tag">→ 华南地区</span>
  1318. </div>
  1319. </div>
  1320. <div class="list-item" onclick="showToast('定位到: 12.5亿元', 'info')">
  1321. <div class="list-item-icon" style="background:linear-gradient(135deg, #f6ffed, #d9f7be);color:var(--success);">💵</div>
  1322. <div class="list-item-info">
  1323. <div class="list-item-name">12.5亿元</div>
  1324. <div class="list-item-desc">总投资额 · 来源: 财务预测表.xlsx</div>
  1325. </div>
  1326. <div class="list-item-relations">
  1327. <span class="relation-tag">→ 智慧园区</span>
  1328. </div>
  1329. </div>
  1330. </div>
  1331. <!-- 地点/组织组 -->
  1332. <div class="list-group">
  1333. <div class="list-group-header">
  1334. <span class="list-group-dot" style="background:var(--warning);"></span>
  1335. <span>地点/组织</span>
  1336. <span class="list-group-count">2</span>
  1337. </div>
  1338. <div class="list-item" onclick="showToast('定位到: 华南地区', 'info')">
  1339. <div class="list-item-icon" style="background:linear-gradient(135deg, #fff7e6, #ffe7ba);color:var(--warning);">📍</div>
  1340. <div class="list-item-info">
  1341. <div class="list-item-name">华南地区</div>
  1342. <div class="list-item-desc">出现 3 次 · 关联 4 个实体</div>
  1343. </div>
  1344. <div class="list-item-relations">
  1345. <span class="relation-tag">→ 智慧园区</span>
  1346. <span class="relation-tag">→ 50万m²</span>
  1347. </div>
  1348. </div>
  1349. <div class="list-item" onclick="showToast('定位到: 华南事业部', 'info')">
  1350. <div class="list-item-icon" style="background:linear-gradient(135deg, #fff7e6, #ffe7ba);color:var(--warning);">🏛️</div>
  1351. <div class="list-item-info">
  1352. <div class="list-item-name">华南事业部</div>
  1353. <div class="list-item-desc">组织机构 · 项目负责部门</div>
  1354. </div>
  1355. <div class="list-item-relations">
  1356. <span class="relation-tag">→ 张三</span>
  1357. </div>
  1358. </div>
  1359. </div>
  1360. </div>
  1361. </div>
  1362. </div>
  1363. </div>
  1364. <!-- 右键菜单 -->
  1365. <div class="context-menu" id="contextMenu">
  1366. <div class="context-menu-item" onclick="execContextAction('copy')">
  1367. <span class="icon">📋</span>
  1368. <span>复制</span>
  1369. <span class="shortcut">Ctrl+C</span>
  1370. </div>
  1371. <div class="context-menu-item" onclick="execContextAction('cut')">
  1372. <span class="icon">✂️</span>
  1373. <span>剪切</span>
  1374. <span class="shortcut">Ctrl+X</span>
  1375. </div>
  1376. <div class="context-menu-item" onclick="execContextAction('paste')">
  1377. <span class="icon">📄</span>
  1378. <span>粘贴</span>
  1379. <span class="shortcut">Ctrl+V</span>
  1380. </div>
  1381. <div class="context-menu-divider"></div>
  1382. <div class="context-menu-item" onclick="execContextAction('polish')">
  1383. <span class="icon">✨</span>
  1384. <span>AI 润色</span>
  1385. </div>
  1386. <div class="context-menu-item" onclick="execContextAction('spell')">
  1387. <span class="icon">📝</span>
  1388. <span>检查拼写</span>
  1389. </div>
  1390. <div class="context-menu-divider"></div>
  1391. <div class="context-menu-item" onclick="execContextAction('mark')">
  1392. <span class="icon">🏷️</span>
  1393. <span>标记为要素</span>
  1394. </div>
  1395. <div class="context-menu-item" onclick="execContextAction('quote')">
  1396. <span class="icon">💬</span>
  1397. <span>引用到AI助手</span>
  1398. </div>
  1399. </div>
  1400. <!-- AI结果确认弹窗 -->
  1401. <div class="ai-confirm-modal" id="aiConfirmModal">
  1402. <div class="ai-confirm-card">
  1403. <div class="ai-confirm-header">
  1404. <div class="ai-confirm-icon" id="aiConfirmIcon">✨</div>
  1405. <div class="ai-confirm-title">
  1406. <h3 id="aiConfirmTitle">AI 润色结果</h3>
  1407. <span id="aiConfirmSubtitle">请确认是否应用以下修改</span>
  1408. </div>
  1409. <button class="ai-confirm-close" onclick="closeAiConfirmModal()">×</button>
  1410. </div>
  1411. <div class="ai-confirm-body">
  1412. <div class="ai-confirm-section">
  1413. <div class="ai-confirm-label">📄 原文内容</div>
  1414. <div class="ai-confirm-text original" id="aiConfirmOriginal">原始文本内容</div>
  1415. </div>
  1416. <div class="ai-confirm-diff">↓</div>
  1417. <div class="ai-confirm-section">
  1418. <div class="ai-confirm-label">✨ <span id="aiConfirmResultLabel">润色结果</span></div>
  1419. <div class="ai-confirm-text result" id="aiConfirmResult">润色后的文本内容</div>
  1420. </div>
  1421. </div>
  1422. <div class="ai-confirm-footer">
  1423. <button class="btn" onclick="closeAiConfirmModal()">取消</button>
  1424. <button class="btn btn-primary" onclick="applyAiResult()">✓ 确认替换</button>
  1425. </div>
  1426. </div>
  1427. </div>
  1428. <!-- 标记为要素弹窗 -->
  1429. <div class="mark-entity-modal" id="markEntityModal">
  1430. <div class="mark-entity-card">
  1431. <div class="mark-entity-header">
  1432. <div class="ai-confirm-icon">🏷️</div>
  1433. <div class="ai-confirm-title">
  1434. <h3>标记为要素</h3>
  1435. <span>选择要素类型以创建标签</span>
  1436. </div>
  1437. <button class="ai-confirm-close" onclick="closeMarkEntityModal()">×</button>
  1438. </div>
  1439. <div class="mark-entity-body">
  1440. <div class="mark-entity-preview" id="markEntityPreview">"选中的文本"</div>
  1441. <div class="ai-confirm-label">选择要素类型</div>
  1442. <div class="mark-entity-types" id="markEntityTypes">
  1443. <div class="mark-entity-type selected" onclick="selectEntityType(this, 'entity')">
  1444. <div class="type-icon">🏢</div>
  1445. <div class="type-name">核心实体</div>
  1446. </div>
  1447. <div class="mark-entity-type" onclick="selectEntityType(this, 'concept')">
  1448. <div class="type-icon">💡</div>
  1449. <div class="type-name">概念/技术</div>
  1450. </div>
  1451. <div class="mark-entity-type" onclick="selectEntityType(this, 'data')">
  1452. <div class="type-icon">📊</div>
  1453. <div class="type-name">数据/指标</div>
  1454. </div>
  1455. <div class="mark-entity-type" onclick="selectEntityType(this, 'location')">
  1456. <div class="type-icon">📍</div>
  1457. <div class="type-name">地点/组织</div>
  1458. </div>
  1459. </div>
  1460. </div>
  1461. <div class="mark-entity-footer">
  1462. <button class="btn" onclick="closeMarkEntityModal()">取消</button>
  1463. <button class="btn btn-primary" onclick="confirmMarkEntity()">✓ 确认标记</button>
  1464. </div>
  1465. </div>
  1466. </div>
  1467. <!-- 实体标签编辑弹窗 -->
  1468. <div class="entity-edit-modal" id="entityEditModal">
  1469. <div class="entity-edit-card">
  1470. <div class="entity-edit-header">
  1471. <div class="entity-edit-icon" id="editEntityIcon">🏢</div>
  1472. <div class="entity-edit-title">
  1473. <h3 id="editEntityName">智慧园区</h3>
  1474. <span id="editEntityType">核心实体 · 来自 项目可行性研究报告.docx</span>
  1475. </div>
  1476. <button class="entity-edit-close" onclick="closeEntityEditModal()">×</button>
  1477. </div>
  1478. <div class="entity-edit-body">
  1479. <!-- 数据关系表 -->
  1480. <div class="entity-edit-section">
  1481. <div class="entity-edit-label">📊 数据关系</div>
  1482. <table class="entity-relation-table">
  1483. <thead>
  1484. <tr>
  1485. <th style="width:30%">属性</th>
  1486. <th style="width:35%">原始值</th>
  1487. <th style="width:35%">当前值</th>
  1488. </tr>
  1489. </thead>
  1490. <tbody id="entityRelationBody">
  1491. <tr>
  1492. <td>标签名称</td>
  1493. <td class="original">智慧园区</td>
  1494. <td class="current"><span class="editable">智慧园区</span></td>
  1495. </tr>
  1496. <tr>
  1497. <td>实体类型</td>
  1498. <td class="original">核心实体</td>
  1499. <td class="current">核心实体</td>
  1500. </tr>
  1501. <tr>
  1502. <td>数据来源</td>
  1503. <td class="original">项目报告.docx</td>
  1504. <td class="current">项目报告.docx</td>
  1505. </tr>
  1506. </tbody>
  1507. </table>
  1508. </div>
  1509. <!-- 编辑区域 -->
  1510. <div class="entity-edit-row">
  1511. <div class="entity-edit-section">
  1512. <div class="entity-edit-label">🏷️ 标签值</div>
  1513. <input type="text" class="entity-edit-input" id="editEntityValue" value="智慧园区">
  1514. </div>
  1515. <div class="entity-edit-section">
  1516. <div class="entity-edit-label">📁 所属分类</div>
  1517. <select class="entity-edit-input" id="editEntityCategory">
  1518. <option value="entity" selected>核心实体</option>
  1519. <option value="concept">概念/技术</option>
  1520. <option value="data">数据/指标</option>
  1521. <option value="location">地点/组织</option>
  1522. </select>
  1523. </div>
  1524. </div>
  1525. <!-- 关联要素 -->
  1526. <div class="entity-edit-section">
  1527. <div class="entity-edit-label">🔗 关联要素</div>
  1528. <div id="editEntityRelations" style="display:flex;flex-wrap:wrap;gap:8px;">
  1529. <span class="popover-relation" onclick="showToast('跳转到: 产业升级', 'info')">产业升级</span>
  1530. <span class="popover-relation" onclick="showToast('跳转到: 城市现代化', 'info')">城市现代化</span>
  1531. <span class="popover-relation" onclick="showToast('跳转到: 1,789亿元', 'info')">1,789亿元</span>
  1532. <span style="padding:3px 8px;background:var(--primary-light);border-radius:4px;font-size:11px;color:var(--primary);cursor:pointer;" onclick="showToast('添加关联', 'info')">+ 添加</span>
  1533. </div>
  1534. </div>
  1535. </div>
  1536. <div class="entity-edit-footer">
  1537. <button class="btn" onclick="showToast('已删除标记', 'info');closeEntityEditModal();">🗑️ 删除标记</button>
  1538. <button class="btn" onclick="closeEntityEditModal()">取消</button>
  1539. <button class="btn btn-primary" onclick="saveEntityEdit()">保存更改</button>
  1540. </div>
  1541. </div>
  1542. </div>
  1543. <!-- 导出菜单 -->
  1544. <div id="exportMenu" style="position:fixed;background:var(--white);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,0.15);min-width:180px;display:none;z-index:2001;overflow:hidden;">
  1545. <div style="padding:12px 16px;cursor:pointer;font-size:13px;display:flex;align-items:center;gap:10px;transition:background 0.15s;" onmouseover="this.style.background='var(--primary-light)'" onmouseout="this.style.background=''" onclick="showToast('导出PDF成功', 'success');hideExportMenu()">
  1546. <span>📄</span><span>导出为 PDF</span>
  1547. </div>
  1548. <div style="padding:12px 16px;cursor:pointer;font-size:13px;display:flex;align-items:center;gap:10px;transition:background 0.15s;" onmouseover="this.style.background='var(--primary-light)'" onmouseout="this.style.background=''" onclick="showToast('导出Word成功', 'success');hideExportMenu()">
  1549. <span>📝</span><span>导出为 Word</span>
  1550. </div>
  1551. <div style="padding:12px 16px;cursor:pointer;font-size:13px;display:flex;align-items:center;gap:10px;transition:background 0.15s;" onmouseover="this.style.background='var(--primary-light)'" onmouseout="this.style.background=''" onclick="showToast('导出Markdown成功', 'success');hideExportMenu()">
  1552. <span>📋</span><span>导出为 Markdown</span>
  1553. </div>
  1554. <div style="height:1px;background:var(--border);"></div>
  1555. <div style="padding:12px 16px;cursor:pointer;font-size:13px;display:flex;align-items:center;gap:10px;transition:background 0.15s;" onmouseover="this.style.background='var(--primary-light)'" onmouseout="this.style.background=''" onclick="showToast('打印预览', 'info');hideExportMenu()">
  1556. <span>🖨️</span><span>打印</span>
  1557. </div>
  1558. </div>
  1559. <!-- FAB资源监控 -->
  1560. <div style="position:fixed;bottom:24px;right:24px;z-index:1000;" id="fabContainer">
  1561. <div id="fabPanel" style="position:absolute;bottom:60px;right:0;width:260px;background:var(--white);border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,0.15);display:none;overflow:hidden;">
  1562. <div style="padding:14px 16px;background:var(--data-gradient);color:white;font-weight:600;font-size:13px;">📊 资源监控</div>
  1563. <div style="padding:14px 16px;">
  1564. <div style="margin-bottom:12px;">
  1565. <div style="display:flex;justify-content:space-between;margin-bottom:4px;font-size:12px;"><span>Token 消耗</span><span style="font-weight:500;">15.6K / 20K</span></div>
  1566. <div style="height:6px;background:var(--bg);border-radius:3px;"><div style="height:100%;width:78%;background:var(--warning);border-radius:3px;"></div></div>
  1567. </div>
  1568. <div style="margin-bottom:12px;">
  1569. <div style="display:flex;justify-content:space-between;margin-bottom:4px;font-size:12px;"><span>GPU 显存</span><span style="font-weight:500;">3.6G / 8G</span></div>
  1570. <div style="height:6px;background:var(--bg);border-radius:3px;"><div style="height:100%;width:45%;background:var(--success);border-radius:3px;"></div></div>
  1571. </div>
  1572. <div style="display:flex;justify-content:space-between;padding:10px;background:var(--bg);border-radius:8px;">
  1573. <div style="text-align:center;"><div style="font-size:16px;font-weight:600;color:var(--primary);">¥3.12</div><div style="font-size:10px;color:var(--text3);">本次会话</div></div>
  1574. <div style="text-align:center;"><div style="font-size:16px;font-weight:600;color:var(--primary);">¥127.50</div><div style="font-size:10px;color:var(--text3);">本月累计</div></div>
  1575. </div>
  1576. </div>
  1577. </div>
  1578. <button style="width:50px;height:50px;border-radius:50%;background:var(--data-gradient);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:20px;color:white;box-shadow:0 6px 20px rgba(82,196,26,0.35);" onclick="toggleFab()">📊</button>
  1579. </div>
  1580. <!-- Toast容器 -->
  1581. <div id="toastBox" style="position:fixed;top:70px;right:24px;z-index:3000;display:flex;flex-direction:column;gap:8px;"></div>
  1582. <!-- 通知面板 -->
  1583. <div id="notifPanel" style="position:fixed;top:56px;right:0;width:360px;height:calc(100vh - 56px);background:var(--white);box-shadow:-4px 0 16px rgba(0,0,0,0.1);transform:translateX(100%);transition:transform 0.3s;z-index:999;display:flex;flex-direction:column;">
  1584. <div style="padding:18px;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;">
  1585. <span style="font-size:15px;font-weight:600;">消息通知</span>
  1586. <span style="font-size:12px;color:var(--primary);cursor:pointer;" onclick="showToast('已全部标为已读', 'success')">全部已读</span>
  1587. </div>
  1588. <div style="flex:1;overflow-y:auto;">
  1589. <div style="padding:14px 18px;border-bottom:1px solid var(--border);background:var(--primary-light);cursor:pointer;" onclick="openEditor()">
  1590. <div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
  1591. <span style="width:22px;height:22px;background:#f6ffed;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;">✅</span>
  1592. <span style="flex:1;font-weight:500;font-size:13px;">文档解析完成</span>
  1593. <span style="font-size:10px;color:var(--text3);">刚刚</span>
  1594. </div>
  1595. <div style="font-size:12px;color:var(--text2);">《市场调研数据.pdf》已解析完成,提取到35个实体</div>
  1596. </div>
  1597. <div style="padding:14px 18px;border-bottom:1px solid var(--border);cursor:pointer;">
  1598. <div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">
  1599. <span style="width:22px;height:22px;background:#fff7e6;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:11px;">💬</span>
  1600. <span style="flex:1;font-weight:500;font-size:13px;">李四评论了您的报告</span>
  1601. <span style="font-size:10px;color:var(--text3);">2小时前</span>
  1602. </div>
  1603. <div style="font-size:12px;color:var(--text2);">建议补充竞争格局分析...</div>
  1604. </div>
  1605. </div>
  1606. </div>
  1607. <!-- 遮罩 -->
  1608. <div id="overlay" style="position:fixed;inset:0;background:rgba(0,0,0,0.3);z-index:998;display:none;" onclick="closeAll()"></div>
  1609. <script>
  1610. // === 导航 ===
  1611. function navTo(page) {
  1612. document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
  1613. document.querySelectorAll('.menu-item').forEach(m => m.classList.remove('active'));
  1614. document.getElementById('page-' + page)?.classList.add('active');
  1615. document.querySelector('[data-page="' + page + '"]')?.classList.add('active');
  1616. document.getElementById('page-editor').classList.remove('active');
  1617. document.getElementById('sidebar').classList.remove('hidden');
  1618. document.getElementById('mainContent').style.display = '';
  1619. closeAll();
  1620. }
  1621. function goHome() { navTo('home'); }
  1622. // === 编辑器 ===
  1623. function openEditor() {
  1624. document.querySelectorAll('.page').forEach(p => p.classList.remove('active'));
  1625. document.getElementById('page-editor').classList.add('active');
  1626. document.getElementById('sidebar').classList.add('hidden');
  1627. document.getElementById('mainContent').style.display = 'none';
  1628. closeAll();
  1629. }
  1630. function closeEditor() { navTo('home'); }
  1631. // === 通知 ===
  1632. function toggleNotif() {
  1633. const panel = document.getElementById('notifPanel');
  1634. const overlay = document.getElementById('overlay');
  1635. const isOpen = panel.style.transform === 'translateX(0%)';
  1636. panel.style.transform = isOpen ? 'translateX(100%)' : 'translateX(0%)';
  1637. overlay.style.display = isOpen ? 'none' : 'block';
  1638. }
  1639. // === FAB ===
  1640. function toggleFab() {
  1641. const panel = document.getElementById('fabPanel');
  1642. panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
  1643. }
  1644. // === 思考模式 ===
  1645. function setMode(el) {
  1646. document.querySelectorAll('.mode-btn').forEach(b => b.classList.remove('active'));
  1647. el.classList.add('active');
  1648. showToast('已切换到 ' + el.textContent.trim(), 'success');
  1649. }
  1650. // === 首页AI输入 ===
  1651. function toggleSendBtn() {
  1652. const input = document.getElementById('homeAiInput');
  1653. const btn = document.getElementById('homeSendBtn');
  1654. btn.classList.toggle('show', input.value.trim().length > 0);
  1655. }
  1656. function handleHomeAi() {
  1657. const input = document.getElementById('homeAiInput');
  1658. if (input.value.trim()) {
  1659. showToast('AI正在处理...', 'info');
  1660. setTimeout(() => openEditor(), 1000);
  1661. input.value = '';
  1662. document.getElementById('homeSendBtn').classList.remove('show');
  1663. }
  1664. }
  1665. // === 要素管理 ===
  1666. // 要素数据
  1667. const tagData = {
  1668. smartpark: { icon: '🏢', type: 'entity', name: '智慧园区', typeText: '核心实体', source: '项目可行性研究报告.docx', relations: ['产业升级', '城市现代化', '智能化管理'] },
  1669. upgrade: { icon: '📈', type: 'concept', name: '产业升级', typeText: '概念', source: '项目可行性研究报告.docx', relations: ['智慧园区', '城市现代化'] },
  1670. modern: { icon: '🌆', type: 'concept', name: '城市现代化', typeText: '概念', source: '项目可行性研究报告.docx', relations: ['智慧园区', '产业升级'] },
  1671. ai: { icon: '🤖', type: 'concept', name: '智能化管理', typeText: '技术', source: '技术方案说明.pdf', relations: ['智慧园区', '低碳绿色'] },
  1672. green: { icon: '🌱', type: 'concept', name: '低碳绿色', typeText: '概念', source: '项目可行性研究报告.docx', relations: ['智慧园区'] },
  1673. location: { icon: '📍', type: 'location', name: '华南地区', typeText: '地点', source: '项目可行性研究报告.docx', relations: ['智慧园区', '50万m²'] },
  1674. data1: { icon: '💰', type: 'data', name: '1,789亿元', typeText: '市场规模', source: '市场调研数据.pdf', relations: ['智慧园区', '18%'] },
  1675. data2: { icon: '📊', type: 'data', name: '18%', typeText: '增长率', source: '市场调研数据.pdf', relations: ['1,789亿元'] },
  1676. data3: { icon: '💵', type: 'data', name: '12.5亿元', typeText: '总投资额', source: '财务预测表.xlsx', relations: ['华南地区'] },
  1677. data4: { icon: '📐', type: 'data', name: '50万m²', typeText: '规划面积', source: '项目报告.docx', relations: ['华南地区'] },
  1678. data5: { icon: '🏭', type: 'data', name: '200家', typeText: '企业数量', source: '项目报告.docx', relations: ['建设目标'] },
  1679. data6: { icon: '💎', type: 'data', name: '50亿元', typeText: '年产值', source: '财务预测表.xlsx', relations: ['建设目标'] },
  1680. data7: { icon: '👥', type: 'data', name: '8000个岗位', typeText: '就业岗位', source: '项目报告.docx', relations: ['建设目标'] },
  1681. chart: { icon: '📊', type: 'asset', name: '趋势图', typeText: '图表资产', source: '资产库', relations: ['柱状图'] },
  1682. template: { icon: '📝', type: 'asset', name: '结论模板', typeText: '文本模板', source: '资产库', relations: ['结论'] }
  1683. };
  1684. let currentTagName = '';
  1685. function showTagPopover(event, tagId) {
  1686. event.stopPropagation();
  1687. const popover = document.getElementById('elementPopover');
  1688. const data = tagData[tagId];
  1689. if (!data) return;
  1690. currentTagName = data.name;
  1691. document.getElementById('popoverIcon').className = 'popover-icon ' + data.type;
  1692. document.getElementById('popoverIcon').textContent = data.icon;
  1693. document.getElementById('popoverTitle').textContent = data.name;
  1694. document.getElementById('popoverType').textContent = data.typeText;
  1695. document.getElementById('popoverSource').textContent = data.source;
  1696. const relationsEl = document.getElementById('popoverRelations');
  1697. relationsEl.innerHTML = data.relations.map(r =>
  1698. `<span class="popover-relation" onclick="showToast('定位到: ${r}', 'info')">→ ${r}</span>`
  1699. ).join('');
  1700. const rect = event.currentTarget.getBoundingClientRect();
  1701. popover.style.top = Math.min(rect.bottom + 8, window.innerHeight - 300) + 'px';
  1702. popover.style.left = Math.min(rect.left, window.innerWidth - 300) + 'px';
  1703. popover.classList.add('show');
  1704. }
  1705. function hideTagPopover() {
  1706. document.getElementById('elementPopover').classList.remove('show');
  1707. }
  1708. function insertTagToEditor() {
  1709. if (currentTagName) {
  1710. showToast('已插入: ' + currentTagName, 'success');
  1711. }
  1712. }
  1713. document.addEventListener('click', function(e) {
  1714. if (!e.target.closest('.element-popover') && !e.target.closest('.element-tag')) {
  1715. hideTagPopover();
  1716. }
  1717. });
  1718. // === 标签拖拽功能 ===
  1719. function handleTagDragStart(event, tagName) {
  1720. currentTagName = tagName;
  1721. event.currentTarget.classList.add('dragging');
  1722. event.dataTransfer.setData('text/plain', tagName);
  1723. event.dataTransfer.effectAllowed = 'copy';
  1724. setTimeout(() => {
  1725. document.querySelectorAll('.editor-content').forEach(el => {
  1726. el.classList.add('drag-over');
  1727. });
  1728. }, 0);
  1729. }
  1730. function handleTagDragEnd(event) {
  1731. event.currentTarget.classList.remove('dragging');
  1732. document.querySelectorAll('.editor-content').forEach(el => {
  1733. el.classList.remove('drag-over');
  1734. });
  1735. }
  1736. // 编辑区放置事件
  1737. document.addEventListener('DOMContentLoaded', function() {
  1738. const editorContents = document.querySelectorAll('.editor-content');
  1739. editorContents.forEach(editor => {
  1740. editor.addEventListener('dragover', function(e) {
  1741. e.preventDefault();
  1742. e.dataTransfer.dropEffect = 'copy';
  1743. });
  1744. editor.addEventListener('drop', function(e) {
  1745. e.preventDefault();
  1746. const tagName = e.dataTransfer.getData('text/plain');
  1747. if (tagName) {
  1748. showToast('✓ 已插入要素: ' + tagName, 'success');
  1749. }
  1750. this.classList.remove('drag-over');
  1751. });
  1752. editor.addEventListener('dragleave', function(e) {
  1753. if (!this.contains(e.relatedTarget)) {
  1754. this.classList.remove('drag-over');
  1755. }
  1756. });
  1757. });
  1758. });
  1759. // === 段落编辑效果 ===
  1760. document.addEventListener('DOMContentLoaded', function() {
  1761. // 为可编辑区域添加段落点击效果
  1762. document.querySelectorAll('.editor-content[contenteditable="true"]').forEach(editor => {
  1763. editor.addEventListener('click', function(e) {
  1764. // 移除所有editing类
  1765. this.querySelectorAll('.editing').forEach(el => el.classList.remove('editing'));
  1766. // 找到点击的段落元素
  1767. let target = e.target;
  1768. while (target && target !== this) {
  1769. if (['P', 'H1', 'H2', 'H3', 'LI'].includes(target.tagName)) {
  1770. target.classList.add('editing');
  1771. break;
  1772. }
  1773. target = target.parentElement;
  1774. }
  1775. });
  1776. editor.addEventListener('blur', function() {
  1777. this.querySelectorAll('.editing').forEach(el => el.classList.remove('editing'));
  1778. });
  1779. });
  1780. });
  1781. // === 右键菜单 ===
  1782. let selectedText = '';
  1783. let selectedRange = null;
  1784. let currentAiAction = '';
  1785. let aiResultText = '';
  1786. let selectedEntityType = 'entity';
  1787. function showContextMenu(event) {
  1788. const selection = window.getSelection();
  1789. selectedText = selection.toString().trim();
  1790. if (selectedText.length > 0) {
  1791. event.preventDefault();
  1792. selectedRange = selection.getRangeAt(0).cloneRange();
  1793. const menu = document.getElementById('contextMenu');
  1794. menu.style.top = event.clientY + 'px';
  1795. menu.style.left = event.clientX + 'px';
  1796. menu.classList.add('show');
  1797. }
  1798. }
  1799. function hideContextMenu() {
  1800. document.getElementById('contextMenu').classList.remove('show');
  1801. }
  1802. function execContextAction(action) {
  1803. hideContextMenu();
  1804. switch(action) {
  1805. case 'copy':
  1806. document.execCommand('copy');
  1807. showToast('已复制到剪贴板', 'success');
  1808. break;
  1809. case 'cut':
  1810. document.execCommand('cut');
  1811. showToast('已剪切', 'success');
  1812. break;
  1813. case 'paste':
  1814. document.execCommand('paste');
  1815. break;
  1816. case 'polish':
  1817. currentAiAction = 'polish';
  1818. showToast('AI正在润色...', 'info');
  1819. setTimeout(() => {
  1820. // 模拟AI润色结果
  1821. aiResultText = improveText(selectedText);
  1822. showAiConfirmModal('✨', 'AI 润色结果', '请确认是否应用润色修改', '润色结果', selectedText, aiResultText);
  1823. }, 1200);
  1824. break;
  1825. case 'spell':
  1826. currentAiAction = 'spell';
  1827. showToast('正在检查拼写...', 'info');
  1828. setTimeout(() => {
  1829. // 模拟拼写检查结果
  1830. aiResultText = checkSpelling(selectedText);
  1831. if (aiResultText === selectedText) {
  1832. showToast('✓ 拼写检查完成,未发现错误', 'success');
  1833. } else {
  1834. showAiConfirmModal('📝', '拼写检查结果', '发现以下拼写问题,请确认修改', '修正结果', selectedText, aiResultText);
  1835. }
  1836. }, 1000);
  1837. break;
  1838. case 'mark':
  1839. showMarkEntityModal(selectedText);
  1840. break;
  1841. case 'quote':
  1842. quoteToAiAssistant(selectedText);
  1843. break;
  1844. }
  1845. }
  1846. // 模拟AI润色
  1847. function improveText(text) {
  1848. // 简单模拟润色效果
  1849. const improvements = {
  1850. '智慧园区': '新一代智慧园区',
  1851. '快速发展': '蓬勃发展',
  1852. '重要载体': '核心引擎和重要载体',
  1853. '产业升级': '产业转型升级',
  1854. '城市现代化': '新型城镇化建设'
  1855. };
  1856. let result = text;
  1857. for (let [key, value] of Object.entries(improvements)) {
  1858. if (text.includes(key)) {
  1859. result = result.replace(key, value);
  1860. }
  1861. }
  1862. if (result === text) {
  1863. result = text + ',这一趋势将持续深化';
  1864. }
  1865. return result;
  1866. }
  1867. // 模拟拼写检查
  1868. function checkSpelling(text) {
  1869. // 简单模拟,实际应该对接拼写检查服务
  1870. return text; // 返回原文表示无错误
  1871. }
  1872. // === AI确认弹窗 ===
  1873. function showAiConfirmModal(icon, title, subtitle, resultLabel, original, result) {
  1874. document.getElementById('aiConfirmIcon').textContent = icon;
  1875. document.getElementById('aiConfirmTitle').textContent = title;
  1876. document.getElementById('aiConfirmSubtitle').textContent = subtitle;
  1877. document.getElementById('aiConfirmResultLabel').textContent = resultLabel;
  1878. document.getElementById('aiConfirmOriginal').textContent = original;
  1879. document.getElementById('aiConfirmResult').textContent = result;
  1880. document.getElementById('aiConfirmModal').classList.add('show');
  1881. }
  1882. function closeAiConfirmModal() {
  1883. document.getElementById('aiConfirmModal').classList.remove('show');
  1884. }
  1885. function applyAiResult() {
  1886. if (selectedRange && aiResultText) {
  1887. // 选中原范围
  1888. const selection = window.getSelection();
  1889. selection.removeAllRanges();
  1890. selection.addRange(selectedRange);
  1891. // 替换内容
  1892. document.execCommand('insertText', false, aiResultText);
  1893. showToast('✓ 已替换原文', 'success');
  1894. }
  1895. closeAiConfirmModal();
  1896. }
  1897. // === 标记为要素弹窗 ===
  1898. function showMarkEntityModal(text) {
  1899. document.getElementById('markEntityPreview').textContent = '"' + text + '"';
  1900. // 重置选择
  1901. document.querySelectorAll('.mark-entity-type').forEach(el => el.classList.remove('selected'));
  1902. document.querySelector('.mark-entity-type').classList.add('selected');
  1903. selectedEntityType = 'entity';
  1904. document.getElementById('markEntityModal').classList.add('show');
  1905. }
  1906. function closeMarkEntityModal() {
  1907. document.getElementById('markEntityModal').classList.remove('show');
  1908. }
  1909. function selectEntityType(el, type) {
  1910. document.querySelectorAll('.mark-entity-type').forEach(t => t.classList.remove('selected'));
  1911. el.classList.add('selected');
  1912. selectedEntityType = type;
  1913. }
  1914. function confirmMarkEntity() {
  1915. if (selectedRange && selectedText) {
  1916. // 创建标签元素
  1917. const selection = window.getSelection();
  1918. selection.removeAllRanges();
  1919. selection.addRange(selectedRange);
  1920. // 获取类型图标和颜色类名
  1921. const typeInfo = {
  1922. entity: { icon: '🏢', class: 'entity' },
  1923. concept: { icon: '💡', class: 'concept' },
  1924. data: { icon: '📊', class: 'data' },
  1925. location: { icon: '📍', class: 'location' }
  1926. };
  1927. const info = typeInfo[selectedEntityType] || typeInfo.entity;
  1928. // 包装为高亮标签 - 带类型class
  1929. const span = document.createElement('span');
  1930. span.className = 'entity-highlight ' + info.class;
  1931. span.setAttribute('contenteditable', 'false');
  1932. span.setAttribute('onclick', `showEntityEditModal(event, 'new_${Date.now()}')`);
  1933. span.textContent = selectedText;
  1934. // 替换选中内容
  1935. selectedRange.deleteContents();
  1936. selectedRange.insertNode(span);
  1937. // 添加到右侧要素列表
  1938. addToElementTags(selectedText, selectedEntityType, info.icon);
  1939. // 动态添加到entityEditData
  1940. const newId = 'new_' + Date.now();
  1941. entityEditData[newId] = {
  1942. icon: info.icon,
  1943. name: selectedText,
  1944. type: selectedEntityType,
  1945. typeText: { entity: '核心实体', concept: '概念/技术', data: '数据/指标', location: '地点/组织' }[selectedEntityType],
  1946. source: '用户标记',
  1947. originalValue: selectedText,
  1948. relations: []
  1949. };
  1950. showToast('✓ 已标记为要素: ' + selectedText, 'success');
  1951. }
  1952. closeMarkEntityModal();
  1953. }
  1954. // 添加到右侧要素标签列表
  1955. function addToElementTags(name, type, icon) {
  1956. const container = document.getElementById('elementTagsWrap') || document.querySelector('.element-tags-wrap');
  1957. if (container) {
  1958. const tag = document.createElement('span');
  1959. tag.className = 'element-tag ' + type;
  1960. tag.setAttribute('draggable', 'true');
  1961. tag.innerHTML = `<span class="tag-icon">${icon}</span><span class="tag-name">${name}</span>`;
  1962. container.appendChild(tag);
  1963. }
  1964. }
  1965. // 引用到AI助手
  1966. function quoteToAiAssistant(text) {
  1967. const aiMessages = document.getElementById('aiMessages');
  1968. const quotedText = text.length > 50 ? text.substring(0, 50) + '...' : text;
  1969. aiMessages.innerHTML += `
  1970. <div class="msg user">
  1971. <div class="msg-avatar">张</div>
  1972. <div class="msg-bubble">
  1973. <div style="padding:8px;background:rgba(255,255,255,0.5);border-radius:6px;margin-bottom:8px;font-size:12px;border-left:3px solid rgba(255,255,255,0.8);">
  1974. 📝 引用: "${quotedText}"
  1975. </div>
  1976. 请基于这段内容帮我分析
  1977. </div>
  1978. </div>
  1979. `;
  1980. aiMessages.scrollTop = aiMessages.scrollHeight;
  1981. showToast('已引用到AI助手', 'success');
  1982. setTimeout(() => {
  1983. aiMessages.innerHTML += `
  1984. <div class="msg ai">
  1985. <div class="msg-avatar">🤖</div>
  1986. <div class="msg-bubble">好的,我已收到您引用的内容。这段文字主要描述了相关业务内容,我可以帮您:<br><br>1. 深入分析其含义<br>2. 扩展补充相关信息<br>3. 检查数据准确性<br><br>请问您需要哪方面的帮助?</div>
  1987. </div>
  1988. `;
  1989. aiMessages.scrollTop = aiMessages.scrollHeight;
  1990. }, 1200);
  1991. }
  1992. // 点击其他地方关闭右键菜单
  1993. document.addEventListener('click', function(e) {
  1994. if (!e.target.closest('.context-menu')) {
  1995. hideContextMenu();
  1996. }
  1997. });
  1998. // 点击弹窗外部关闭
  1999. document.getElementById('aiConfirmModal')?.addEventListener('click', function(e) {
  2000. if (e.target === this) closeAiConfirmModal();
  2001. });
  2002. document.getElementById('markEntityModal')?.addEventListener('click', function(e) {
  2003. if (e.target === this) closeMarkEntityModal();
  2004. });
  2005. // === 实体标签编辑弹窗 ===
  2006. const entityEditData = {
  2007. smartpark: {
  2008. icon: '🏢', name: '智慧园区', type: 'entity', typeText: '核心实体',
  2009. source: '项目可行性研究报告.docx', originalValue: '智慧园区',
  2010. relations: ['产业升级', '城市现代化', '智能化管理', '1,789亿元']
  2011. },
  2012. upgrade: {
  2013. icon: '📈', name: '产业升级', type: 'concept', typeText: '概念',
  2014. source: '项目可行性研究报告.docx', originalValue: '产业升级',
  2015. relations: ['智慧园区', '城市现代化']
  2016. },
  2017. modern: {
  2018. icon: '🌆', name: '城市现代化', type: 'concept', typeText: '概念',
  2019. source: '项目可行性研究报告.docx', originalValue: '城市现代化',
  2020. relations: ['智慧园区', '产业升级']
  2021. },
  2022. ai: {
  2023. icon: '🤖', name: '智能化管理', type: 'concept', typeText: '技术',
  2024. source: '技术方案说明.pdf', originalValue: '智能化管理',
  2025. relations: ['智慧园区', '低碳绿色']
  2026. },
  2027. green: {
  2028. icon: '🌱', name: '低碳绿色', type: 'concept', typeText: '概念',
  2029. source: '项目可行性研究报告.docx', originalValue: '低碳绿色',
  2030. relations: ['智慧园区']
  2031. },
  2032. location: {
  2033. icon: '📍', name: '华南地区', type: 'location', typeText: '地点',
  2034. source: '项目可行性研究报告.docx', originalValue: '华南地区',
  2035. relations: ['智慧园区', '50万平方米', '12.5亿元']
  2036. },
  2037. data1: {
  2038. icon: '💰', name: '1,789亿元', type: 'data', typeText: '市场规模',
  2039. source: '市场调研数据.pdf', originalValue: '1,789亿元',
  2040. relations: ['智慧园区', '18%', '2024年']
  2041. },
  2042. data2: {
  2043. icon: '📊', name: '18%', type: 'data', typeText: '增长率',
  2044. source: '市场调研数据.pdf', originalValue: '18%',
  2045. relations: ['1,789亿元', '市场规模']
  2046. },
  2047. data3: {
  2048. icon: '💵', name: '12.5亿元', type: 'data', typeText: '总投资额',
  2049. source: '财务预测表.xlsx', originalValue: '12.5亿元',
  2050. relations: ['华南地区', '智慧园区']
  2051. },
  2052. data4: {
  2053. icon: '📐', name: '50万平方米', type: 'data', typeText: '规划面积',
  2054. source: '项目可行性研究报告.docx', originalValue: '50万平方米',
  2055. relations: ['华南地区']
  2056. },
  2057. manufacture: {
  2058. icon: '🏭', name: '智能制造产业集群', type: 'concept', typeText: '产业',
  2059. source: '项目可行性研究报告.docx', originalValue: '智能制造产业集群',
  2060. relations: ['智慧园区', '数字服务中心']
  2061. },
  2062. digital: {
  2063. icon: '💻', name: '数字服务中心', type: 'concept', typeText: '设施',
  2064. source: '项目可行性研究报告.docx', originalValue: '数字服务中心',
  2065. relations: ['智慧园区', '智能制造产业集群']
  2066. }
  2067. };
  2068. let currentEditEntityId = null;
  2069. function showEntityEditModal(event, entityId) {
  2070. event.preventDefault();
  2071. event.stopPropagation();
  2072. const data = entityEditData[entityId];
  2073. if (!data) return;
  2074. currentEditEntityId = entityId;
  2075. // 更新弹窗内容
  2076. document.getElementById('editEntityIcon').textContent = data.icon;
  2077. document.getElementById('editEntityName').textContent = data.name;
  2078. document.getElementById('editEntityType').textContent = data.typeText + ' · 来自 ' + data.source;
  2079. document.getElementById('editEntityValue').value = data.name;
  2080. document.getElementById('editEntityCategory').value = data.type;
  2081. // 更新数据关系表
  2082. const tableBody = document.getElementById('entityRelationBody');
  2083. tableBody.innerHTML = `
  2084. <tr>
  2085. <td>标签名称</td>
  2086. <td class="original">${data.originalValue}</td>
  2087. <td class="current"><span class="editable">${data.name}</span></td>
  2088. </tr>
  2089. <tr>
  2090. <td>实体类型</td>
  2091. <td class="original">${data.typeText}</td>
  2092. <td class="current">${data.typeText}</td>
  2093. </tr>
  2094. <tr>
  2095. <td>数据来源</td>
  2096. <td class="original">${data.source}</td>
  2097. <td class="current">${data.source}</td>
  2098. </tr>
  2099. <tr>
  2100. <td>出现次数</td>
  2101. <td class="original">-</td>
  2102. <td class="current">${Math.floor(Math.random() * 5) + 1} 次</td>
  2103. </tr>
  2104. `;
  2105. // 更新关联要素
  2106. const relationsEl = document.getElementById('editEntityRelations');
  2107. relationsEl.innerHTML = data.relations.map(r =>
  2108. `<span class="popover-relation" onclick="showToast('跳转到: ${r}', 'info')">${r}</span>`
  2109. ).join('') + `<span style="padding:3px 8px;background:var(--primary-light);border-radius:4px;font-size:11px;color:var(--primary);cursor:pointer;" onclick="showToast('添加关联', 'info')">+ 添加</span>`;
  2110. // 显示弹窗
  2111. document.getElementById('entityEditModal').classList.add('show');
  2112. }
  2113. function closeEntityEditModal() {
  2114. document.getElementById('entityEditModal').classList.remove('show');
  2115. currentEditEntityId = null;
  2116. }
  2117. function saveEntityEdit() {
  2118. const newValue = document.getElementById('editEntityValue').value;
  2119. const newCategory = document.getElementById('editEntityCategory').value;
  2120. if (currentEditEntityId && entityEditData[currentEditEntityId]) {
  2121. entityEditData[currentEditEntityId].name = newValue;
  2122. entityEditData[currentEditEntityId].type = newCategory;
  2123. showToast('✓ 标签已更新: ' + newValue, 'success');
  2124. }
  2125. closeEntityEditModal();
  2126. }
  2127. // 点击弹窗外部关闭
  2128. document.getElementById('entityEditModal')?.addEventListener('click', function(e) {
  2129. if (e.target === this) closeEntityEditModal();
  2130. });
  2131. // === AI对话 ===
  2132. function handleAiKey(e) {
  2133. if (e.key === 'Enter' && !e.shiftKey) {
  2134. e.preventDefault();
  2135. sendAiMsg();
  2136. }
  2137. }
  2138. function autoResizeTextarea(el) {
  2139. el.style.height = 'auto';
  2140. el.style.height = Math.min(el.scrollHeight, 100) + 'px';
  2141. }
  2142. function sendAiMsg() {
  2143. const textarea = document.getElementById('aiTextarea');
  2144. const msg = textarea.value.trim();
  2145. if (!msg) return;
  2146. const container = document.getElementById('aiMessages');
  2147. container.innerHTML += '<div class="msg user"><div class="msg-avatar">张</div><div class="msg-bubble">' + msg + '</div></div>';
  2148. textarea.value = '';
  2149. textarea.style.height = 'auto';
  2150. container.scrollTop = container.scrollHeight;
  2151. setTimeout(() => {
  2152. container.innerHTML += '<div class="msg ai"><div class="msg-avatar">🤖</div><div class="msg-bubble">好的,我来帮您处理这个请求。基于已解析的文档,我找到了相关内容可以补充到报告中。</div></div>';
  2153. container.scrollTop = container.scrollHeight;
  2154. }, 1000);
  2155. }
  2156. // === 知识图谱弹窗 ===
  2157. function showGraphModal() {
  2158. document.getElementById('graphModal').classList.add('show');
  2159. showToast('已加载标记要素关系图谱', 'info');
  2160. }
  2161. function closeGraphModal() {
  2162. document.getElementById('graphModal').classList.remove('show');
  2163. }
  2164. // 图谱/列表视图切换
  2165. function switchGraphView(view) {
  2166. const graphBtn = document.getElementById('graphViewBtn');
  2167. const listBtn = document.getElementById('listViewBtn');
  2168. const graphBody = document.getElementById('graphViewBody');
  2169. const listBody = document.getElementById('listViewBody');
  2170. if (view === 'graph') {
  2171. graphBtn.classList.add('active');
  2172. listBtn.classList.remove('active');
  2173. graphBody.style.display = 'block';
  2174. listBody.style.display = 'none';
  2175. } else {
  2176. graphBtn.classList.remove('active');
  2177. listBtn.classList.add('active');
  2178. graphBody.style.display = 'none';
  2179. listBody.style.display = 'flex';
  2180. }
  2181. }
  2182. // 列表类型筛选
  2183. function filterListType(el, type) {
  2184. document.querySelectorAll('.list-filter-tag').forEach(t => t.classList.remove('active'));
  2185. el.classList.add('active');
  2186. showToast('筛选: ' + el.textContent, 'info');
  2187. }
  2188. // 点击弹窗外部关闭
  2189. document.getElementById('graphModal')?.addEventListener('click', function(e) {
  2190. if (e.target === this) closeGraphModal();
  2191. });
  2192. // === 导出菜单 ===
  2193. function showExportMenu(btn) {
  2194. const menu = document.getElementById('exportMenu');
  2195. const rect = btn.getBoundingClientRect();
  2196. menu.style.top = (rect.bottom + 8) + 'px';
  2197. menu.style.right = (window.innerWidth - rect.right) + 'px';
  2198. menu.style.display = 'block';
  2199. }
  2200. function hideExportMenu() {
  2201. document.getElementById('exportMenu').style.display = 'none';
  2202. }
  2203. document.addEventListener('click', function(e) {
  2204. if (!e.target.closest('[onclick*="showExportMenu"]') && !e.target.closest('#exportMenu')) {
  2205. hideExportMenu();
  2206. }
  2207. });
  2208. // === 视图切换 ===
  2209. function switchView(view) {
  2210. const originalBtn = document.getElementById('viewOriginal');
  2211. const markedBtn = document.getElementById('viewMarked');
  2212. const originalContent = document.getElementById('contentOriginal');
  2213. const markedContent = document.getElementById('contentMarked');
  2214. if (view === 'original') {
  2215. originalBtn.classList.add('active');
  2216. markedBtn.classList.remove('active');
  2217. originalContent.style.display = 'block';
  2218. markedContent.style.display = 'none';
  2219. showToast('已切换到原文视图', 'info');
  2220. } else {
  2221. originalBtn.classList.remove('active');
  2222. markedBtn.classList.add('active');
  2223. originalContent.style.display = 'none';
  2224. markedContent.style.display = 'block';
  2225. showToast('已切换到标记视图 - 显示AI提取的实体标记', 'info');
  2226. }
  2227. }
  2228. // === 文件高亮 ===
  2229. function highlightFile(el) {
  2230. document.querySelectorAll('.file-item').forEach(f => f.classList.remove('active'));
  2231. el.classList.add('active');
  2232. }
  2233. // === 上传模拟 ===
  2234. function simulateUpload() {
  2235. showToast('请选择要上传的文件', 'info');
  2236. }
  2237. // === 实体信息 ===
  2238. function showEntityInfo(entity) {
  2239. showToast('实体: ' + entity, 'info');
  2240. }
  2241. // === AI建议 ===
  2242. function acceptSuggestion() {
  2243. showToast('✓ 已采纳建议,内容已更新', 'success');
  2244. const card = document.getElementById('aiSuggestionCard');
  2245. if (card) card.style.display = 'none';
  2246. }
  2247. function ignoreSuggestion() {
  2248. showToast('已忽略建议', 'info');
  2249. const card = document.getElementById('aiSuggestionCard');
  2250. if (card) card.style.display = 'none';
  2251. }
  2252. function acceptContentSuggestion() {
  2253. showToast('✓ 已添加竞争格局分析章节', 'success');
  2254. }
  2255. // === AI Tab切换 ===
  2256. function switchAiTab(el, tab) {
  2257. document.querySelectorAll('.ai-tab').forEach(t => t.classList.remove('active'));
  2258. el.classList.add('active');
  2259. showToast('切换到 ' + el.textContent.trim(), 'info');
  2260. }
  2261. function acceptContentSuggestion() {
  2262. showToast('✓ 已添加竞争格局分析章节', 'success');
  2263. }
  2264. // === Toast ===
  2265. function showToast(msg, type) {
  2266. const box = document.getElementById('toastBox');
  2267. const icons = { success: '✅', error: '❌', info: 'ℹ️' };
  2268. const colors = { success: '#f6ffed', error: '#fff1f0', info: 'var(--primary-light)' };
  2269. const textColors = { success: 'var(--success)', error: 'var(--danger)', info: 'var(--primary)' };
  2270. const toast = document.createElement('div');
  2271. toast.style.cssText = 'display:flex;align-items:center;gap:10px;padding:12px 18px;background:var(--white);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,0.15);transform:translateX(120%);transition:transform 0.3s;min-width:240px;';
  2272. toast.innerHTML = '<span style="width:24px;height:24px;border-radius:50%;background:' + colors[type] + ';color:' + textColors[type] + ';display:flex;align-items:center;justify-content:center;font-size:12px;">' + icons[type] + '</span><span style="font-size:13px;">' + msg + '</span>';
  2273. box.appendChild(toast);
  2274. setTimeout(() => toast.style.transform = 'translateX(0)', 10);
  2275. setTimeout(() => {
  2276. toast.style.transform = 'translateX(120%)';
  2277. setTimeout(() => toast.remove(), 300);
  2278. }, 3000);
  2279. }
  2280. // === 关闭所有 ===
  2281. function closeAll() {
  2282. document.getElementById('notifPanel').style.transform = 'translateX(100%)';
  2283. document.getElementById('overlay').style.display = 'none';
  2284. document.getElementById('fabPanel').style.display = 'none';
  2285. }
  2286. // === 初始化 ===
  2287. setTimeout(() => showToast('欢迎使用灵越智报平台 🎉', 'success'), 500);
  2288. // 更新欢迎语
  2289. (function() {
  2290. const hour = new Date().getHours();
  2291. let greeting = '早上好';
  2292. if (hour >= 12 && hour < 18) greeting = '下午好';
  2293. else if (hour >= 18) greeting = '晚上好';
  2294. const el = document.querySelector('.welcome h1');
  2295. if (el) el.innerHTML = greeting + ',张三!<span>智能报告,洞察未来。</span>';
  2296. })();
  2297. // 模拟解析进度
  2298. let progress1 = 65;
  2299. setInterval(() => {
  2300. progress1 += Math.random() * 3;
  2301. if (progress1 >= 100) {
  2302. progress1 = 100;
  2303. const el = document.querySelector('#parsingFile1 .file-status');
  2304. if (el) {
  2305. el.textContent = '✓ 已完成';
  2306. el.className = 'file-status done';
  2307. }
  2308. } else {
  2309. const el = document.querySelector('#parsingFile1 .file-status');
  2310. if (el && el.classList.contains('parsing')) {
  2311. el.textContent = '📊 解析中 ' + Math.floor(progress1) + '%';
  2312. }
  2313. }
  2314. }, 2000);
  2315. </script>
  2316. </body>
  2317. </html>