project-timeline.scss 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. .project-timeline-container {
  2. width: 100%;
  3. height: 100%;
  4. display: flex;
  5. flex-direction: column;
  6. background: #ffffff;
  7. border-radius: 8px;
  8. overflow: hidden;
  9. }
  10. // 顶部筛选栏
  11. .timeline-header {
  12. padding: 16px;
  13. background: #f9fafb;
  14. border-bottom: 1px solid #e5e7eb;
  15. }
  16. .filter-section {
  17. display: flex;
  18. align-items: center;
  19. gap: 16px;
  20. flex-wrap: wrap;
  21. }
  22. .filter-group {
  23. display: flex;
  24. align-items: center;
  25. gap: 8px;
  26. label {
  27. font-size: 14px;
  28. font-weight: 500;
  29. color: #374151;
  30. white-space: nowrap;
  31. }
  32. }
  33. .filter-select {
  34. padding: 6px 12px;
  35. border: 1px solid #d1d5db;
  36. border-radius: 6px;
  37. font-size: 14px;
  38. background: #ffffff;
  39. cursor: pointer;
  40. transition: all 0.2s;
  41. &:hover {
  42. border-color: #9ca3af;
  43. }
  44. &:focus {
  45. outline: none;
  46. border-color: #3b82f6;
  47. box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
  48. }
  49. }
  50. .quick-filters {
  51. margin-left: auto;
  52. }
  53. .filter-btn {
  54. padding: 6px 12px;
  55. border: 1px solid #d1d5db;
  56. border-radius: 6px;
  57. background: #ffffff;
  58. font-size: 13px;
  59. cursor: pointer;
  60. transition: all 0.2s;
  61. &:hover {
  62. background: #f3f4f6;
  63. }
  64. &.active {
  65. background: #3b82f6;
  66. color: #ffffff;
  67. border-color: #3b82f6;
  68. }
  69. }
  70. .view-controls,
  71. .sort-controls,
  72. .time-scale-controls {
  73. border-left: 1px solid #e5e7eb;
  74. padding-left: 16px;
  75. }
  76. .view-btn,
  77. .sort-btn,
  78. .scale-btn,
  79. .refresh-btn {
  80. padding: 6px 12px;
  81. border: 1px solid #d1d5db;
  82. border-radius: 6px;
  83. background: #ffffff;
  84. font-size: 13px;
  85. cursor: pointer;
  86. transition: all 0.2s;
  87. &:hover {
  88. background: #f3f4f6;
  89. }
  90. &.active {
  91. background: #3b82f6;
  92. color: #ffffff;
  93. border-color: #3b82f6;
  94. }
  95. }
  96. // 时间尺度切换按钮特殊样式
  97. .time-scale-controls {
  98. .scale-btn.active {
  99. background: #10b981;
  100. border-color: #10b981;
  101. font-weight: 600;
  102. }
  103. }
  104. // 🆕 刷新按钮特殊样式
  105. .refresh-btn {
  106. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  107. color: #ffffff;
  108. border: none;
  109. font-weight: 600;
  110. &:hover {
  111. background: linear-gradient(135deg, #5568d3 0%, #63408b 100%);
  112. transform: scale(1.05);
  113. }
  114. &:active {
  115. animation: refresh-spin 0.6s ease-in-out;
  116. }
  117. }
  118. @keyframes refresh-spin {
  119. from {
  120. transform: rotate(0deg);
  121. }
  122. to {
  123. transform: rotate(360deg);
  124. }
  125. }
  126. // 设计师统计面板
  127. .designer-stats-panel {
  128. margin-top: 12px;
  129. padding: 12px 16px;
  130. background: #ffffff;
  131. border: 1px solid #e5e7eb;
  132. border-radius: 6px;
  133. }
  134. .stats-header {
  135. display: flex;
  136. align-items: center;
  137. justify-content: space-between;
  138. margin-bottom: 12px;
  139. h3 {
  140. margin: 0;
  141. font-size: 16px;
  142. font-weight: 600;
  143. color: #111827;
  144. }
  145. }
  146. .workload-badge {
  147. padding: 4px 12px;
  148. border-radius: 12px;
  149. font-size: 13px;
  150. font-weight: 500;
  151. &.level-low {
  152. background: #d1fae5;
  153. color: #065f46;
  154. }
  155. &.level-medium {
  156. background: #fef3c7;
  157. color: #92400e;
  158. }
  159. &.level-high {
  160. background: #fee2e2;
  161. color: #991b1b;
  162. }
  163. }
  164. .stats-body {
  165. display: grid;
  166. grid-template-columns: repeat(3, 1fr);
  167. gap: 12px;
  168. }
  169. .stat-item {
  170. display: flex;
  171. flex-direction: column;
  172. padding: 8px;
  173. background: #f9fafb;
  174. border-radius: 4px;
  175. }
  176. .stat-label {
  177. font-size: 12px;
  178. color: #6b7280;
  179. margin-bottom: 4px;
  180. }
  181. .stat-value {
  182. font-size: 18px;
  183. font-weight: 600;
  184. color: #111827;
  185. &.urgent {
  186. color: #ea580c;
  187. }
  188. &.overdue {
  189. color: #dc2626;
  190. }
  191. }
  192. // 时间轴主体
  193. .timeline-body {
  194. flex: 1;
  195. overflow-y: auto;
  196. padding: 16px;
  197. }
  198. // 列表视图
  199. .projects-list {
  200. display: flex;
  201. flex-direction: column;
  202. gap: 12px;
  203. }
  204. .project-item {
  205. position: relative;
  206. display: flex;
  207. padding: 16px;
  208. background: #ffffff;
  209. border: 1px solid #e5e7eb;
  210. border-radius: 8px;
  211. cursor: pointer;
  212. transition: all 0.2s;
  213. &:hover {
  214. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  215. transform: translateY(-2px);
  216. }
  217. &.status-overdue {
  218. border-left-width: 4px;
  219. border-left-color: #dc2626;
  220. }
  221. &.status-urgent {
  222. border-left-width: 4px;
  223. border-left-color: #ea580c;
  224. }
  225. &.status-warning {
  226. border-left-width: 4px;
  227. border-left-color: #f59e0b;
  228. }
  229. }
  230. .priority-bar {
  231. position: absolute;
  232. left: 0;
  233. top: 0;
  234. bottom: 0;
  235. width: 4px;
  236. border-radius: 8px 0 0 8px;
  237. &.priority-critical {
  238. background: linear-gradient(180deg, #dc2626 0%, #991b1b 100%);
  239. }
  240. &.priority-high {
  241. background: linear-gradient(180deg, #ea580c 0%, #c2410c 100%);
  242. }
  243. &.priority-medium {
  244. background: linear-gradient(180deg, #f59e0b 0%, #d97706 100%);
  245. }
  246. &.priority-low {
  247. background: linear-gradient(180deg, #10b981 0%, #059669 100%);
  248. }
  249. }
  250. .project-content {
  251. flex: 1;
  252. padding-left: 8px;
  253. }
  254. .project-header {
  255. display: flex;
  256. align-items: center;
  257. justify-content: space-between;
  258. margin-bottom: 12px;
  259. }
  260. .project-name {
  261. margin: 0;
  262. font-size: 16px;
  263. font-weight: 600;
  264. color: #111827;
  265. }
  266. .project-badges {
  267. display: flex;
  268. gap: 8px;
  269. }
  270. .badge {
  271. padding: 4px 8px;
  272. border-radius: 4px;
  273. font-size: 12px;
  274. font-weight: 500;
  275. white-space: nowrap;
  276. &.badge-stalled {
  277. background: #f3f4f6;
  278. color: #6b7280;
  279. }
  280. &.badge-urgent {
  281. background: #fee2e2;
  282. color: #991b1b;
  283. }
  284. &.badge-overdue {
  285. background: #fecaca;
  286. color: #7f1d1d;
  287. }
  288. &.badge-warning {
  289. background: #fed7aa;
  290. color: #9a3412;
  291. }
  292. // 🆕 空间与交付物统计徽章(列表视图)
  293. &.badge-deliverable {
  294. padding: 4px 10px;
  295. border-radius: 12px;
  296. font-size: 11px;
  297. font-weight: 600;
  298. cursor: help;
  299. transition: transform 0.2s, box-shadow 0.2s;
  300. &:hover {
  301. transform: scale(1.05);
  302. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  303. }
  304. }
  305. }
  306. .project-meta {
  307. display: flex;
  308. gap: 16px;
  309. flex-wrap: wrap;
  310. }
  311. .meta-item {
  312. display: flex;
  313. gap: 4px;
  314. font-size: 13px;
  315. }
  316. .meta-label {
  317. color: #6b7280;
  318. }
  319. .meta-value {
  320. color: #374151;
  321. font-weight: 500;
  322. &.text-danger {
  323. color: #dc2626;
  324. }
  325. }
  326. // 空状态
  327. .empty-state {
  328. display: flex;
  329. align-items: center;
  330. justify-content: center;
  331. padding: 60px 20px;
  332. text-align: center;
  333. p {
  334. margin: 0;
  335. font-size: 15px;
  336. color: #9ca3af;
  337. }
  338. }
  339. // 时间轴视图容器
  340. .timeline-view-container {
  341. position: relative;
  342. width: 100%;
  343. min-height: 400px;
  344. }
  345. // 图例说明
  346. .timeline-legend {
  347. display: flex;
  348. justify-content: center;
  349. align-items: center;
  350. gap: 24px;
  351. padding: 12px 20px;
  352. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  353. border-radius: 8px 8px 0 0;
  354. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  355. }
  356. .legend-item {
  357. display: flex;
  358. align-items: center;
  359. gap: 8px;
  360. }
  361. .legend-icon {
  362. display: flex;
  363. align-items: center;
  364. justify-content: center;
  365. width: 24px;
  366. height: 24px;
  367. border-radius: 50%;
  368. font-size: 16px;
  369. color: #ffffff;
  370. box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2);
  371. &.start-icon {
  372. background: #10b981;
  373. }
  374. &.review-icon {
  375. background: #8b5cf6;
  376. }
  377. &.delivery-icon {
  378. background: #f59e0b;
  379. border-radius: 4px;
  380. transform: rotate(45deg);
  381. }
  382. }
  383. .legend-bar-demo {
  384. width: 40px;
  385. height: 12px;
  386. border-radius: 4px;
  387. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  388. }
  389. // 🆕 四种紧急度颜色图例
  390. .legend-bar-green {
  391. background: linear-gradient(135deg, #86EFAC 0%, #4ADE80 100%);
  392. }
  393. .legend-bar-yellow {
  394. background: linear-gradient(135deg, #FEF08A 0%, #EAB308 100%);
  395. }
  396. .legend-bar-orange {
  397. background: linear-gradient(135deg, #FCD34D 0%, #F59E0B 100%);
  398. }
  399. .legend-bar-red {
  400. background: linear-gradient(135deg, #FCA5A5 0%, #EF4444 100%);
  401. }
  402. .legend-label {
  403. font-size: 13px;
  404. font-weight: 500;
  405. color: #ffffff;
  406. text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  407. }
  408. // 🆕 图例注释样式
  409. .legend-note {
  410. margin-left: auto;
  411. padding-left: 16px;
  412. border-left: 1px solid rgba(255, 255, 255, 0.3);
  413. .legend-label {
  414. font-size: 12px;
  415. font-weight: 600;
  416. color: #fef3c7;
  417. opacity: 0.95;
  418. }
  419. }
  420. // 时间刻度尺
  421. .timeline-ruler {
  422. display: flex;
  423. position: sticky;
  424. top: 0;
  425. z-index: 10;
  426. background: #ffffff;
  427. border-bottom: 2px solid #e5e7eb;
  428. padding: 8px 0;
  429. }
  430. .ruler-header {
  431. width: 180px;
  432. min-width: 180px;
  433. padding: 12px 12px;
  434. font-weight: 600;
  435. font-size: 14px;
  436. color: #111827;
  437. border-right: 2px solid #e5e7eb;
  438. background: #f9fafb;
  439. }
  440. .ruler-ticks {
  441. flex: 1;
  442. display: flex;
  443. position: relative;
  444. }
  445. .ruler-tick {
  446. flex: 1;
  447. text-align: center;
  448. border-right: 1px solid #e5e7eb;
  449. padding: 8px 4px;
  450. display: flex;
  451. flex-direction: column;
  452. gap: 2px;
  453. &:last-child {
  454. border-right: none;
  455. }
  456. &.first {
  457. border-left: 2px solid #3b82f6;
  458. }
  459. }
  460. .tick-date {
  461. font-size: 14px;
  462. color: #111827;
  463. font-weight: 600;
  464. line-height: 1.2;
  465. }
  466. .tick-weekday {
  467. font-size: 11px;
  468. color: #6b7280;
  469. font-weight: 500;
  470. line-height: 1.2;
  471. }
  472. // 🆕 今日标记线(实时移动,精确到分钟)- 重构版
  473. .today-line {
  474. position: absolute;
  475. top: 0;
  476. bottom: 0;
  477. z-index: 10;
  478. pointer-events: none;
  479. left: 0; // 通过 [style.left] 动态设置
  480. }
  481. // 🆕 今日时间标签(顶部显示完整时间)
  482. .today-label {
  483. position: absolute;
  484. top: -40px;
  485. left: 50%;
  486. transform: translateX(-50%);
  487. padding: 8px 16px;
  488. background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
  489. color: #ffffff;
  490. font-size: 13px;
  491. font-weight: 700;
  492. border-radius: 8px;
  493. white-space: nowrap;
  494. box-shadow: 0 4px 16px rgba(239, 68, 68, 0.5);
  495. letter-spacing: 0.5px;
  496. animation: today-label-pulse 2s ease-in-out infinite;
  497. // 小三角箭头
  498. &::after {
  499. content: '';
  500. position: absolute;
  501. top: 100%;
  502. left: 50%;
  503. transform: translateX(-50%);
  504. width: 0;
  505. height: 0;
  506. border-left: 6px solid transparent;
  507. border-right: 6px solid transparent;
  508. border-top: 6px solid #dc2626;
  509. }
  510. }
  511. // 🆕 顶部圆点指示器(更大更明显)
  512. .today-dot {
  513. position: absolute;
  514. top: -4px;
  515. left: 50%;
  516. transform: translateX(-50%);
  517. width: 16px;
  518. height: 16px;
  519. background: #ef4444;
  520. border-radius: 50%;
  521. border: 3px solid #ffffff;
  522. box-shadow: 0 0 0 2px #ef4444, 0 4px 12px rgba(239, 68, 68, 0.6);
  523. animation: today-dot-pulse 1.5s ease-in-out infinite;
  524. }
  525. // 🆕 主竖线条(更宽更明显)
  526. .today-bar {
  527. position: absolute;
  528. top: 0;
  529. bottom: 0;
  530. left: 50%;
  531. transform: translateX(-50%);
  532. width: 4px;
  533. background: linear-gradient(180deg,
  534. rgba(239, 68, 68, 0.95) 0%,
  535. rgba(239, 68, 68, 0.85) 50%,
  536. rgba(239, 68, 68, 0.95) 100%
  537. );
  538. box-shadow:
  539. 0 0 8px rgba(239, 68, 68, 0.6),
  540. 0 0 16px rgba(239, 68, 68, 0.4);
  541. animation: today-bar-pulse 2s ease-in-out infinite;
  542. }
  543. // 🆕 时间标签脉动动画
  544. @keyframes today-label-pulse {
  545. 0%, 100% {
  546. transform: translateX(-50%) scale(1);
  547. box-shadow: 0 4px 16px rgba(239, 68, 68, 0.5);
  548. }
  549. 50% {
  550. transform: translateX(-50%) scale(1.05);
  551. box-shadow: 0 6px 24px rgba(239, 68, 68, 0.7);
  552. }
  553. }
  554. // 🆕 圆点脉动动画(更明显)
  555. @keyframes today-dot-pulse {
  556. 0%, 100% {
  557. transform: translateX(-50%) scale(1);
  558. box-shadow: 0 0 0 2px #ef4444, 0 4px 12px rgba(239, 68, 68, 0.6);
  559. }
  560. 50% {
  561. transform: translateX(-50%) scale(1.4);
  562. box-shadow: 0 0 0 4px rgba(239, 68, 68, 0.5), 0 6px 20px rgba(239, 68, 68, 0.8);
  563. }
  564. }
  565. // 🆕 竖线脉动动画
  566. @keyframes today-bar-pulse {
  567. 0%, 100% {
  568. opacity: 1;
  569. box-shadow:
  570. 0 0 8px rgba(239, 68, 68, 0.6),
  571. 0 0 16px rgba(239, 68, 68, 0.4);
  572. }
  573. 50% {
  574. opacity: 0.9;
  575. box-shadow:
  576. 0 0 12px rgba(239, 68, 68, 0.8),
  577. 0 0 24px rgba(239, 68, 68, 0.6);
  578. }
  579. }
  580. // 项目时间轴
  581. .timeline-projects {
  582. position: relative;
  583. min-height: 300px;
  584. }
  585. .timeline-row {
  586. display: flex;
  587. border-bottom: 1px solid #f3f4f6;
  588. cursor: pointer;
  589. transition: background 0.2s;
  590. &:hover {
  591. background: #f9fafb;
  592. .project-bar {
  593. transform: scaleY(1.1);
  594. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  595. }
  596. .event-marker {
  597. transform: scale(1.3);
  598. }
  599. }
  600. }
  601. // 项目标签区
  602. .project-label {
  603. width: 180px;
  604. min-width: 180px;
  605. padding: 12px 12px;
  606. display: flex;
  607. flex-direction: column;
  608. gap: 4px;
  609. border-right: 2px solid #e5e7eb;
  610. background: #fafafa;
  611. }
  612. .project-name-label {
  613. font-size: 14px;
  614. font-weight: 500;
  615. color: #111827;
  616. white-space: nowrap;
  617. overflow: hidden;
  618. text-overflow: ellipsis;
  619. }
  620. .designer-label {
  621. font-size: 12px;
  622. color: #6b7280;
  623. }
  624. .priority-badge {
  625. font-size: 16px;
  626. line-height: 1;
  627. }
  628. // 🆕 空间与交付物统计徽章
  629. .space-deliverable-badge {
  630. padding: 2px 8px;
  631. border-radius: 10px;
  632. font-size: 10px;
  633. font-weight: 600;
  634. color: white;
  635. margin-left: 4px;
  636. white-space: nowrap;
  637. cursor: help;
  638. transition: transform 0.2s, box-shadow 0.2s;
  639. &:hover {
  640. transform: scale(1.05);
  641. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  642. }
  643. }
  644. // 时间轴轨道
  645. .timeline-track {
  646. flex: 1;
  647. position: relative;
  648. height: 70px;
  649. padding: 19px 0;
  650. background: repeating-linear-gradient(
  651. 90deg,
  652. transparent,
  653. transparent calc(100% / 7 - 1px),
  654. #f3f4f6 calc(100% / 7 - 1px),
  655. #f3f4f6 calc(100% / 7)
  656. );
  657. }
  658. // 项目条形图
  659. .project-bar {
  660. position: absolute;
  661. top: 50%;
  662. transform: translateY(-50%);
  663. height: 32px;
  664. border-radius: 6px;
  665. transition: all 0.3s;
  666. overflow: hidden;
  667. box-shadow: 0 3px 8px rgba(0, 0, 0, 0.12);
  668. border: 2px solid rgba(255, 255, 255, 0.5);
  669. opacity: 0.95;
  670. &.status-overdue {
  671. border: 3px solid #dc2626;
  672. animation: pulse 2s infinite;
  673. box-shadow: 0 0 15px rgba(220, 38, 38, 0.4);
  674. }
  675. &:hover {
  676. opacity: 1;
  677. }
  678. }
  679. // 进度填充
  680. .progress-fill {
  681. position: absolute;
  682. top: 0;
  683. left: 0;
  684. bottom: 0;
  685. background: linear-gradient(90deg,
  686. rgba(0, 0, 0, 0.25) 0%,
  687. rgba(0, 0, 0, 0.15) 100%
  688. );
  689. transition: width 0.3s;
  690. border-right: 2px solid rgba(255, 255, 255, 0.6);
  691. }
  692. // 事件标记
  693. .event-marker {
  694. position: absolute;
  695. top: 50%;
  696. transform: translateY(-50%);
  697. width: 28px;
  698. height: 28px;
  699. display: flex;
  700. align-items: center;
  701. justify-content: center;
  702. font-size: 20px;
  703. color: #ffffff;
  704. border-radius: 50%;
  705. cursor: pointer;
  706. transition: all 0.2s;
  707. z-index: 10;
  708. box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
  709. border: 2px solid rgba(255, 255, 255, 0.9);
  710. &.start {
  711. font-size: 16px;
  712. width: 24px;
  713. height: 24px;
  714. }
  715. &.review {
  716. font-size: 18px;
  717. width: 26px;
  718. height: 26px;
  719. border-radius: 50%;
  720. }
  721. &.delivery {
  722. font-size: 22px;
  723. width: 30px;
  724. height: 30px;
  725. border-radius: 4px;
  726. transform: translateY(-50%) rotate(45deg);
  727. &:hover {
  728. transform: translateY(-50%) rotate(45deg) scale(1.3);
  729. }
  730. }
  731. &.blink {
  732. animation: blink 1s infinite;
  733. }
  734. &:hover {
  735. transform: translateY(-50%) scale(1.4);
  736. z-index: 20;
  737. box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
  738. }
  739. }
  740. // 动画
  741. @keyframes pulse {
  742. 0%, 100% {
  743. opacity: 1;
  744. }
  745. 50% {
  746. opacity: 0.7;
  747. }
  748. }
  749. @keyframes blink {
  750. 0%, 100% {
  751. opacity: 1;
  752. }
  753. 50% {
  754. opacity: 0.3;
  755. }
  756. }
  757. // 响应式设计
  758. @media (max-width: 768px) {
  759. .filter-section {
  760. flex-direction: column;
  761. align-items: stretch;
  762. }
  763. .filter-group {
  764. width: 100%;
  765. &.quick-filters {
  766. margin-left: 0;
  767. }
  768. &.view-controls,
  769. &.sort-controls {
  770. border-left: none;
  771. border-top: 1px solid #e5e7eb;
  772. padding-left: 0;
  773. padding-top: 12px;
  774. }
  775. }
  776. .stats-body {
  777. grid-template-columns: 1fr;
  778. }
  779. .project-header {
  780. flex-direction: column;
  781. align-items: flex-start;
  782. gap: 8px;
  783. }
  784. .project-meta {
  785. flex-direction: column;
  786. gap: 8px;
  787. }
  788. // 时间轴视图响应式
  789. .timeline-legend {
  790. flex-wrap: wrap;
  791. gap: 12px;
  792. padding: 8px 12px;
  793. }
  794. .legend-item {
  795. gap: 6px;
  796. }
  797. .legend-label {
  798. font-size: 11px;
  799. }
  800. .ruler-header,
  801. .project-label {
  802. width: 100px;
  803. min-width: 100px;
  804. padding: 8px;
  805. }
  806. .project-name-label {
  807. font-size: 11px;
  808. }
  809. .designer-label {
  810. font-size: 10px;
  811. }
  812. .tick-date {
  813. font-size: 11px;
  814. }
  815. .tick-weekday {
  816. font-size: 9px;
  817. }
  818. .timeline-track {
  819. height: 50px;
  820. padding: 14px 0;
  821. }
  822. .project-bar {
  823. height: 22px;
  824. }
  825. .event-marker {
  826. width: 20px;
  827. height: 20px;
  828. font-size: 14px;
  829. &.start {
  830. width: 18px;
  831. height: 18px;
  832. font-size: 12px;
  833. }
  834. &.review {
  835. width: 19px;
  836. height: 19px;
  837. font-size: 13px;
  838. }
  839. &.delivery {
  840. width: 22px;
  841. height: 22px;
  842. font-size: 16px;
  843. }
  844. }
  845. }