styles.css 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. :root {
  2. --el-color-primary: #409eff;
  3. --el-color-primary-light-3: #79bbff;
  4. --el-color-primary-light-5: #a0cfff;
  5. --el-color-primary-light-7: #c6e2ff;
  6. --el-color-primary-light-9: #ecf5ff;
  7. --el-color-primary-dark-2: #337ecc;
  8. --el-border-radius-base: 4px;
  9. color: #303133;
  10. background: #f2f3f5;
  11. font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
  12. font-synthesis: none;
  13. text-rendering: optimizeLegibility;
  14. }
  15. * { box-sizing: border-box; }
  16. body {
  17. margin: 0;
  18. min-width: 320px;
  19. min-height: 100vh;
  20. color: #303133;
  21. background: #f2f3f5;
  22. }
  23. button, input, select { font: inherit; }
  24. button { cursor: pointer; }
  25. button:disabled, input:disabled, select:disabled { cursor: not-allowed; }
  26. h1, h2, p { margin: 0; }
  27. .app-shell { min-height: 100vh; background: #f2f3f5; }
  28. .login-shell { min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 24px; background: linear-gradient(160deg, #304156 0%, #1d2b3a 100%); }
  29. .login-card { width: min(420px, 100%); display: flex; flex-direction: column; gap: 14px; padding: 34px 32px 30px; background: #fff; border-radius: 8px; box-shadow: 0 18px 48px rgba(0, 0, 0, .28); }
  30. .login-brand { display: flex; align-items: center; gap: 13px; margin-bottom: 6px; }
  31. .login-brand .brand-mark { flex-shrink: 0; }
  32. .login-brand h1 { color: #303133; }
  33. .login-brand .brand-kicker { color: #909399; }
  34. .login-hint { color: #909399; font-size: 13px; }
  35. .login-input { width: 100%; }
  36. .login-error { margin-top: 2px; }
  37. .login-button.el-button { width: 100%; height: 42px; margin: 6px 0 0; font-size: 15px; letter-spacing: .2em; }
  38. .header-logout.el-button { height: 32px; margin: 0; color: #d9e2ec; border-color: #7aa7d4; background: transparent; }
  39. .header-logout.el-button:hover { color: #fff; border-color: #f56c6c; background: rgba(245, 108, 108, .18); }
  40. .app-header {
  41. min-height: 72px;
  42. display: flex;
  43. align-items: center;
  44. justify-content: space-between;
  45. gap: 24px;
  46. padding: 14px clamp(18px, 4vw, 60px);
  47. color: #fff;
  48. background: #304156;
  49. border-bottom: 1px solid #253447;
  50. }
  51. .brand-lockup, .header-meta, .panel-heading, .chart-actions, .selection-controls, .time-strip-head, .time-strip-foot, .app-footer, .period-modal-head {
  52. display: flex;
  53. align-items: center;
  54. justify-content: space-between;
  55. }
  56. .brand-lockup { justify-content: flex-start; gap: 13px; }
  57. .brand-mark { width: 38px; height: 38px; display: flex; align-items: flex-end; gap: 3px; padding: 7px; background: #409eff; border-radius: 4px; }
  58. .brand-mark span { display: block; width: 5px; background: #fff; border-radius: 1px; }
  59. .brand-mark span:nth-child(1) { height: 11px; }
  60. .brand-mark span:nth-child(2) { height: 20px; }
  61. .brand-mark span:nth-child(3) { height: 26px; }
  62. .brand-kicker { margin-bottom: 3px; color: #a9c9e8; font-size: 10px; font-weight: 600; letter-spacing: .1em; }
  63. h1 { font-size: 18px; line-height: 1.35; font-weight: 600; }
  64. h2 { font-size: 18px; line-height: 1.35; font-weight: 600; }
  65. .header-meta { justify-content: flex-end; gap: 16px; color: #d9e2ec; font-size: 13px; }
  66. .live-indicator { display: inline-flex; align-items: center; gap: 7px; color: #cbd7e4; font-size: 12px; }
  67. .live-indicator i, .chart-status i { width: 7px; height: 7px; display: inline-block; border-radius: 50%; background: #67c23a; }
  68. .header-date { max-width: 280px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  69. .header-refresh.el-button { min-width: 68px; height: 32px; margin: 0; color: #fff; border-color: #7aa7d4; background: transparent; }
  70. .header-refresh.el-button:hover { color: #fff; border-color: #409eff; background: rgba(64, 158, 255, .18); }
  71. .spinning { animation: spin .8s linear infinite; }
  72. @keyframes spin { to { transform: rotate(360deg); } }
  73. .workspace {
  74. display: grid;
  75. grid-template-columns: minmax(0, 1fr) 292px;
  76. gap: 16px;
  77. width: min(1600px, calc(100% - 32px));
  78. margin: 20px auto 0;
  79. }
  80. .panel { background: #fff; border: 1px solid #ebeef5; border-radius: 4px; box-shadow: 0 2px 12px rgba(0, 0, 0, .04); }
  81. .query-panel { grid-column: 1; grid-row: 1; }
  82. .selection-panel { grid-column: 1; grid-row: 2; }
  83. .chart-panel { grid-column: 1 / -1; grid-row: 3; }
  84. .insight-panel { grid-column: 2; grid-row: 1 / span 2; align-self: stretch; }
  85. .query-panel { padding: 22px 24px 18px; }
  86. .panel-heading { align-items: flex-start; gap: 16px; }
  87. .compact-heading { margin-bottom: 18px; }
  88. .connection-badge.el-tag { height: 28px; padding: 0 10px; font-size: 12px; }
  89. .query-grid {
  90. display: grid;
  91. grid-template-columns: minmax(220px, 1.7fr) minmax(260px, 2fr) minmax(180px, 1.25fr) minmax(180px, 1.25fr) 170px 126px;
  92. align-items: end;
  93. gap: 16px 12px;
  94. }
  95. .field { min-width: 0; }
  96. .window-field .field-label { white-space: nowrap; }
  97. .field-label { display: flex; align-items: baseline; gap: 7px; margin-bottom: 8px; color: #606266; font-size: 14px; font-weight: 500; line-height: 20px; }
  98. .field-label em { color: #909399; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 11px; font-style: normal; font-weight: 400; }
  99. .query-control { width: 100%; }
  100. .query-control.el-select, .query-control.el-date-editor { height: 40px; }
  101. .query-control.el-input-number { width: 100%; }
  102. .query-control .el-input__wrapper, .query-control.el-input-number { min-height: 40px; border-radius: 4px; }
  103. .query-control .el-input__inner, .query-control .el-select__placeholder, .query-control .el-select__selected-item, .query-control .el-date-editor__placeholder { font-size: 14px; }
  104. .query-control .el-tag { font-size: 13px; }
  105. .point-counts { color: #909399; }
  106. .point-counts .abnormal-count { color: #e05252; font-weight: 600; }
  107. .window-number .el-input__inner { text-align: center; }
  108. .query-button.el-button { width: 100%; height: 40px; margin: 0; border-radius: 4px; font-size: 14px; }
  109. .query-row-2 { display: flex; align-items: flex-start; gap: 16px; grid-column: 1 / -1; }
  110. .query-row-2 .field-check,
  111. .query-row-2 .field-status { min-height: 68px; }
  112. .query-row-2 .field-check .field-label,
  113. .query-row-2 .field-status .field-label { white-space: nowrap; }
  114. .query-checkbox.el-checkbox { height: 40px; margin-right: 20px; display: inline-flex; align-items: center; }
  115. .query-checkbox.el-checkbox:last-child { margin-right: 0; }
  116. .query-checkbox .el-checkbox__label { font-size: 14px; color: #303133; }
  117. .field-status { width: 120px; max-width: 100%; }
  118. .data-alert { margin-top: 16px; }
  119. .selection-panel { padding: 20px 24px 18px; }
  120. .time-strip { min-width: 0; }
  121. .time-strip-head { align-items: flex-start; margin-bottom: 12px; }
  122. .time-summary { padding-top: 4px; color: #909399; font-size: 13px; }
  123. .time-legend { display: inline-flex; align-items: center; gap: 4px; margin-right: 10px; color: #606266; font-size: 12px; }
  124. .time-legend i { width: 9px; height: 9px; display: inline-block; border-radius: 50%; }
  125. .legend-running { background: #2e7d32; }
  126. .legend-stopped { background: #c0c4cc; }
  127. .time-summary .mono, .readout-number { color: #303133; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: 500; }
  128. .summary-divider { padding: 0 8px; color: #dcdfe6; }
  129. .timeline-canvas-host { position: relative; width: 100%; min-height: 210px; overflow: hidden; border: 1px solid #ebeef5; border-radius: 4px; background: #fff; }
  130. .timeline-canvas-host canvas { display: block; width: 100%; height: 210px; cursor: crosshair; }
  131. .timeline-canvas-host.is-loading { opacity: .7; }
  132. .canvas-loading, .chart-loading, .modal-loading { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #909399; background: rgba(255, 255, 255, .82); font-size: 13px; }
  133. .time-strip-foot { gap: 16px; margin-top: 12px; }
  134. .time-foot-item { display: flex; flex-direction: column; gap: 3px; min-width: 100px; }
  135. .time-foot-item.align-right { text-align: right; }
  136. .foot-label { color: #909399; font-size: 12px; }
  137. .time-foot-item strong { color: #606266; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 13px; font-weight: 500; }
  138. .window-track { flex: 1; padding: 0 6px; }
  139. .window-track .el-slider { width: 100%; }
  140. .selection-controls { gap: 12px; margin-top: 14px; }
  141. .selection-readout { display: flex; align-items: center; gap: 8px; color: #606266; font-size: 14px; flex: 1; min-width: 0; }
  142. .selection-readout > span:last-child { line-height: 1.7; word-break: break-all; }
  143. .selection-actions { display: flex; gap: 8px; flex-shrink: 0; }
  144. .selection-readout strong { color: #303133; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: 500; }
  145. .selection-accent { width: 7px; height: 7px; background: #409eff; border-radius: 50%; }
  146. .reference-badge {
  147. flex-shrink: 0;
  148. padding: 1px 8px;
  149. border: 1px solid #4d9e6f;
  150. border-radius: 10px;
  151. color: #2e7d32;
  152. background: #ecf7f1;
  153. font-size: 12px;
  154. white-space: nowrap;
  155. }
  156. .jump-select { width: 280px; }
  157. .jump-select .el-select__wrapper { min-height: 32px; }
  158. .ghost-button.chart-query { font-weight: 500; }
  159. .ghost-button.chart-query.is-dirty {
  160. border-color: #409eff;
  161. background: #ecf5ff;
  162. color: #409eff;
  163. box-shadow: 0 0 0 1px #409eff inset;
  164. }
  165. .ghost-button.el-button { height: 32px; padding: 0 14px; font-size: 13px; }
  166. .window-files { margin-top: 12px; border: 1px solid #ebeef5; border-radius: 4px; overflow: hidden; background: #fff; }
  167. .window-files-title { padding: 8px 12px; color: #606266; font-size: 12px; font-weight: 600; background: #f5f7fa; border-bottom: 1px solid #ebeef5; }
  168. .window-files-table { width: 100%; border-collapse: collapse; font-size: 12px; }
  169. .window-files-table th, .window-files-table td { padding: 6px 10px; text-align: left; border-bottom: 1px solid #f0f2f5; white-space: nowrap; }
  170. .window-files-table th { color: #909399; font-weight: 500; background: #fafbfc; }
  171. .window-files-table td { color: #303133; }
  172. .window-files-table td.mono { color: #606266; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; }
  173. .window-files-table td.file-name { max-width: 280px; overflow: hidden; text-overflow: ellipsis; }
  174. .window-files-table tr:last-child td { border-bottom: 0; }
  175. .window-files-table td.actions { white-space: nowrap; }
  176. .window-files-table .file-action.el-button { height: 24px; margin: 0 2px; padding: 0 10px; font-size: 12px; }
  177. .chart-panel { min-height: 500px; padding: 22px 24px 15px; }
  178. .chart-heading { margin-bottom: 10px; }
  179. .chart-actions { gap: 15px; }
  180. .mode-switch.el-radio-group { display: inline-flex; }
  181. .mode-switch .el-radio-button__inner { font-size: 13px; }
  182. .annotation-width { display: inline-flex; align-items: baseline; gap: 5px; color: #909399; font-size: 13px; white-space: nowrap; }
  183. .annotation-width strong { color: #409eff; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 15px; font-weight: 600; }
  184. .sampling-switch { --el-switch-on-color: #409eff; }
  185. .chart-status { display: flex; align-items: center; gap: 8px; color: #909399; font-size: 13px; white-space: nowrap; }
  186. .chart-status i { width: 7px; height: 7px; }
  187. .chart-status i.busy { background: #e6a23c; animation: pulse 1s ease-in-out infinite alternate; }
  188. @keyframes pulse { to { opacity: .35; } }
  189. .wave-chart-shell { position: relative; }
  190. .chart-toolbar-note { display: flex; align-items: center; gap: 8px; height: 28px; color: #909399; font-size: 12px; }
  191. .chart-dot { width: 7px; height: 7px; border-radius: 50%; background: #409eff; }
  192. .chart-separator { width: 1px; height: 14px; margin: 0 3px; background: #dcdfe6; }
  193. .chart-point-count { margin-left: auto; color: #606266; font-weight: 500; }
  194. .wave-chart { width: 100%; height: 680px; }
  195. .wave-chart.is-merge { height: 560px; }
  196. .pv-preview-shell { position: relative; width: 100%; height: 132px; overflow: hidden; border: 1px solid #ebeef5; border-radius: 4px; background: #f8fafb; }
  197. .pv-preview-title { position: absolute; z-index: 1; top: 3px; left: 10px; color: #8b9aa2; font-size: 11px; pointer-events: none; }
  198. .pv-preview-canvas { display: block; width: 100%; height: 132px; }
  199. .chart-empty-hint { margin-top: 7px; color: #e6a23c; font-size: 12px; }
  200. .annotation-nav { margin-top: 12px; padding: 10px 12px 12px; border: 1px solid #ebeef5; border-radius: 4px; background: #fafbfc; }
  201. .annotation-nav-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 9px; }
  202. .annotation-nav-title { color: #606266; font-size: 13px; font-weight: 600; }
  203. .annotation-nav-controls { display: flex; align-items: center; gap: 8px; }
  204. .annotation-nav-controls .el-button { height: 28px; padding: 0 12px; font-size: 12px; }
  205. .annotation-nav-counter { color: #606266; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; }
  206. .annotation-nav-track { position: relative; height: 16px; border-radius: 3px; background: #eef1f3; overflow: hidden; }
  207. .annotation-nav-seg { position: absolute; top: 2px; bottom: 2px; border-radius: 2px; cursor: pointer; }
  208. .annotation-nav-seg.normal { background: #67c23a; opacity: .75; }
  209. .annotation-nav-seg.abnormal { background: #f56c6c; opacity: .85; }
  210. .annotation-nav-seg.active { outline: 2px solid #409eff; outline-offset: 1px; }
  211. .annotation-nav-seg:hover { opacity: 1; }
  212. .annotation-nav-legend { display: flex; gap: 12px; margin-top: 8px; color: #909399; font-size: 12px; }
  213. .annotation-nav-legend span { display: inline-flex; align-items: center; gap: 5px; }
  214. .annotation-swatch { width: 9px; height: 9px; border-radius: 2px; display: inline-block; }
  215. .annotation-swatch.normal { background: #67c23a; }
  216. .annotation-swatch.abnormal { background: #f56c6c; }
  217. .insight-panel { min-height: 0; padding: 16px; color: #303133; background: #fff; border-color: #ebeef5; }
  218. .insight-panel .compact-heading { margin-bottom: 10px; }
  219. .readout-number { color: #409eff; font-size: 23px; }
  220. .readout-grid { display: flex; flex-direction: column; gap: 8px; margin-top: 12px; }
  221. .readout-card { min-height: 46px; display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 12px; border: 1px solid #ebeef5; border-radius: 4px; background: #fff; }
  222. .readout-card span, .data-footprint span { color: #909399; font-size: 12px; }
  223. .readout-value { min-width: 0; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
  224. .readout-card strong { margin: 0; color: #303133; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 13px; font-weight: 500; text-align: right; }
  225. .readout-card small { margin: 0; color: #909399; font-size: 10px; white-space: nowrap; }
  226. .data-footprint { display: grid; gap: 8px; margin-top: 14px; padding-top: 12px; border-top: 1px solid #ebeef5; }
  227. .data-footprint div { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
  228. .data-footprint strong { max-width: 170px; overflow: hidden; color: #606266; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; font-weight: 500; text-align: right; text-overflow: ellipsis; white-space: nowrap; }
  229. .app-footer { width: min(1600px, calc(100% - 32px)); margin: 0 auto; padding: 17px 2px 22px; color: #909399; font-size: 11px; }
  230. .app-footer b { padding: 0 5px; color: #409eff; font-weight: 400; }
  231. .modal-backdrop { position: fixed; z-index: 20; inset: 0; display: flex; align-items: center; justify-content: center; padding: 24px; background: rgba(0, 0, 0, .45); backdrop-filter: blur(2px); }
  232. .period-modal { position: relative; width: min(1060px, 100%); min-height: 600px; overflow: hidden; background: #fff; border-radius: 4px; box-shadow: 0 12px 32px rgba(0, 0, 0, .16); }
  233. .period-modal-head { align-items: flex-start; padding: 22px 25px 18px; color: #303133; background: #f5f7fa; border-bottom: 1px solid #ebeef5; }
  234. .period-modal-head .eyebrow { display: block; margin-bottom: 7px; color: #409eff; }
  235. .period-modal-head h2 { font-size: 21px; }
  236. .period-modal-head p { margin-top: 7px; color: #909399; font-size: 12px; }
  237. .icon-button { width: 29px; height: 29px; border: 0; color: #909399; background: transparent; font-size: 20px; line-height: 1; }
  238. .icon-button:hover { color: #409eff; }
  239. .period-stat-row { display: flex; flex-wrap: wrap; gap: 0; border-bottom: 1px solid #ebeef5; }
  240. .period-stat-row > div { flex: 1 1 140px; min-height: 68px; display: flex; flex-direction: column; justify-content: center; gap: 5px; padding: 9px 18px; border-right: 1px solid #ebeef5; }
  241. .period-stat-row span { color: #909399; font-size: 11px; }
  242. .period-stat-row strong { color: #606266; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-size: 12px; font-weight: 500; }
  243. .modal-tabs { display: flex; gap: 18px; padding: 17px 25px 0; }
  244. .modal-tabs button { border: 0; border-bottom: 2px solid transparent; padding: 0 0 8px; color: #909399; background: transparent; font-size: 13px; }
  245. .modal-tabs button.active { color: #409eff; border-bottom-color: #409eff; }
  246. .period-chart { width: 100%; height: 440px; }
  247. .modal-loading { position: absolute; z-index: 2; top: 100px; bottom: 0; background: rgba(255, 255, 255, .82); }
  248. @media (max-width: 1250px) {
  249. .workspace { grid-template-columns: minmax(0, 1fr) 250px; }
  250. .query-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  251. .field-point { grid-column: span 2; }
  252. .field-types { grid-column: span 1; }
  253. .query-action { grid-column: span 1; }
  254. }
  255. @media (max-width: 930px) {
  256. .workspace { display: flex; flex-direction: column; width: min(100% - 20px, 760px); }
  257. .insight-panel { order: 4; }
  258. .query-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  259. .field-point, .field-types, .query-action { grid-column: span 2; }
  260. .insight-panel { min-height: auto; }
  261. .readout-grid { grid-template-columns: repeat(2, 1fr); margin: 14px -16px 0; }
  262. .chart-heading { align-items: flex-start; flex-direction: column; }
  263. }
  264. @media (max-width: 620px) {
  265. .app-header { align-items: flex-start; flex-direction: column; gap: 13px; padding: 15px; }
  266. .header-meta { width: 100%; justify-content: space-between; gap: 8px; }
  267. .header-date { max-width: 150px; }
  268. .workspace { width: calc(100% - 16px); margin-top: 10px; gap: 10px; }
  269. .query-panel, .selection-panel, .chart-panel { padding: 17px 14px 14px; }
  270. .query-grid { grid-template-columns: 1fr; gap: 12px; }
  271. .field-point, .field-types, .query-action { grid-column: span 1; }
  272. .time-summary { font-size: 12px; text-align: right; }
  273. .selection-controls { align-items: flex-start; flex-direction: column; }
  274. .chart-actions { width: 100%; align-items: flex-start; flex-direction: column; gap: 10px; }
  275. .chart-status { align-self: flex-end; }
  276. .wave-chart { height: 600px; }
  277. .wave-chart.is-merge { height: 520px; }
  278. .pv-preview-shell, .pv-preview-canvas { height: 118px; }
  279. .chart-toolbar-note { font-size: 11px; }
  280. .chart-point-count { display: none; }
  281. .readout-grid { grid-template-columns: 1fr; }
  282. .app-footer { width: calc(100% - 20px); align-items: flex-start; flex-direction: column; gap: 8px; line-height: 1.4; }
  283. .modal-backdrop { align-items: flex-end; padding: 0; }
  284. .period-modal { max-height: 92vh; overflow: auto; }
  285. .period-stat-row > div { flex-basis: 50%; border-bottom: 1px solid #ebeef5; }
  286. .period-chart { height: 300px; }
  287. }