project-files-modal.component.scss 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. .modal-overlay {
  2. position: fixed;
  3. top: 0;
  4. left: 0;
  5. right: 0;
  6. bottom: 0;
  7. background-color: rgba(0, 0, 0, 0.5);
  8. display: flex;
  9. align-items: center;
  10. justify-content: center;
  11. z-index: 99;
  12. padding: 20px;
  13. }
  14. .modal-container {
  15. background: white;
  16. border-radius: 12px;
  17. max-width: 1200px;
  18. width: 100%;
  19. max-height: 90vh;
  20. display: flex;
  21. flex-direction: column;
  22. box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  23. overflow: hidden;
  24. }
  25. .modal-header {
  26. padding: 24px;
  27. border-bottom: 1px solid #e5e7eb;
  28. display: flex;
  29. justify-content: space-between;
  30. align-items: flex-start;
  31. gap: 20px;
  32. flex-shrink: 0;
  33. .header-left {
  34. flex: 1;
  35. min-width: 0;
  36. .modal-title {
  37. font-size: 24px;
  38. font-weight: 600;
  39. color: #1f2937;
  40. margin: 0 0 12px 0;
  41. display: flex;
  42. align-items: center;
  43. gap: 8px;
  44. .title-icon {
  45. width: 28px;
  46. height: 28px;
  47. color: #3b82f6;
  48. }
  49. }
  50. .file-stats {
  51. display: flex;
  52. gap: 16px;
  53. flex-wrap: wrap;
  54. .stat-item {
  55. display: flex;
  56. flex-direction: column;
  57. align-items: center;
  58. min-width: 50px;
  59. .stat-number {
  60. font-size: 18px;
  61. font-weight: 600;
  62. color: #1f2937;
  63. line-height: 1;
  64. }
  65. .stat-label {
  66. font-size: 12px;
  67. color: #6b7280;
  68. margin-top: 2px;
  69. }
  70. }
  71. }
  72. }
  73. .header-right {
  74. display: flex;
  75. align-items: center;
  76. gap: 12px;
  77. flex-shrink: 0;
  78. .view-toggle {
  79. display: flex;
  80. border: 1px solid #e5e7eb;
  81. border-radius: 6px;
  82. overflow: hidden;
  83. .toggle-btn {
  84. background: white;
  85. border: none;
  86. padding: 8px 12px;
  87. cursor: pointer;
  88. display: flex;
  89. align-items: center;
  90. justify-content: center;
  91. transition: all 0.2s ease;
  92. color: #6b7280;
  93. svg {
  94. width: 18px;
  95. height: 18px;
  96. }
  97. &:hover {
  98. background-color: #f9fafb;
  99. }
  100. &.active {
  101. background-color: #3b82f6;
  102. color: white;
  103. }
  104. &:not(:last-child) {
  105. border-right: 1px solid #e5e7eb;
  106. }
  107. }
  108. }
  109. .search-box {
  110. position: relative;
  111. display: flex;
  112. align-items: center;
  113. .search-icon {
  114. position: absolute;
  115. left: 12px;
  116. width: 18px;
  117. height: 18px;
  118. color: #6b7280;
  119. }
  120. .search-input {
  121. padding: 8px 12px 8px 36px;
  122. border: 1px solid #e5e7eb;
  123. border-radius: 6px;
  124. font-size: 14px;
  125. width: 200px;
  126. outline: none;
  127. transition: border-color 0.2s ease;
  128. &:focus {
  129. border-color: #3b82f6;
  130. box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
  131. }
  132. }
  133. }
  134. .filter-select {
  135. padding: 8px 12px;
  136. border: 1px solid #e5e7eb;
  137. border-radius: 6px;
  138. font-size: 14px;
  139. outline: none;
  140. cursor: pointer;
  141. transition: border-color 0.2s ease;
  142. &:focus {
  143. border-color: #3b82f6;
  144. }
  145. }
  146. .close-btn {
  147. background: none;
  148. border: none;
  149. padding: 8px;
  150. border-radius: 6px;
  151. cursor: pointer;
  152. color: #6b7280;
  153. transition: all 0.2s ease;
  154. display: flex;
  155. align-items: center;
  156. justify-content: center;
  157. svg {
  158. width: 20px;
  159. height: 20px;
  160. }
  161. &:hover {
  162. background-color: #f3f4f6;
  163. color: #374151;
  164. }
  165. }
  166. }
  167. }
  168. .modal-content {
  169. flex: 1;
  170. padding: 24px;
  171. overflow-y: auto;
  172. min-height: 0;
  173. }
  174. .loading-state {
  175. display: flex;
  176. flex-direction: column;
  177. align-items: center;
  178. justify-content: center;
  179. padding: 60px 20px;
  180. color: #6b7280;
  181. .loading-spinner {
  182. width: 40px;
  183. height: 40px;
  184. border: 3px solid #e5e7eb;
  185. border-top: 3px solid #3b82f6;
  186. border-radius: 50%;
  187. animation: spin 1s linear infinite;
  188. margin-bottom: 16px;
  189. }
  190. p {
  191. margin: 0;
  192. font-size: 16px;
  193. }
  194. }
  195. .empty-state {
  196. text-align: center;
  197. padding: 60px 20px;
  198. color: #6b7280;
  199. .empty-icon {
  200. width: 64px;
  201. height: 64px;
  202. margin: 0 auto 16px;
  203. opacity: 0.3;
  204. }
  205. h3 {
  206. font-size: 18px;
  207. font-weight: 600;
  208. margin: 0 0 8px 0;
  209. color: #374151;
  210. }
  211. p {
  212. margin: 0;
  213. font-size: 14px;
  214. }
  215. }
  216. .files-grid {
  217. display: grid;
  218. grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  219. gap: 20px;
  220. }
  221. .file-card {
  222. background: white;
  223. border: 1px solid #e5e7eb;
  224. border-radius: 8px;
  225. overflow: hidden;
  226. cursor: pointer;
  227. transition: all 0.2s ease;
  228. &:hover {
  229. border-color: #3b82f6;
  230. box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
  231. transform: translateY(-2px);
  232. }
  233. .file-preview {
  234. aspect-ratio: 16/9;
  235. background-color: #f9fafb;
  236. position: relative;
  237. overflow: hidden;
  238. .preview-image {
  239. width: 100%;
  240. height: 100%;
  241. object-fit: cover;
  242. }
  243. .preview-placeholder {
  244. display: flex;
  245. flex-direction: column;
  246. align-items: center;
  247. justify-content: center;
  248. height: 100%;
  249. padding: 20px;
  250. .file-icon {
  251. font-size: 48px;
  252. margin-bottom: 8px;
  253. opacity: 0.6;
  254. }
  255. .file-extension {
  256. font-size: 14px;
  257. font-weight: 600;
  258. color: #6b7280;
  259. background-color: #f3f4f6;
  260. padding: 4px 8px;
  261. border-radius: 4px;
  262. }
  263. }
  264. }
  265. .file-info {
  266. padding: 16px;
  267. .file-name {
  268. font-size: 14px;
  269. font-weight: 600;
  270. color: #1f2937;
  271. margin: 0 0 8px 0;
  272. line-height: 1.4;
  273. display: -webkit-box;
  274. -webkit-line-clamp: 2;
  275. -webkit-box-orient: vertical;
  276. overflow: hidden;
  277. }
  278. .file-meta {
  279. display: flex;
  280. gap: 8px;
  281. margin-bottom: 8px;
  282. font-size: 12px;
  283. color: #6b7280;
  284. .file-size {
  285. font-weight: 500;
  286. }
  287. }
  288. .file-description {
  289. margin-bottom: 12px;
  290. p {
  291. font-size: 12px;
  292. color: #6b7280;
  293. margin: 0;
  294. line-height: 1.4;
  295. display: -webkit-box;
  296. -webkit-line-clamp: 2;
  297. -webkit-box-orient: vertical;
  298. overflow: hidden;
  299. }
  300. }
  301. .file-footer {
  302. display: flex;
  303. justify-content: space-between;
  304. align-items: center;
  305. .uploader-info {
  306. display: flex;
  307. align-items: center;
  308. gap: 8px;
  309. flex: 1;
  310. min-width: 0;
  311. .uploader-avatar {
  312. width: 24px;
  313. height: 24px;
  314. border-radius: 50%;
  315. object-fit: cover;
  316. }
  317. .uploader-name {
  318. font-size: 12px;
  319. color: #374151;
  320. font-weight: 500;
  321. white-space: nowrap;
  322. overflow: hidden;
  323. text-overflow: ellipsis;
  324. }
  325. .source-badge {
  326. font-size: 10px;
  327. padding: 2px 6px;
  328. border-radius: 10px;
  329. font-weight: 500;
  330. white-space: nowrap;
  331. &.source-wxwork {
  332. background-color: #dcfce7;
  333. color: #166534;
  334. }
  335. &.source-manual {
  336. background-color: #dbeafe;
  337. color: #1e40af;
  338. }
  339. &.source-default {
  340. background-color: #f3f4f6;
  341. color: #6b7280;
  342. }
  343. }
  344. }
  345. .file-actions {
  346. .action-btn {
  347. background: none;
  348. border: none;
  349. padding: 6px;
  350. border-radius: 4px;
  351. cursor: pointer;
  352. color: #6b7280;
  353. transition: all 0.2s ease;
  354. display: flex;
  355. align-items: center;
  356. justify-content: center;
  357. svg {
  358. width: 16px;
  359. height: 16px;
  360. }
  361. &:hover {
  362. background-color: #f3f4f6;
  363. color: #374151;
  364. &.download-btn {
  365. background-color: #eff6ff;
  366. color: #3b82f6;
  367. }
  368. }
  369. &.download-btn:hover {
  370. background-color: #eff6ff;
  371. color: #3b82f6;
  372. }
  373. }
  374. }
  375. }
  376. }
  377. }
  378. .files-list {
  379. .file-list-item {
  380. display: flex;
  381. align-items: center;
  382. gap: 16px;
  383. padding: 16px;
  384. border-bottom: 1px solid #f3f4f6;
  385. cursor: pointer;
  386. transition: background-color 0.2s ease;
  387. &:hover {
  388. background-color: #f9fafb;
  389. }
  390. &:last-child {
  391. border-bottom: none;
  392. }
  393. .list-file-icon {
  394. width: 48px;
  395. height: 48px;
  396. border-radius: 6px;
  397. overflow: hidden;
  398. background-color: #f3f4f6;
  399. display: flex;
  400. align-items: center;
  401. justify-content: center;
  402. flex-shrink: 0;
  403. .list-preview-image {
  404. width: 100%;
  405. height: 100%;
  406. object-fit: cover;
  407. }
  408. .list-icon {
  409. font-size: 24px;
  410. }
  411. }
  412. .list-file-info {
  413. flex: 1;
  414. min-width: 0;
  415. .list-file-name {
  416. font-size: 14px;
  417. font-weight: 600;
  418. color: #1f2937;
  419. margin-bottom: 4px;
  420. }
  421. .list-file-meta {
  422. display: flex;
  423. gap: 12px;
  424. font-size: 12px;
  425. color: #6b7280;
  426. flex-wrap: wrap;
  427. .source-badge {
  428. font-size: 10px;
  429. padding: 2px 6px;
  430. border-radius: 10px;
  431. font-weight: 500;
  432. &.source-wxwork {
  433. background-color: #dcfce7;
  434. color: #166534;
  435. }
  436. &.source-manual {
  437. background-color: #dbeafe;
  438. color: #1e40af;
  439. }
  440. &.source-default {
  441. background-color: #f3f4f6;
  442. color: #6b7280;
  443. }
  444. }
  445. }
  446. .list-file-description {
  447. font-size: 12px;
  448. color: #6b7280;
  449. margin-top: 4px;
  450. display: -webkit-box;
  451. -webkit-line-clamp: 1;
  452. -webkit-box-orient: vertical;
  453. overflow: hidden;
  454. }
  455. }
  456. .list-file-actions {
  457. .action-btn {
  458. background: none;
  459. border: none;
  460. padding: 8px;
  461. border-radius: 4px;
  462. cursor: pointer;
  463. color: #6b7280;
  464. transition: all 0.2s ease;
  465. svg {
  466. width: 18px;
  467. height: 18px;
  468. }
  469. &:hover {
  470. background-color: #f3f4f6;
  471. color: #374151;
  472. &.download-btn {
  473. background-color: #eff6ff;
  474. color: #3b82f6;
  475. }
  476. }
  477. }
  478. }
  479. }
  480. }
  481. // 预览模态框
  482. .preview-overlay {
  483. position: fixed;
  484. top: 0;
  485. left: 0;
  486. right: 0;
  487. bottom: 0;
  488. background-color: rgba(0, 0, 0, 0.8);
  489. display: flex;
  490. align-items: center;
  491. justify-content: center;
  492. z-index: 100;
  493. padding: 20px;
  494. }
  495. .preview-container {
  496. background: white;
  497. border-radius: 12px;
  498. max-width: 90vw;
  499. max-height: 90vh;
  500. width: 100%;
  501. display: flex;
  502. flex-direction: column;
  503. overflow: hidden;
  504. .preview-header {
  505. padding: 20px;
  506. border-bottom: 1px solid #e5e7eb;
  507. display: flex;
  508. justify-content: space-between;
  509. align-items: center;
  510. h3 {
  511. font-size: 18px;
  512. font-weight: 600;
  513. color: #1f2937;
  514. margin: 0;
  515. flex: 1;
  516. min-width: 0;
  517. overflow: hidden;
  518. text-overflow: ellipsis;
  519. white-space: nowrap;
  520. }
  521. .preview-close {
  522. background: none;
  523. border: none;
  524. padding: 8px;
  525. border-radius: 6px;
  526. cursor: pointer;
  527. color: #6b7280;
  528. transition: all 0.2s ease;
  529. svg {
  530. width: 20px;
  531. height: 20px;
  532. }
  533. &:hover {
  534. background-color: #f3f4f6;
  535. color: #374151;
  536. }
  537. }
  538. }
  539. .preview-content {
  540. flex: 1;
  541. padding: 20px;
  542. display: flex;
  543. align-items: center;
  544. justify-content: center;
  545. background-color: #f9fafb;
  546. min-height: 300px;
  547. .preview-full-image {
  548. max-width: 100%;
  549. max-height: 100%;
  550. object-fit: contain;
  551. border-radius: 8px;
  552. }
  553. .preview-video {
  554. max-width: 100%;
  555. max-height: 100%;
  556. border-radius: 8px;
  557. }
  558. .preview-no-preview {
  559. text-align: center;
  560. color: #6b7280;
  561. .preview-icon-large {
  562. font-size: 64px;
  563. margin-bottom: 16px;
  564. opacity: 0.6;
  565. }
  566. p {
  567. margin: 0 0 16px 0;
  568. font-size: 16px;
  569. }
  570. .preview-download-btn {
  571. background: #3b82f6;
  572. color: white;
  573. border: none;
  574. padding: 10px 20px;
  575. border-radius: 6px;
  576. font-size: 14px;
  577. font-weight: 500;
  578. cursor: pointer;
  579. transition: all 0.2s ease;
  580. &:hover {
  581. background: #2563eb;
  582. }
  583. }
  584. }
  585. }
  586. .preview-footer {
  587. padding: 20px;
  588. border-top: 1px solid #e5e7eb;
  589. background-color: #f9fafb;
  590. .preview-meta {
  591. display: flex;
  592. gap: 16px;
  593. margin-bottom: 16px;
  594. font-size: 14px;
  595. color: #6b7280;
  596. flex-wrap: wrap;
  597. .source-badge {
  598. font-size: 12px;
  599. padding: 4px 8px;
  600. border-radius: 12px;
  601. font-weight: 500;
  602. &.source-wxwork {
  603. background-color: #dcfce7;
  604. color: #166534;
  605. }
  606. &.source-manual {
  607. background-color: #dbeafe;
  608. color: #1e40af;
  609. }
  610. &.source-default {
  611. background-color: #f3f4f6;
  612. color: #6b7280;
  613. }
  614. }
  615. }
  616. .preview-description {
  617. .description-textarea {
  618. width: 100%;
  619. min-height: 60px;
  620. padding: 12px;
  621. border: 1px solid #e5e7eb;
  622. border-radius: 6px;
  623. font-size: 14px;
  624. font-family: inherit;
  625. resize: vertical;
  626. outline: none;
  627. transition: border-color 0.2s ease;
  628. &:focus {
  629. border-color: #3b82f6;
  630. box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
  631. }
  632. &::placeholder {
  633. color: #9ca3af;
  634. }
  635. }
  636. }
  637. }
  638. }
  639. @keyframes spin {
  640. 0% { transform: rotate(0deg); }
  641. 100% { transform: rotate(360deg); }
  642. }
  643. // 响应式设计
  644. @media (max-width: 768px) {
  645. .modal-overlay {
  646. padding: 0;
  647. }
  648. .modal-container {
  649. max-height: 100vh;
  650. border-radius: 0;
  651. }
  652. .modal-header {
  653. padding: 16px;
  654. flex-direction: column;
  655. gap: 16px;
  656. .header-left {
  657. .modal-title {
  658. font-size: 20px;
  659. }
  660. .file-stats {
  661. justify-content: center;
  662. gap: 12px;
  663. }
  664. }
  665. .header-right {
  666. width: 100%;
  667. flex-direction: column;
  668. gap: 12px;
  669. .search-box .search-input {
  670. width: 100%;
  671. }
  672. }
  673. }
  674. .modal-content {
  675. padding: 16px;
  676. }
  677. .files-grid {
  678. grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  679. gap: 16px;
  680. }
  681. .file-card {
  682. .file-info {
  683. padding: 12px;
  684. }
  685. .file-footer {
  686. flex-direction: column;
  687. gap: 8px;
  688. align-items: stretch;
  689. .uploader-info {
  690. justify-content: center;
  691. }
  692. .file-actions {
  693. justify-content: center;
  694. }
  695. }
  696. }
  697. .files-list {
  698. .file-list-item {
  699. padding: 12px;
  700. gap: 12px;
  701. .list-file-icon {
  702. width: 40px;
  703. height: 40px;
  704. }
  705. }
  706. }
  707. .preview-overlay {
  708. padding: 0;
  709. }
  710. .preview-container {
  711. max-width: 100vw;
  712. max-height: 100vh;
  713. border-radius: 0;
  714. }
  715. }
  716. @media (max-width: 480px) {
  717. .files-grid {
  718. grid-template-columns: 1fr;
  719. }
  720. .modal-header {
  721. .header-right {
  722. .view-toggle {
  723. justify-content: center;
  724. }
  725. .filter-select {
  726. width: 100%;
  727. }
  728. }
  729. }
  730. }
  731. .file-actions {
  732. display: flex;
  733. gap: 8px;
  734. margin-top: 8px;
  735. }
  736. .download-btn, .analyze-btn {
  737. padding: 6px 12px;
  738. border: none;
  739. border-radius: 4px;
  740. cursor: pointer;
  741. }
  742. .download-btn {
  743. background: #1976d2;
  744. color: #fff;
  745. }
  746. .analyze-btn {
  747. background: #6a1b9a;
  748. color: #fff;
  749. }