quotation-editor.component.scss 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841
  1. .quotation-editor {
  2. width: 100%;
  3. // 加载状态
  4. .loading-container {
  5. display: flex;
  6. flex-direction: column;
  7. align-items: center;
  8. justify-content: center;
  9. padding: 60px 24px;
  10. text-align: center;
  11. .spinner {
  12. margin-bottom: 16px;
  13. }
  14. p {
  15. color: var(--ion-color-medium);
  16. margin: 0;
  17. }
  18. }
  19. // 产品管理区域
  20. .product-management {
  21. margin-bottom: 20px;
  22. .product-header {
  23. display: flex;
  24. align-items: center;
  25. justify-content: space-between;
  26. padding: 16px 20px;
  27. background: var(--ion-color-light);
  28. border-radius: 12px;
  29. border: 1px solid var(--ion-color-light-shade);
  30. h3 {
  31. margin: 0;
  32. font-size: 18px;
  33. font-weight: 600;
  34. color: var(--ion-color-dark);
  35. }
  36. .product-actions {
  37. display: flex;
  38. gap: 12px;
  39. button {
  40. display: flex;
  41. align-items: center;
  42. gap: 8px;
  43. padding: 8px 16px;
  44. border-radius: 8px;
  45. font-size: 14px;
  46. font-weight: 500;
  47. transition: all 0.2s ease;
  48. .icon {
  49. width: 16px;
  50. height: 16px;
  51. }
  52. }
  53. }
  54. }
  55. }
  56. // 空状态
  57. .empty-state {
  58. text-align: center;
  59. padding: 48px 24px;
  60. color: var(--ion-color-medium);
  61. .empty-icon {
  62. width: 80px;
  63. height: 80px;
  64. margin: 0 auto 16px;
  65. opacity: 0.3;
  66. }
  67. .empty-message {
  68. font-size: 16px;
  69. font-weight: 500;
  70. margin: 0 0 8px;
  71. color: var(--ion-color-dark);
  72. }
  73. .empty-hint {
  74. font-size: 14px;
  75. margin: 0;
  76. }
  77. }
  78. // 工具栏
  79. .quotation-toolbar {
  80. display: flex;
  81. align-items: center;
  82. justify-content: space-between;
  83. padding: 12px 16px;
  84. background: var(--ion-color-light);
  85. border-radius: 8px;
  86. margin-bottom: 16px;
  87. .toolbar-title {
  88. font-size: 16px;
  89. font-weight: 600;
  90. margin: 0;
  91. color: var(--ion-color-dark);
  92. }
  93. .toolbar-right {
  94. display: flex;
  95. gap: 8px;
  96. }
  97. .btn-icon {
  98. padding: 6px;
  99. background: transparent;
  100. border: 1px solid var(--ion-color-medium);
  101. border-radius: 4px;
  102. cursor: pointer;
  103. transition: all 0.2s;
  104. &:hover {
  105. background: var(--ion-color-light-shade);
  106. border-color: var(--ion-color-primary);
  107. }
  108. .icon {
  109. width: 18px;
  110. height: 18px;
  111. color: var(--ion-color-medium-shade);
  112. }
  113. }
  114. }
  115. // 卡片视图
  116. .quotation-spaces {
  117. display: flex;
  118. flex-direction: column;
  119. gap: 16px;
  120. }
  121. .space-card {
  122. border: 1px solid var(--ion-color-light-shade);
  123. border-radius: 8px;
  124. background: white;
  125. overflow: hidden;
  126. transition: all 0.3s;
  127. &.expanded {
  128. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  129. .space-header {
  130. background: var(--ion-color-light);
  131. border-bottom: 1px solid var(--ion-color-light-shade);
  132. }
  133. .space-toggle .icon {
  134. transform: rotate(180deg);
  135. }
  136. }
  137. }
  138. .space-header {
  139. display: flex;
  140. align-items: center;
  141. justify-content: space-between;
  142. padding: 16px;
  143. cursor: pointer;
  144. transition: background 0.2s;
  145. &:hover {
  146. background: var(--ion-color-light-tint);
  147. }
  148. .space-info {
  149. flex: 1;
  150. }
  151. .space-name {
  152. font-size: 16px;
  153. font-weight: 600;
  154. margin: 0 0 4px;
  155. color: var(--ion-color-dark);
  156. }
  157. .space-subtotal {
  158. font-size: 14px;
  159. margin: 0;
  160. color: var(--ion-color-primary);
  161. font-weight: 500;
  162. }
  163. .space-toggle {
  164. .icon {
  165. width: 20px;
  166. height: 20px;
  167. color: var(--ion-color-medium);
  168. transition: transform 0.3s;
  169. }
  170. }
  171. }
  172. .space-content {
  173. padding: 16px;
  174. animation: slideDown 0.3s ease-out;
  175. }
  176. @keyframes slideDown {
  177. from {
  178. opacity: 0;
  179. transform: translateY(-10px);
  180. }
  181. to {
  182. opacity: 1;
  183. transform: translateY(0);
  184. }
  185. }
  186. // 工序网格
  187. .process-grid {
  188. display: grid;
  189. grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  190. gap: 12px;
  191. }
  192. .process-item {
  193. border: 1px solid var(--ion-color-light-shade);
  194. border-radius: 6px;
  195. padding: 12px;
  196. background: var(--ion-color-light-tint);
  197. transition: all 0.2s;
  198. &.enabled {
  199. border-color: var(--ion-color-primary);
  200. background: white;
  201. box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
  202. }
  203. .process-header {
  204. display: flex;
  205. align-items: center;
  206. gap: 8px;
  207. cursor: pointer;
  208. margin-bottom: 8px;
  209. .checkbox-wrapper {
  210. display: flex;
  211. align-items: center;
  212. .checkbox-input {
  213. display: none;
  214. &:checked + .checkbox-custom {
  215. background: var(--ion-color-primary);
  216. border-color: var(--ion-color-primary);
  217. &::after {
  218. opacity: 1;
  219. }
  220. }
  221. }
  222. .checkbox-custom {
  223. width: 18px;
  224. height: 18px;
  225. border: 2px solid var(--ion-color-medium);
  226. border-radius: 4px;
  227. position: relative;
  228. transition: all 0.2s;
  229. &::after {
  230. content: '';
  231. position: absolute;
  232. left: 4px;
  233. top: 1px;
  234. width: 5px;
  235. height: 9px;
  236. border: solid white;
  237. border-width: 0 2px 2px 0;
  238. transform: rotate(45deg);
  239. opacity: 0;
  240. transition: opacity 0.2s;
  241. }
  242. }
  243. }
  244. .badge {
  245. padding: 4px 12px;
  246. border-radius: 12px;
  247. font-size: 16px;
  248. font-weight: 700;
  249. background: white;
  250. &[data-color="primary"] {
  251. color: var(--ion-color-primary-tint);
  252. border: solid 1px var(--ion-color-primary-tint);
  253. }
  254. &[data-color="secondary"] {
  255. color: var(--ion-color-secondary-tint);
  256. border: solid 1px var(--ion-color-secondary-tint);
  257. }
  258. &[data-color="tertiary"] {
  259. color: var(--ion-color-tertiary-tint);
  260. border: solid 1px var(--ion-color-tertiary-tint);
  261. }
  262. &[data-color="success"] {
  263. color: var(--ion-color-success-tint);
  264. border: solid 1px var(--ion-color-success-tint);
  265. }
  266. }
  267. }
  268. .process-inputs {
  269. display: flex;
  270. flex-direction: column;
  271. gap: 8px;
  272. .input-group {
  273. display: flex;
  274. flex-direction: column;
  275. gap: 4px;
  276. .input-label {
  277. font-size: 12px;
  278. color: var(--ion-color-medium-shade);
  279. font-weight: 500;
  280. }
  281. .input-with-note {
  282. display: flex;
  283. align-items: center;
  284. gap: 4px;
  285. .input-field {
  286. flex: 1;
  287. padding: 6px 8px;
  288. border: 1px solid var(--ion-color-light-shade);
  289. border-radius: 4px;
  290. font-size: 14px;
  291. &:focus {
  292. outline: none;
  293. border-color: var(--ion-color-primary);
  294. }
  295. &:disabled {
  296. background: var(--ion-color-light);
  297. color: var(--ion-color-medium);
  298. }
  299. }
  300. .input-note {
  301. font-size: 12px;
  302. color: var(--ion-color-medium);
  303. white-space: nowrap;
  304. }
  305. }
  306. }
  307. .process-subtotal {
  308. padding: 6px 8px;
  309. background: var(--ion-color-light);
  310. border-radius: 4px;
  311. font-size: 13px;
  312. font-weight: 600;
  313. color: var(--ion-color-primary);
  314. text-align: right;
  315. }
  316. }
  317. }
  318. // 表格视图
  319. .quotation-table {
  320. display: flex;
  321. flex-direction: column;
  322. gap: 24px;
  323. }
  324. .table-section {
  325. border: 1px solid var(--ion-color-light-shade);
  326. border-radius: 8px;
  327. overflow: hidden;
  328. background: white;
  329. .table-header {
  330. display: flex;
  331. align-items: center;
  332. justify-content: space-between;
  333. padding: 12px 16px;
  334. background: var(--ion-color-light);
  335. border-bottom: 1px solid var(--ion-color-light-shade);
  336. .table-space-name {
  337. font-size: 16px;
  338. font-weight: 600;
  339. margin: 0;
  340. color: var(--ion-color-dark);
  341. }
  342. .table-space-subtotal {
  343. font-size: 14px;
  344. font-weight: 600;
  345. color: var(--ion-color-primary);
  346. }
  347. }
  348. }
  349. .process-table {
  350. width: 100%;
  351. border-collapse: collapse;
  352. thead {
  353. background: var(--ion-color-light-tint);
  354. th {
  355. padding: 10px 12px;
  356. text-align: left;
  357. font-size: 13px;
  358. font-weight: 600;
  359. color: var(--ion-color-medium-shade);
  360. border-bottom: 2px solid var(--ion-color-light-shade);
  361. &.col-checkbox {
  362. width: 40px;
  363. }
  364. &.col-process {
  365. width: auto;
  366. }
  367. &.col-price,
  368. &.col-quantity {
  369. width: 120px;
  370. }
  371. &.col-unit {
  372. width: 80px;
  373. }
  374. &.col-subtotal {
  375. width: 120px;
  376. text-align: right;
  377. }
  378. }
  379. }
  380. tbody {
  381. tr {
  382. border-bottom: 1px solid var(--ion-color-light-shade);
  383. transition: background 0.2s;
  384. &:hover {
  385. background: var(--ion-color-light-tint);
  386. }
  387. &.enabled {
  388. background: rgba(var(--ion-color-primary-rgb), 0.02);
  389. &:hover {
  390. background: rgba(var(--ion-color-primary-rgb), 0.05);
  391. }
  392. }
  393. td {
  394. padding: 12px;
  395. font-size: 14px;
  396. &.col-subtotal {
  397. text-align: right;
  398. }
  399. .checkbox-wrapper {
  400. display: flex;
  401. align-items: center;
  402. justify-content: center;
  403. .checkbox-input {
  404. display: none;
  405. &:checked + .checkbox-custom {
  406. background: var(--ion-color-primary);
  407. border-color: var(--ion-color-primary);
  408. &::after {
  409. opacity: 1;
  410. }
  411. }
  412. }
  413. .checkbox-custom {
  414. width: 18px;
  415. height: 18px;
  416. border: 2px solid var(--ion-color-medium);
  417. border-radius: 4px;
  418. position: relative;
  419. transition: all 0.2s;
  420. cursor: pointer;
  421. &::after {
  422. content: '';
  423. position: absolute;
  424. left: 4px;
  425. top: 1px;
  426. width: 5px;
  427. height: 9px;
  428. border: solid white;
  429. border-width: 0 2px 2px 0;
  430. transform: rotate(45deg);
  431. opacity: 0;
  432. transition: opacity 0.2s;
  433. }
  434. }
  435. }
  436. .table-input {
  437. width: 100%;
  438. padding: 6px 8px;
  439. border: 1px solid var(--ion-color-light-shade);
  440. border-radius: 4px;
  441. font-size: 14px;
  442. &:focus {
  443. outline: none;
  444. border-color: var(--ion-color-primary);
  445. }
  446. &:disabled {
  447. background: var(--ion-color-light);
  448. color: var(--ion-color-medium);
  449. }
  450. }
  451. .disabled-value {
  452. color: var(--ion-color-medium);
  453. }
  454. }
  455. }
  456. }
  457. }
  458. // 总价
  459. .quotation-total {
  460. display: flex;
  461. align-items: center;
  462. justify-content: space-between;
  463. padding: 16px 20px;
  464. background: linear-gradient(135deg, var(--ion-color-primary) 0%, var(--ion-color-primary-shade) 100%);
  465. border-radius: 8px;
  466. margin-top: 16px;
  467. .total-label {
  468. font-size: 16px;
  469. font-weight: 500;
  470. color: white;
  471. }
  472. .total-amount {
  473. font-size: 24px;
  474. font-weight: 700;
  475. color: white;
  476. }
  477. }
  478. // ============ 产品相关样式 ============
  479. // 产品卡片
  480. .quotation-products {
  481. .product-card {
  482. border: 1px solid var(--ion-color-light-shade);
  483. border-radius: 12px;
  484. margin-bottom: 16px;
  485. background: white;
  486. overflow: hidden;
  487. transition: all 0.3s ease;
  488. &.expanded {
  489. box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
  490. }
  491. .product-header {
  492. display: flex;
  493. align-items: center;
  494. justify-content: space-between;
  495. padding: 16px 20px;
  496. cursor: pointer;
  497. user-select: none;
  498. transition: background-color 0.2s;
  499. &:hover {
  500. background-color: var(--ion-color-light-tint);
  501. }
  502. .product-info {
  503. display: flex;
  504. align-items: center;
  505. gap: 16px;
  506. flex: 1;
  507. .product-title {
  508. display: flex;
  509. align-items: center;
  510. gap: 12px;
  511. .product-icon {
  512. width: 40px;
  513. height: 40px;
  514. display: flex;
  515. align-items: center;
  516. justify-content: center;
  517. background: var(--ion-color-primary-tint);
  518. border-radius: 10px;
  519. color: var(--ion-color-primary);
  520. font-size: 20px;
  521. }
  522. .product-details {
  523. .product-name {
  524. font-size: 18px;
  525. font-weight: 600;
  526. color: var(--ion-color-dark);
  527. margin: 0 0 4px;
  528. }
  529. .product-meta {
  530. display: flex;
  531. align-items: center;
  532. gap: 8px;
  533. .badge {
  534. font-size: 12px;
  535. padding: 2px 8px;
  536. border-radius: 12px;
  537. font-weight: 500;
  538. }
  539. .designer-name {
  540. font-size: 13px;
  541. color: var(--ion-color-medium);
  542. }
  543. }
  544. }
  545. }
  546. .product-pricing {
  547. text-align: right;
  548. .product-subtotal {
  549. font-size: 20px;
  550. font-weight: 700;
  551. color: var(--ion-color-primary);
  552. margin: 0 0 2px;
  553. }
  554. .percentage {
  555. font-size: 13px;
  556. color: var(--ion-color-medium);
  557. }
  558. }
  559. }
  560. .product-actions {
  561. display: flex;
  562. align-items: center;
  563. gap: 8px;
  564. .btn-icon {
  565. width: 32px;
  566. height: 32px;
  567. border-radius: 8px;
  568. border: none;
  569. background: var(--ion-color-light-tint);
  570. color: var(--ion-color-medium);
  571. cursor: pointer;
  572. transition: all 0.2s;
  573. &:hover {
  574. background: var(--ion-color-light-shade);
  575. color: var(--ion-color-dark);
  576. }
  577. &.danger:hover {
  578. background: var(--ion-color-danger-tint);
  579. color: var(--ion-color-danger);
  580. }
  581. .icon {
  582. width: 16px;
  583. height: 16px;
  584. }
  585. }
  586. .product-toggle {
  587. margin-left: 8px;
  588. color: var(--ion-color-medium);
  589. transition: transform 0.3s ease;
  590. .icon {
  591. width: 20px;
  592. height: 20px;
  593. }
  594. }
  595. }
  596. }
  597. .product-card.expanded .product-toggle {
  598. transform: rotate(180deg);
  599. }
  600. .product-content {
  601. border-top: 1px solid var(--ion-color-light-shade);
  602. animation: slideDown 0.3s ease-out;
  603. }
  604. .product-details-section {
  605. padding: 16px 20px;
  606. background: var(--ion-color-light-tint);
  607. border-bottom: 1px solid var(--ion-color-light-shade);
  608. .detail-item {
  609. display: flex;
  610. justify-content: space-between;
  611. align-items: center;
  612. margin-bottom: 8px;
  613. &:last-child {
  614. margin-bottom: 0;
  615. }
  616. .detail-label {
  617. font-size: 14px;
  618. color: var(--ion-color-medium);
  619. }
  620. .detail-value {
  621. font-size: 14px;
  622. font-weight: 500;
  623. color: var(--ion-color-dark);
  624. }
  625. }
  626. }
  627. }
  628. }
  629. // 报价汇总
  630. .quotation-summary {
  631. background: white;
  632. border: 1px solid var(--ion-color-light-shade);
  633. border-radius: 12px;
  634. padding: 20px;
  635. margin-top: 20px;
  636. .summary-header {
  637. display: flex;
  638. align-items: center;
  639. justify-content: space-between;
  640. margin-bottom: 16px;
  641. h4 {
  642. margin: 0;
  643. font-size: 18px;
  644. font-weight: 600;
  645. color: var(--ion-color-dark);
  646. }
  647. .breakdown-toggle {
  648. .btn-text {
  649. background: none;
  650. border: none;
  651. color: var(--ion-color-primary);
  652. font-size: 14px;
  653. cursor: pointer;
  654. padding: 4px 8px;
  655. border-radius: 4px;
  656. transition: background-color 0.2s;
  657. &:hover {
  658. background-color: var(--ion-color-primary-tint);
  659. }
  660. }
  661. }
  662. }
  663. // 内部执行分配区域
  664. .allocation-section {
  665. margin-top: 20px;
  666. padding-top: 20px;
  667. border-top: 1px solid var(--ion-color-light-shade);
  668. .allocation-header {
  669. display: flex;
  670. justify-content: space-between;
  671. align-items: center;
  672. margin-bottom: 16px;
  673. h4 {
  674. margin: 0;
  675. font-size: 16px;
  676. font-weight: 600;
  677. color: var(--ion-color-dark);
  678. }
  679. .btn-text {
  680. background: none;
  681. border: none;
  682. color: var(--ion-color-primary);
  683. font-size: 14px;
  684. cursor: pointer;
  685. padding: 4px 8px;
  686. border-radius: 4px;
  687. transition: background-color 0.2s;
  688. &:hover {
  689. background-color: var(--ion-color-primary-tint);
  690. }
  691. }
  692. }
  693. .allocation-list {
  694. display: flex;
  695. flex-direction: column;
  696. gap: 12px;
  697. margin-bottom: 16px;
  698. .allocation-item {
  699. display: flex;
  700. align-items: center;
  701. gap: 12px;
  702. padding: 16px;
  703. border-radius: 10px;
  704. border-left: 4px solid;
  705. background: var(--ion-color-light-tint);
  706. transition: all 0.2s ease;
  707. &:hover {
  708. transform: translateY(-2px);
  709. box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
  710. }
  711. &.modeling {
  712. border-left-color: #8B5CF6; // 紫色 - 建模
  713. background: rgba(139, 92, 246, 0.05);
  714. .allocation-icon {
  715. background: rgba(139, 92, 246, 0.1);
  716. color: #8B5CF6;
  717. }
  718. }
  719. &.decoration {
  720. border-left-color: #F59E0B; // 橙色 - 软装渲染
  721. background: rgba(245, 158, 11, 0.05);
  722. .allocation-icon {
  723. background: rgba(245, 158, 11, 0.1);
  724. color: #F59E0B;
  725. }
  726. }
  727. &.company {
  728. border-left-color: #10B981; // 绿色 - 公司分配
  729. background: rgba(16, 185, 129, 0.05);
  730. .allocation-icon {
  731. background: rgba(16, 185, 129, 0.1);
  732. color: #10B981;
  733. }
  734. }
  735. .allocation-icon {
  736. width: 48px;
  737. height: 48px;
  738. display: flex;
  739. align-items: center;
  740. justify-content: center;
  741. border-radius: 10px;
  742. flex-shrink: 0;
  743. .icon {
  744. width: 24px;
  745. height: 24px;
  746. }
  747. }
  748. .allocation-info {
  749. flex: 1;
  750. display: flex;
  751. flex-direction: column;
  752. gap: 4px;
  753. .allocation-name {
  754. font-size: 15px;
  755. font-weight: 600;
  756. color: var(--ion-color-dark);
  757. line-height: 1.2;
  758. }
  759. .allocation-desc {
  760. font-size: 12px;
  761. color: var(--ion-color-medium);
  762. line-height: 1.3;
  763. }
  764. }
  765. .allocation-values {
  766. display: flex;
  767. flex-direction: column;
  768. align-items: flex-end;
  769. gap: 2px;
  770. .allocation-percentage {
  771. font-size: 13px;
  772. font-weight: 500;
  773. color: var(--ion-color-medium-shade);
  774. background: rgba(0, 0, 0, 0.04);
  775. padding: 2px 8px;
  776. border-radius: 12px;
  777. min-width: 45px;
  778. text-align: center;
  779. }
  780. .allocation-amount {
  781. font-size: 20px;
  782. font-weight: 700;
  783. color: var(--ion-color-dark);
  784. line-height: 1.2;
  785. }
  786. }
  787. }
  788. }
  789. .allocation-note {
  790. display: flex;
  791. align-items: flex-start;
  792. gap: 10px;
  793. padding: 12px 16px;
  794. background: rgba(56, 128, 255, 0.08);
  795. border-radius: 8px;
  796. border-left: 3px solid var(--ion-color-primary);
  797. .icon {
  798. width: 18px;
  799. height: 18px;
  800. color: var(--ion-color-primary);
  801. flex-shrink: 0;
  802. margin-top: 2px;
  803. }
  804. span {
  805. flex: 1;
  806. font-size: 13px;
  807. color: var(--ion-color-medium-shade);
  808. line-height: 1.5;
  809. }
  810. }
  811. }
  812. .breakdown-list {
  813. margin-bottom: 16px;
  814. .breakdown-item {
  815. display: flex;
  816. justify-content: space-between;
  817. align-items: center;
  818. padding: 8px 0;
  819. border-bottom: 1px solid var(--ion-color-light-tint);
  820. &:last-child {
  821. border-bottom: none;
  822. }
  823. .breakdown-name {
  824. flex: 1;
  825. font-size: 14px;
  826. color: var(--ion-color-dark);
  827. }
  828. .breakdown-amount {
  829. font-size: 15px;
  830. font-weight: 600;
  831. color: var(--ion-color-dark);
  832. margin: 0 16px;
  833. }
  834. .breakdown-percentage {
  835. font-size: 13px;
  836. color: var(--ion-color-medium);
  837. min-width: 50px;
  838. text-align: right;
  839. }
  840. }
  841. }
  842. .total-section {
  843. .total-row {
  844. display: flex;
  845. justify-content: space-between;
  846. align-items: center;
  847. padding: 16px 0;
  848. border-top: 2px solid var(--ion-color-primary);
  849. background: linear-gradient(135deg, var(--ion-color-primary) 0%, var(--ion-color-primary-shade) 100%);
  850. margin: 0 -20px 0px;
  851. padding: 16px 20px;
  852. .total-label {
  853. font-size: 16px;
  854. font-weight: 500;
  855. color: white;
  856. }
  857. .total-amount {
  858. font-size: 24px;
  859. font-weight: 700;
  860. color: white;
  861. }
  862. }
  863. .total-meta {
  864. display: flex;
  865. justify-content: space-between;
  866. align-items: center;
  867. margin-top: 8px;
  868. font-size: 12px;
  869. color: var(--ion-color-medium);
  870. .generate-info,
  871. .valid-info {
  872. display: flex;
  873. align-items: center;
  874. gap: 4px;
  875. }
  876. }
  877. }
  878. }
  879. // 兼容性 - 保持原有space类名
  880. .quotation-spaces {
  881. @extend .quotation-products;
  882. }
  883. .space-card {
  884. @extend .product-card;
  885. }
  886. .space-header {
  887. @extend .product-header;
  888. }
  889. .space-content {
  890. @extend .product-content;
  891. }
  892. // 移动端适配
  893. @media (max-width: 768px) {
  894. .allocation-section {
  895. .allocation-list {
  896. .allocation-item {
  897. flex-wrap: nowrap;
  898. padding: 14px;
  899. .allocation-icon {
  900. width: 40px;
  901. height: 40px;
  902. .icon {
  903. width: 20px;
  904. height: 20px;
  905. }
  906. }
  907. .allocation-info {
  908. flex: 1;
  909. min-width: 120px;
  910. .allocation-name {
  911. font-size: 14px;
  912. }
  913. .allocation-desc {
  914. font-size: 11px;
  915. }
  916. }
  917. .allocation-values {
  918. width: 100%;
  919. flex-direction: row;
  920. justify-content: space-between;
  921. align-items: center;
  922. margin-top: 8px;
  923. padding-top: 8px;
  924. border-top: 1px solid rgba(0, 0, 0, 0.06);
  925. .allocation-percentage {
  926. font-size: 12px;
  927. }
  928. .allocation-amount {
  929. font-size: 18px;
  930. }
  931. }
  932. }
  933. }
  934. .allocation-note {
  935. padding: 10px 12px;
  936. .icon {
  937. width: 16px;
  938. height: 16px;
  939. }
  940. span {
  941. font-size: 12px;
  942. }
  943. }
  944. }
  945. .product-content .process-grid {
  946. grid-template-columns: 1fr;
  947. }
  948. }
  949. }
  950. // ============ 模态框样式 ============
  951. .modal-overlay {
  952. position: fixed;
  953. top: 0;
  954. left: 0;
  955. right: 0;
  956. bottom: 0;
  957. background: rgba(0, 0, 0, 0.6);
  958. backdrop-filter: blur(4px);
  959. display: flex;
  960. align-items: center;
  961. justify-content: center;
  962. z-index: 10000;
  963. padding: 20px;
  964. animation: fadeIn 0.2s ease-out;
  965. }
  966. @keyframes fadeIn {
  967. from {
  968. opacity: 0;
  969. }
  970. to {
  971. opacity: 1;
  972. }
  973. }
  974. .modal-container {
  975. background: white;
  976. border-radius: 16px;
  977. box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
  978. max-width: 600px;
  979. width: 100%;
  980. max-height: 90vh;
  981. display: flex;
  982. flex-direction: column;
  983. animation: slideUp 0.3s ease-out;
  984. }
  985. @keyframes slideUp {
  986. from {
  987. opacity: 0;
  988. transform: translateY(20px);
  989. }
  990. to {
  991. opacity: 1;
  992. transform: translateY(0);
  993. }
  994. }
  995. .modal-header {
  996. display: flex;
  997. align-items: center;
  998. justify-content: space-between;
  999. padding: 20px 24px;
  1000. border-bottom: 1px solid #e5e7eb;
  1001. h3 {
  1002. margin: 0;
  1003. font-size: 20px;
  1004. font-weight: 600;
  1005. color: #111827;
  1006. }
  1007. .close-btn {
  1008. width: 32px;
  1009. height: 32px;
  1010. border-radius: 8px;
  1011. border: none;
  1012. background: transparent;
  1013. cursor: pointer;
  1014. display: flex;
  1015. align-items: center;
  1016. justify-content: center;
  1017. transition: all 0.2s ease;
  1018. color: #6b7280;
  1019. &:hover {
  1020. background: #f3f4f6;
  1021. color: #111827;
  1022. }
  1023. &:active {
  1024. transform: scale(0.95);
  1025. }
  1026. .icon {
  1027. width: 20px;
  1028. height: 20px;
  1029. }
  1030. }
  1031. }
  1032. .modal-body {
  1033. flex: 1;
  1034. overflow-y: auto;
  1035. padding: 24px;
  1036. &::-webkit-scrollbar {
  1037. width: 8px;
  1038. }
  1039. &::-webkit-scrollbar-track {
  1040. background: #f3f4f6;
  1041. border-radius: 4px;
  1042. }
  1043. &::-webkit-scrollbar-thumb {
  1044. background: #d1d5db;
  1045. border-radius: 4px;
  1046. &:hover {
  1047. background: #9ca3af;
  1048. }
  1049. }
  1050. }
  1051. .modal-footer {
  1052. display: flex;
  1053. align-items: center;
  1054. justify-content: flex-end;
  1055. gap: 12px;
  1056. padding: 16px 24px;
  1057. border-top: 1px solid #e5e7eb;
  1058. button {
  1059. padding: 10px 20px;
  1060. border-radius: 8px;
  1061. font-size: 14px;
  1062. font-weight: 500;
  1063. cursor: pointer;
  1064. transition: all 0.2s ease;
  1065. border: none;
  1066. &.btn-secondary {
  1067. background: #f3f4f6;
  1068. color: #374151;
  1069. &:hover {
  1070. background: #e5e7eb;
  1071. }
  1072. }
  1073. &.btn-primary {
  1074. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1075. color: white;
  1076. &:hover:not(:disabled) {
  1077. transform: translateY(-1px);
  1078. box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
  1079. }
  1080. &:disabled {
  1081. opacity: 0.5;
  1082. cursor: not-allowed;
  1083. }
  1084. }
  1085. &:active:not(:disabled) {
  1086. transform: scale(0.98);
  1087. }
  1088. }
  1089. }
  1090. // ============ 表单样式 ============
  1091. .form-group {
  1092. margin-bottom: 20px;
  1093. .form-label {
  1094. display: block;
  1095. margin-bottom: 8px;
  1096. font-size: 14px;
  1097. font-weight: 500;
  1098. color: #374151;
  1099. }
  1100. .form-input,
  1101. .form-select {
  1102. width: 100%;
  1103. padding: 10px 14px;
  1104. border: 1.5px solid #e5e7eb;
  1105. border-radius: 8px;
  1106. font-size: 14px;
  1107. color: #111827;
  1108. transition: all 0.2s ease;
  1109. outline: none;
  1110. background: white;
  1111. &:focus {
  1112. border-color: #667eea;
  1113. box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
  1114. }
  1115. &::placeholder {
  1116. color: #9ca3af;
  1117. }
  1118. }
  1119. .form-select {
  1120. cursor: pointer;
  1121. }
  1122. .input-with-hint {
  1123. .input-hint {
  1124. display: block;
  1125. margin-top: 6px;
  1126. font-size: 12px;
  1127. color: #6b7280;
  1128. }
  1129. }
  1130. .checkbox-label {
  1131. display: flex;
  1132. align-items: center;
  1133. gap: 10px;
  1134. cursor: pointer;
  1135. padding: 12px;
  1136. border-radius: 8px;
  1137. transition: background 0.2s ease;
  1138. &:hover {
  1139. background: #f9fafb;
  1140. }
  1141. input[type="checkbox"] {
  1142. width: 18px;
  1143. height: 18px;
  1144. cursor: pointer;
  1145. accent-color: #667eea;
  1146. }
  1147. span {
  1148. font-size: 14px;
  1149. color: #374151;
  1150. user-select: none;
  1151. }
  1152. }
  1153. .radio-group {
  1154. display: flex;
  1155. gap: 12px;
  1156. flex-wrap: wrap;
  1157. .radio-label {
  1158. display: flex;
  1159. align-items: center;
  1160. gap: 8px;
  1161. padding: 10px 16px;
  1162. border: 1.5px solid #e5e7eb;
  1163. border-radius: 8px;
  1164. cursor: pointer;
  1165. transition: all 0.2s ease;
  1166. background: white;
  1167. &:hover {
  1168. border-color: #667eea;
  1169. background: #f5f7ff;
  1170. }
  1171. input[type="radio"] {
  1172. cursor: pointer;
  1173. accent-color: #667eea;
  1174. }
  1175. span {
  1176. font-size: 14px;
  1177. color: #374151;
  1178. user-select: none;
  1179. }
  1180. &:has(input:checked) {
  1181. border-color: #667eea;
  1182. background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);
  1183. font-weight: 500;
  1184. }
  1185. }
  1186. }
  1187. }
  1188. // ============ 场景选择网格 ============
  1189. .scene-grid {
  1190. display: grid;
  1191. grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
  1192. gap: 12px;
  1193. .scene-card {
  1194. padding: 16px 12px;
  1195. border: 1.5px solid #e5e7eb;
  1196. border-radius: 10px;
  1197. background: white;
  1198. cursor: pointer;
  1199. transition: all 0.2s ease;
  1200. text-align: center;
  1201. display: flex;
  1202. flex-direction: column;
  1203. align-items: center;
  1204. justify-content: center;
  1205. gap: 8px;
  1206. &:hover {
  1207. border-color: #667eea;
  1208. background: #f5f7ff;
  1209. transform: translateY(-2px);
  1210. box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
  1211. }
  1212. &:active {
  1213. transform: translateY(0);
  1214. }
  1215. &.selected {
  1216. border-color: #667eea;
  1217. background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(118, 75, 162, 0.15) 100%);
  1218. box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
  1219. .scene-name {
  1220. color: #667eea;
  1221. font-weight: 600;
  1222. }
  1223. }
  1224. &.custom {
  1225. border-style: dashed;
  1226. border-color: #9ca3af;
  1227. color: #6b7280;
  1228. &:hover {
  1229. border-color: #667eea;
  1230. border-style: solid;
  1231. }
  1232. &.selected {
  1233. border-style: solid;
  1234. border-color: #667eea;
  1235. color: #667eea;
  1236. }
  1237. }
  1238. .scene-name {
  1239. font-size: 13px;
  1240. font-weight: 500;
  1241. color: #374151;
  1242. transition: all 0.2s ease;
  1243. }
  1244. }
  1245. }
  1246. // ============ 加价规则配置 ============
  1247. .pricing-adjustments {
  1248. margin-top: 24px;
  1249. padding: 20px;
  1250. background: linear-gradient(135deg, #f9fafb 0%, #f3f4f6 100%);
  1251. border-radius: 12px;
  1252. border: 1px solid #e5e7eb;
  1253. .section-title {
  1254. margin: 0 0 16px 0;
  1255. font-size: 15px;
  1256. font-weight: 600;
  1257. color: #374151;
  1258. }
  1259. .form-group {
  1260. margin-bottom: 16px;
  1261. &:last-child {
  1262. margin-bottom: 0;
  1263. }
  1264. }
  1265. }
  1266. // ============ 价格预览 ============
  1267. .price-preview {
  1268. margin-top: 24px;
  1269. padding: 20px;
  1270. background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
  1271. border-radius: 12px;
  1272. border: 2px solid #fbbf24;
  1273. .price-preview-row {
  1274. display: flex;
  1275. align-items: center;
  1276. justify-content: space-between;
  1277. padding: 8px 0;
  1278. font-size: 14px;
  1279. &.adjustment {
  1280. color: #f59e0b;
  1281. font-weight: 500;
  1282. .price {
  1283. color: #f59e0b;
  1284. }
  1285. }
  1286. &.total {
  1287. margin-top: 8px;
  1288. padding-top: 12px;
  1289. border-top: 2px solid rgba(251, 191, 36, 0.3);
  1290. font-size: 16px;
  1291. font-weight: 600;
  1292. .price {
  1293. font-size: 24px;
  1294. color: #d97706;
  1295. }
  1296. }
  1297. .label {
  1298. color: #92400e;
  1299. font-weight: 500;
  1300. }
  1301. .price {
  1302. font-weight: 600;
  1303. color: #92400e;
  1304. }
  1305. }
  1306. }
  1307. // ============ 内部分配小卡片 ============
  1308. .allocation-mini {
  1309. margin-top: 20px;
  1310. padding: 16px;
  1311. background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
  1312. border-radius: 10px;
  1313. border: 1px solid #86efac;
  1314. .section-title {
  1315. margin: 0 0 12px 0;
  1316. font-size: 14px;
  1317. font-weight: 600;
  1318. color: #166534;
  1319. }
  1320. .allocation-mini-grid {
  1321. display: grid;
  1322. grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  1323. gap: 10px;
  1324. .allocation-mini-item {
  1325. padding: 10px 12px;
  1326. background: white;
  1327. border-radius: 8px;
  1328. border-left: 3px solid;
  1329. display: flex;
  1330. flex-direction: column;
  1331. gap: 4px;
  1332. &.modeling {
  1333. border-left-color: #8b5cf6;
  1334. }
  1335. &.decoration {
  1336. border-left-color: #f59e0b;
  1337. }
  1338. &.company {
  1339. border-left-color: #10b981;
  1340. }
  1341. .label {
  1342. font-size: 11px;
  1343. color: #6b7280;
  1344. font-weight: 500;
  1345. }
  1346. .value {
  1347. font-size: 14px;
  1348. font-weight: 600;
  1349. color: #111827;
  1350. }
  1351. }
  1352. }
  1353. }
  1354. // ============ 分配明细网格样式 ============
  1355. .allocation-section-detail {
  1356. margin-top: 20px;
  1357. .section-title {
  1358. margin: 0 0 16px 0;
  1359. font-size: 16px;
  1360. font-weight: 600;
  1361. color: #111827;
  1362. .section-subtitle {
  1363. font-size: 13px;
  1364. font-weight: 400;
  1365. color: #6b7280;
  1366. margin-left: 8px;
  1367. }
  1368. }
  1369. .allocation-grid-detail {
  1370. display: flex;
  1371. flex-direction: column;
  1372. gap: 12px;
  1373. .allocation-item-detail {
  1374. border: 1.5px solid #e5e7eb;
  1375. border-radius: 10px;
  1376. padding: 14px 16px;
  1377. background: white;
  1378. transition: all 0.2s ease;
  1379. &:not(.enabled) {
  1380. opacity: 0.5;
  1381. background: #f9fafb;
  1382. }
  1383. &.enabled {
  1384. border-left-width: 4px;
  1385. }
  1386. &[data-type="modeling"].enabled {
  1387. border-left-color: #8b5cf6;
  1388. background: linear-gradient(90deg, rgba(139, 92, 246, 0.03) 0%, white 100%);
  1389. }
  1390. &[data-type="decoration"].enabled {
  1391. border-left-color: #f59e0b;
  1392. background: linear-gradient(90deg, rgba(245, 158, 11, 0.03) 0%, white 100%);
  1393. }
  1394. &[data-type="company"].enabled {
  1395. border-left-color: #10b981;
  1396. background: linear-gradient(90deg, rgba(16, 185, 129, 0.03) 0%, white 100%);
  1397. }
  1398. .allocation-header-detail {
  1399. display: flex;
  1400. align-items: center;
  1401. justify-content: space-between;
  1402. margin-bottom: 12px;
  1403. .allocation-left {
  1404. display: flex;
  1405. align-items: center;
  1406. gap: 12px;
  1407. flex: 1;
  1408. .checkbox-wrapper {
  1409. display: flex;
  1410. align-items: center;
  1411. .checkbox-input {
  1412. width: 18px;
  1413. height: 18px;
  1414. cursor: pointer;
  1415. accent-color: #667eea;
  1416. }
  1417. .checkbox-custom {
  1418. display: none;
  1419. }
  1420. }
  1421. .allocation-info-detail {
  1422. display: flex;
  1423. flex-direction: column;
  1424. gap: 4px;
  1425. .allocation-name-detail {
  1426. font-size: 15px;
  1427. font-weight: 600;
  1428. color: #111827;
  1429. }
  1430. .allocation-desc-detail {
  1431. font-size: 12px;
  1432. color: #6b7280;
  1433. }
  1434. }
  1435. }
  1436. .allocation-percentage-badge {
  1437. padding: 4px 12px;
  1438. background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  1439. color: white;
  1440. border-radius: 16px;
  1441. font-size: 13px;
  1442. font-weight: 600;
  1443. }
  1444. }
  1445. .allocation-input-section {
  1446. padding-left: 30px;
  1447. .input-label-small {
  1448. display: block;
  1449. margin-bottom: 8px;
  1450. font-size: 13px;
  1451. font-weight: 500;
  1452. color: #374151;
  1453. }
  1454. .input-with-currency {
  1455. position: relative;
  1456. display: flex;
  1457. align-items: center;
  1458. .currency-symbol {
  1459. position: absolute;
  1460. left: 14px;
  1461. font-size: 14px;
  1462. font-weight: 600;
  1463. color: #6b7280;
  1464. pointer-events: none;
  1465. }
  1466. .amount-input {
  1467. width: 100%;
  1468. padding: 10px 14px 10px 32px;
  1469. border: 1.5px solid #e5e7eb;
  1470. border-radius: 8px;
  1471. font-size: 16px;
  1472. font-weight: 600;
  1473. color: #111827;
  1474. transition: all 0.2s ease;
  1475. outline: none;
  1476. &:focus {
  1477. border-color: #667eea;
  1478. box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
  1479. }
  1480. &:disabled {
  1481. background: #f3f4f6;
  1482. cursor: not-allowed;
  1483. }
  1484. }
  1485. }
  1486. .allocation-hint {
  1487. margin-top: 6px;
  1488. font-size: 12px;
  1489. color: #6b7280;
  1490. padding-left: 2px;
  1491. }
  1492. }
  1493. }
  1494. }
  1495. }
  1496. // ============ 移动端适配(模态框) ============
  1497. @media (max-width: 768px) {
  1498. .modal-container {
  1499. max-width: none;
  1500. width: 100%;
  1501. max-height: 95vh;
  1502. margin: 0;
  1503. border-radius: 16px 16px 0 0;
  1504. }
  1505. .modal-header {
  1506. padding: 16px 20px;
  1507. h3 {
  1508. font-size: 18px;
  1509. }
  1510. }
  1511. .modal-body {
  1512. padding: 20px;
  1513. }
  1514. .modal-footer {
  1515. padding: 12px 20px;
  1516. button {
  1517. flex: 1;
  1518. padding: 12px;
  1519. }
  1520. }
  1521. .scene-grid {
  1522. grid-template-columns: repeat(3, 1fr);
  1523. gap: 10px;
  1524. .scene-card {
  1525. padding: 12px 8px;
  1526. .scene-name {
  1527. font-size: 12px;
  1528. }
  1529. }
  1530. }
  1531. .form-group .radio-group {
  1532. flex-direction: column;
  1533. .radio-label {
  1534. width: 100%;
  1535. }
  1536. }
  1537. .allocation-mini .allocation-mini-grid {
  1538. grid-template-columns: 1fr;
  1539. }
  1540. .price-preview {
  1541. padding: 16px;
  1542. .price-preview-row.total .price {
  1543. font-size: 20px;
  1544. }
  1545. }
  1546. }