时差培养箱-培养全流程详图.html 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. <style>
  8. * { margin: 0; padding: 0; box-sizing: border-box; }
  9. :root {
  10. --operate-color: #4A90E2;
  11. --operate-bg: #EAF3FC;
  12. --control-color: #F39C12;
  13. --control-bg: #FEF5E7;
  14. --front-color: #9B59B6;
  15. --front-bg: #F5EEF8;
  16. --branch-color: #E67E22;
  17. --branch-bg: #FDF2E9;
  18. --error-color: #E74C3C;
  19. --error-bg: #FDEDEC;
  20. --start-color: #16A085;
  21. --start-bg: #E8F8F5;
  22. --bg-page: #F4F6F8;
  23. --text-primary: #2C3E50;
  24. --text-secondary: #7F8C8D;
  25. --border-light: #E0E4E8;
  26. }
  27. html, body {
  28. font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
  29. background: var(--bg-page);
  30. color: var(--text-primary);
  31. height: 100%;
  32. overflow: hidden;
  33. }
  34. /* 顶部栏 */
  35. .top-bar {
  36. position: fixed;
  37. top: 0; left: 0; right: 0;
  38. height: 60px;
  39. z-index: 1000;
  40. background: #fff;
  41. border-bottom: 1px solid var(--border-light);
  42. display: flex;
  43. align-items: center;
  44. justify-content: space-between;
  45. padding: 0 24px;
  46. box-shadow: 0 2px 8px rgba(0,0,0,0.06);
  47. }
  48. .top-title { font-size: 20px; font-weight: 700; color: var(--operate-color); }
  49. .top-actions { display: flex; gap: 12px; align-items: center; }
  50. .btn {
  51. padding: 7px 16px; border: 1px solid var(--border-light);
  52. background: #fff; border-radius: 8px; cursor: pointer;
  53. font-size: 13px; color: var(--text-secondary); transition: all .2s;
  54. }
  55. .btn:hover { border-color: var(--operate-color); color: var(--operate-color); }
  56. .btn.primary { background: var(--operate-color); color: #fff; border-color: var(--operate-color); }
  57. .btn.primary:hover { background: #357ABD; }
  58. /* 图例 */
  59. .legend { display: flex; gap: 16px; font-size: 12px; }
  60. .legend-item { display: flex; align-items: center; gap: 5px; }
  61. .legend-dot { width: 11px; height: 11px; border-radius: 3px; }
  62. .legend-line { width: 20px; height: 0; border-top-width: 2px; border-top-style: solid; }
  63. /* 画布区域(可平移缩放) */
  64. .canvas-viewport {
  65. position: fixed;
  66. top: 60px; left: 0; right: 0; bottom: 0;
  67. overflow: hidden;
  68. cursor: grab;
  69. background:
  70. radial-gradient(circle, #dde3e8 1px, transparent 1px);
  71. background-size: 24px 24px;
  72. }
  73. .canvas-viewport.panning { cursor: grabbing; }
  74. .canvas-world {
  75. position: absolute;
  76. top: 0; left: 0;
  77. transform-origin: 0 0;
  78. }
  79. .svg-lines {
  80. position: absolute;
  81. top: 0; left: 0;
  82. overflow: visible;
  83. pointer-events: none;
  84. z-index: 1;
  85. }
  86. /* 节点 */
  87. .flow-node {
  88. position: absolute;
  89. width: 200px;
  90. padding: 12px 16px;
  91. background: #fff;
  92. border: 2px solid;
  93. border-radius: 10px;
  94. cursor: move;
  95. z-index: 2;
  96. box-shadow: 0 2px 6px rgba(0,0,0,0.08);
  97. transition: box-shadow .15s, transform .15s;
  98. user-select: none;
  99. }
  100. .flow-node:hover { box-shadow: 0 6px 16px rgba(0,0,0,0.18); z-index: 5; }
  101. .flow-node.active { box-shadow: 0 0 0 3px rgba(74,144,226,0.4), 0 6px 16px rgba(0,0,0,0.2); z-index: 6; }
  102. .flow-node.dragging { opacity: 0.85; box-shadow: 0 10px 28px rgba(0,0,0,0.28); z-index: 100; }
  103. .flow-node.operate { border-color: var(--operate-color); background: var(--operate-bg); }
  104. .flow-node.control { border-color: var(--control-color); background: var(--control-bg); }
  105. .flow-node.front { border-color: var(--front-color); background: var(--front-bg); }
  106. .flow-node.branch { border-color: var(--branch-color); background: var(--branch-bg); border-style: dashed; }
  107. .flow-node.error { border-color: var(--error-color); background: var(--error-bg); }
  108. .flow-node.start { border-color: var(--start-color); background: var(--start-bg); }
  109. .node-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
  110. .node-icon { font-size: 20px; }
  111. .node-title { font-size: 14px; font-weight: 700; color: var(--text-primary); line-height: 1.3; }
  112. .node-tag {
  113. display: inline-block; font-size: 11px; padding: 1px 8px;
  114. border-radius: 8px; background: rgba(0,0,0,0.06); color: var(--text-secondary);
  115. }
  116. .node-brief { font-size: 11.5px; color: var(--text-secondary); margin-top: 4px; line-height: 1.4; }
  117. /* 缩放控制 */
  118. .zoom-ctrl {
  119. position: fixed; bottom: 24px; right: 24px; z-index: 900;
  120. display: flex; flex-direction: column; gap: 6px;
  121. background: #fff; border: 1px solid var(--border-light);
  122. border-radius: 10px; padding: 6px; box-shadow: 0 2px 8px rgba(0,0,0,0.1);
  123. }
  124. .zoom-btn {
  125. width: 34px; height: 34px; border: none; background: #f5f7f8;
  126. border-radius: 6px; cursor: pointer; font-size: 18px; color: var(--text-primary);
  127. }
  128. .zoom-btn:hover { background: var(--operate-bg); }
  129. .zoom-label { text-align: center; font-size: 11px; color: var(--text-secondary); }
  130. /* 右侧详情面板 */
  131. .detail-backdrop {
  132. position: fixed; inset: 0; background: rgba(0,0,0,0.35);
  133. z-index: 1500; opacity: 0; pointer-events: none; transition: opacity .25s;
  134. }
  135. .detail-backdrop.show { opacity: 1; pointer-events: auto; }
  136. .detail-panel {
  137. position: fixed; top: 0; right: -640px; width: 640px; max-width: 92vw;
  138. height: 100vh; background: #fff; z-index: 1600;
  139. box-shadow: -4px 0 24px rgba(0,0,0,0.18); overflow-y: auto;
  140. transition: right .3s ease;
  141. }
  142. .detail-panel.show { right: 0; }
  143. .detail-header {
  144. position: sticky; top: 0; background: #fff; z-index: 10;
  145. padding: 18px 22px; border-bottom: 1px solid var(--border-light);
  146. display: flex; align-items: center; justify-content: space-between;
  147. }
  148. .detail-title-wrap { display: flex; align-items: center; gap: 10px; }
  149. .detail-title { font-size: 18px; font-weight: 700; }
  150. .detail-badge { font-size: 11px; padding: 2px 10px; border-radius: 10px; color: #fff; }
  151. .detail-close {
  152. width: 32px; height: 32px; border: none; background: var(--border-light);
  153. border-radius: 50%; cursor: pointer; font-size: 18px; color: var(--text-secondary);
  154. }
  155. .detail-close:hover { background: var(--error-color); color: #fff; }
  156. .detail-body { padding: 20px 22px 40px; }
  157. .detail-section { margin-bottom: 20px; }
  158. .section-title {
  159. font-size: 14px; font-weight: 700; color: var(--operate-color);
  160. margin-bottom: 10px; padding-bottom: 6px; border-bottom: 1px solid var(--border-light);
  161. display: flex; align-items: center; gap: 6px;
  162. }
  163. .section-content { font-size: 13px; line-height: 1.75; color: var(--text-primary); }
  164. .section-content ul { list-style: none; }
  165. .section-content li { padding: 3px 0 3px 18px; position: relative; }
  166. .section-content li:before {
  167. content: "▸"; position: absolute; left: 0; color: var(--operate-color);
  168. }
  169. .flow-arrow { color: var(--error-color); font-weight: 700; }
  170. .code-loc {
  171. background: #2C3E50; color: #7FDBFF; padding: 6px 10px; border-radius: 5px;
  172. font-family: Consolas, monospace; font-size: 12px; margin-top: 5px; word-break: break-all;
  173. }
  174. .cross-box {
  175. background: #FEF9E7; border: 1px solid #F9E79F; border-radius: 8px;
  176. padding: 12px 14px; line-height: 1.9;
  177. }
  178. </style>
  179. </head>
  180. <body>
  181. <!-- 顶部栏 -->
  182. <div class="top-bar">
  183. <div class="top-title">🧬 时差培养箱 · 培养全流程详图</div>
  184. <div class="legend">
  185. <span class="legend-item"><span class="legend-dot" style="background:var(--start-color)"></span>起止</span>
  186. <span class="legend-item"><span class="legend-dot" style="background:var(--operate-color)"></span>operate</span>
  187. <span class="legend-item"><span class="legend-dot" style="background:var(--control-color)"></span>control</span>
  188. <span class="legend-item"><span class="legend-dot" style="background:var(--front-color)"></span>front</span>
  189. <span class="legend-item"><span class="legend-dot" style="background:var(--branch-color)"></span>判断</span>
  190. <span class="legend-item"><span class="legend-dot" style="background:var(--error-color)"></span>异常</span>
  191. <span class="legend-item"><span class="legend-line" style="border-color:#7F8C8D"></span>本端</span>
  192. <span class="legend-item"><span class="legend-line" style="border-color:#16A085;border-top-style:dashed"></span>跨端</span>
  193. <span class="legend-item"><span class="legend-line" style="border-color:#E74C3C;border-top-style:dotted"></span>异常/回流</span>
  194. </div>
  195. <div class="top-actions">
  196. <button class="btn" id="btnReset">↺ 重置布局</button>
  197. <button class="btn" id="btnFit">⊡ 适应屏幕</button>
  198. <button class="btn primary" id="btnSave">💾 已自动保存</button>
  199. </div>
  200. </div>
  201. <!-- 画布 -->
  202. <div class="canvas-viewport" id="viewport">
  203. <div class="canvas-world" id="world">
  204. <svg class="svg-lines" id="svg"></svg>
  205. <!-- 节点由 JS 渲染 -->
  206. </div>
  207. </div>
  208. <!-- 缩放控制 -->
  209. <div class="zoom-ctrl">
  210. <button class="zoom-btn" id="zoomIn">+</button>
  211. <div class="zoom-label" id="zoomLabel">100%</div>
  212. <button class="zoom-btn" id="zoomOut">-</button>
  213. </div>
  214. <!-- 详情面板 -->
  215. <div class="detail-backdrop" id="backdrop"></div>
  216. <div class="detail-panel" id="panel">
  217. <div class="detail-header">
  218. <div class="detail-title-wrap">
  219. <span class="detail-title" id="panelTitle">节点详情</span>
  220. <span class="detail-badge" id="panelBadge"></span>
  221. </div>
  222. <button class="detail-close" id="panelClose">×</button>
  223. </div>
  224. <div class="detail-body" id="panelBody"></div>
  225. </div>
  226. <script src="dagre.min.js"></script>
  227. <script src="flow-data.js"></script>
  228. <script src="flow-render.js"></script>
  229. </body>
  230. </html>