index.vue 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406
  1. <template>
  2. <div class="background-content">
  3. <div class="row">
  4. <el-row>
  5. <el-col :span="11">
  6. <el-select
  7. v-model="background.fillType"
  8. @change="changeBackgroundType"
  9. >
  10. <el-option
  11. v-for="item in BackgroundFillMode"
  12. :key="item.id"
  13. :label="item.name"
  14. :value="item.id"
  15. ></el-option>
  16. </el-select>
  17. </el-col>
  18. <el-col :span="2"></el-col>
  19. <el-col :span="11" v-if="background.fillType === 0">
  20. <el-popover trigger="click" placement="bottom" :width="265">
  21. <template #reference>
  22. <ColorButton :color="background.color || '#fff'" />
  23. </template>
  24. <ColorPicker
  25. :modelValue="background.color"
  26. @update:modelValue="(color: string) => updateBackground({color: color, fill: color})"
  27. />
  28. </el-popover>
  29. </el-col>
  30. <el-col :span="11" v-else-if="background.fillType === 1">
  31. <el-select v-model="background.imageSize" @change="changeImageSize">
  32. <el-option
  33. v-for="item in BackgroundFillImageMode"
  34. :key="item.id"
  35. :label="item.name"
  36. :value="item.id"
  37. ></el-option>
  38. </el-select>
  39. </el-col>
  40. <el-col :span="11" v-else-if="background.fillType === 2">
  41. <el-select
  42. v-model="background.gradientType"
  43. @change="changeGradientType"
  44. >
  45. <el-option
  46. v-for="item in BackgroundFillGradientMode"
  47. :key="item.id"
  48. :value="item.value"
  49. :label="item.name"
  50. ></el-option>
  51. </el-select>
  52. </el-col>
  53. <el-col :span="11" v-else-if="background.fillType === 3">
  54. <el-select v-model="gridColorMode" @change="changeGridColorMode">
  55. <el-option
  56. v-for="item in BackgroundFillGridMode"
  57. :key="item.id"
  58. :label="item.name"
  59. :value="item.value"
  60. ></el-option>
  61. </el-select>
  62. </el-col>
  63. <el-col :span="11" v-else-if="background.fillType === 4">
  64. <el-button
  65. class="full-row"
  66. @click="generateShadingBackgroundRandom"
  67. >{{ $t("style.randomShape") }}</el-button
  68. >
  69. </el-col>
  70. </el-row>
  71. </div>
  72. <!-- 图片填充 -->
  73. <div v-if="background.fillType === 1">
  74. <FileInput @change="(files: FileList) => uploadBackgroundImage(files)">
  75. <div class="background-image">
  76. <div
  77. class="content"
  78. :style="{ backgroundImage: `url(${background.imageURL})` }"
  79. >
  80. <IconPlus />
  81. </div>
  82. </div>
  83. </FileInput>
  84. </div>
  85. <!-- 渐变填充 -->
  86. <div v-if="background.fillType === 2">
  87. <div class="background-gradient-body">
  88. <div
  89. class="gradient-content"
  90. v-for="(item, nameIndex) in GradientColorLibs"
  91. :key="nameIndex"
  92. :value="item.name"
  93. @click.stop="changeGradientName(item.name)"
  94. >
  95. <GradientFill
  96. :name="item.name"
  97. :type="background.gradientType"
  98. :colors="item.colors"
  99. ></GradientFill>
  100. </div>
  101. </div>
  102. <el-row>
  103. <el-col :span="7" class="slider-name"
  104. >{{ $t("style.opacity") }}:</el-col
  105. >
  106. <el-col :span="13">
  107. <el-slider
  108. class="common-slider"
  109. :min="0"
  110. :max="1"
  111. :step="0.01"
  112. v-model="gradientOpacity"
  113. @change="generateGradientBackground"
  114. />
  115. </el-col>
  116. <el-col :span="4" class="slider-num">{{ gradientOpacity }}</el-col>
  117. </el-row>
  118. <el-row v-if="background.gradientType === 'linear'">
  119. <el-col :span="7" class="slider-name"
  120. >{{ $t("style.gradientAngle") }}:</el-col
  121. >
  122. <el-col :span="13">
  123. <el-slider
  124. class="common-slider"
  125. :min="0"
  126. :max="360"
  127. :step="1"
  128. v-model="gradientRotate"
  129. @change="generateGradientBackground"
  130. />
  131. </el-col>
  132. <el-col :span="4" class="slider-num">{{ gradientRotate }}</el-col>
  133. </el-row>
  134. <el-row class="mb-10" v-if="background.gradientType === 'linear'">
  135. <el-col :span="7" class="slider-name"
  136. >{{ $t("style.horizontalPosition") }}:</el-col
  137. >
  138. <el-col :span="13">
  139. <el-slider
  140. class="common-slider"
  141. :min="0"
  142. :max="1"
  143. :step="0.01"
  144. v-model="gradientOffsetX"
  145. @change="generateGradientBackground"
  146. />
  147. </el-col>
  148. <el-col :span="4" class="slider-num">{{ gradientOffsetX }}</el-col>
  149. </el-row>
  150. <el-row class="mb-10" v-else>
  151. <el-col :span="7" class="slider-name"
  152. >{{ $t("style.verticalPosition") }}:</el-col
  153. >
  154. <el-col :span="13">
  155. <el-slider
  156. class="common-slider"
  157. :min="0"
  158. :max="1"
  159. :step="0.01"
  160. v-model="gradientOffsetY"
  161. @change="generateGradientBackground"
  162. />
  163. </el-col>
  164. <el-col :span="4" class="slider-num">{{ gradientOffsetY }}</el-col>
  165. </el-row>
  166. <div class="row">
  167. <div
  168. v-for="(item, index) in background.gradientColor"
  169. :key="index"
  170. class="gradient-box"
  171. >
  172. <el-popover trigger="click" width="265">
  173. <template #reference>
  174. <ColorButton :color="item.color || '#fff'" />
  175. </template>
  176. <ColorPicker
  177. :modelValue="item.color"
  178. @update:modelValue="(color: string) => updateGradientBackground(index, color)"
  179. />
  180. </el-popover>
  181. </div>
  182. </div>
  183. </div>
  184. <!-- 网格填充 -->
  185. <div class="mb-10" v-if="background.fillType === 3">
  186. <el-row>
  187. <el-col :span="4" class="slider-name"
  188. >{{ $t("style.strength") }}:</el-col
  189. >
  190. <el-col :span="16">
  191. <el-slider
  192. class="common-slider"
  193. :min="0"
  194. :max="1"
  195. :step="0.01"
  196. v-model="gridStrengthRef"
  197. @change="changeGridStrength"
  198. />
  199. </el-col>
  200. <el-col :span="4" class="slider-num">{{ gridStrengthRef }}</el-col>
  201. </el-row>
  202. <el-row>
  203. <el-col :span="4" class="slider-name"
  204. >{{ $t("style.variance") }}:</el-col
  205. >
  206. <el-col :span="16">
  207. <el-slider
  208. class="common-slider"
  209. :min="0"
  210. :max="1"
  211. :step="0.01"
  212. v-model="gridVarianceRef"
  213. @change="changeGridVariance"
  214. />
  215. </el-col>
  216. <el-col :span="4" class="slider-num">{{ gridVarianceRef }}</el-col>
  217. </el-row>
  218. <el-row class="mb-10">
  219. <el-col :span="4" class="slider-name">{{ $t("style.size") }}:</el-col>
  220. <el-col :span="16">
  221. <el-slider
  222. class="common-slider"
  223. :min="0.1"
  224. :max="0.25"
  225. :step="0.01"
  226. v-model="gridSizeRef"
  227. @change="changeGridSize"
  228. />
  229. </el-col>
  230. <el-col :span="4" class="slider-num">{{ gridSizeRef }}</el-col>
  231. </el-row>
  232. <el-row class="mb-10">
  233. <el-button class="full-row" @click="generateGridBackgroundRandom">{{
  234. $t("style.randomGeneration")
  235. }}</el-button>
  236. </el-row>
  237. <el-row class="mb-10">
  238. <el-radio-group class="full-ratio" v-model="isGridLibData">
  239. <el-radio-button :label="true">{{
  240. $t("style.colorSelect")
  241. }}</el-radio-button>
  242. <el-radio-button :label="false">{{
  243. $t("style.customize")
  244. }}</el-radio-button>
  245. </el-radio-group>
  246. </el-row>
  247. <el-row>
  248. <el-button
  249. class="full-row"
  250. v-if="isGridLibData"
  251. @click="generateGridBackgroundRandColor"
  252. >
  253. <IconShuffleOne />
  254. </el-button>
  255. <el-button class="full-row" v-else @click="showGridColorSelf">
  256. <IconPlus />
  257. </el-button>
  258. </el-row>
  259. <div class="mt-10" v-if="isGridLibData">
  260. <div
  261. class="row color-contianer"
  262. v-for="(item, index) in GridColorLibs"
  263. :key="index"
  264. >
  265. <div
  266. v-for="color in item.color"
  267. :key="color"
  268. class="color-box"
  269. :style="{ backgroundColor: color }"
  270. @click="changeGridColor(item.color)"
  271. ></div>
  272. </div>
  273. </div>
  274. <div class="mt-10" v-else>
  275. <div
  276. :class="[item.length > 0 ? 'row' : '', 'color-contianer']"
  277. v-for="(item, index) in gridColorRecent"
  278. :key="index"
  279. >
  280. <div
  281. v-for="color in item"
  282. :key="color"
  283. class="color-box"
  284. :style="{ backgroundColor: color }"
  285. @click="changeGridColor(item)"
  286. ></div>
  287. </div>
  288. </div>
  289. </div>
  290. <!-- 底纹填充 -->
  291. <div class="mb-10" v-if="background.fillType === 4">
  292. <el-row>
  293. <el-col :span="7" class="slider-name"
  294. >{{ $t("style.graphScale") }}:</el-col
  295. >
  296. <el-col :span="13">
  297. <el-slider
  298. class="common-slider"
  299. :min="1"
  300. :max="shadingColorLib.maxScale"
  301. :step="1"
  302. v-model="shadingBackground.scale"
  303. @change="changeShadingZoom"
  304. />
  305. </el-col>
  306. <el-col :span="4" class="slider-num">{{
  307. shadingBackground.scale
  308. }}</el-col>
  309. </el-row>
  310. <el-row>
  311. <el-col :span="7" class="slider-name"
  312. >{{ $t("style.horizontalPosition") }}:</el-col
  313. >
  314. <el-col :span="13">
  315. <el-slider
  316. class="common-slider"
  317. :min="0"
  318. :max="shadingColorLib.width * 2"
  319. :step="1"
  320. v-model="shadingBackground.moveLeft"
  321. @change="changeShadingHorizontal"
  322. />
  323. </el-col>
  324. <el-col :span="4" class="slider-num">{{
  325. shadingBackground.moveLeft
  326. }}</el-col>
  327. </el-row>
  328. <el-row>
  329. <el-col :span="7" class="slider-name"
  330. >{{ $t("style.verticalPosition") }}:</el-col
  331. >
  332. <el-col :span="13">
  333. <el-slider
  334. class="common-slider"
  335. :min="0"
  336. :max="shadingColorLib.height"
  337. :step="1"
  338. v-model="shadingBackground.moveTop"
  339. @change="changeShadingVertical"
  340. />
  341. </el-col>
  342. <el-col :span="4" class="slider-num">{{
  343. shadingBackground.moveTop
  344. }}</el-col>
  345. </el-row>
  346. <el-row
  347. v-if="
  348. shadingColorLib.mode === 'stroke-join' ||
  349. shadingColorLib.mode === 'stroke'
  350. "
  351. >
  352. <el-col :span="7" class="slider-name"
  353. >{{ $t("style.lineThickness") }}:</el-col
  354. >
  355. <el-col :span="13">
  356. <el-slider
  357. class="common-slider"
  358. :min="0.5"
  359. :max="shadingColorLib.maxStroke"
  360. :step="0.5"
  361. v-model="shadingBackground.stroke"
  362. @change="changeShadingStroke"
  363. />
  364. </el-col>
  365. <el-col :span="4" class="slider-num">{{
  366. shadingBackground.stroke
  367. }}</el-col>
  368. </el-row>
  369. <el-row v-if="shadingColorLib.maxSpacing[0] > 0">
  370. <el-col :span="7" class="slider-name"
  371. >{{ $t("style.verticalSpace") }}:</el-col
  372. >
  373. <el-col :span="13">
  374. <el-slider
  375. class="common-slider"
  376. :min="0"
  377. :max="shadingColorLib.maxSpacing[0]"
  378. :step="0.5"
  379. v-model="shadingBackground.spacing[0]"
  380. @change="changeShadingHSpacing"
  381. />
  382. </el-col>
  383. <el-col :span="4" class="slider-num">{{
  384. shadingBackground.spacing[0]
  385. }}</el-col>
  386. </el-row>
  387. <el-row v-if="shadingColorLib.maxSpacing[1] > 0">
  388. <el-col :span="7" class="slider-name"
  389. >{{ $t("style.horizontalSpace") }}:</el-col
  390. >
  391. <el-col :span="13">
  392. <el-slider
  393. class="common-slider"
  394. :min="0"
  395. :max="shadingColorLib.maxSpacing[1]"
  396. :step="0.5"
  397. v-model="shadingBackground.spacing[1]"
  398. @change="changeShadingVSpacing"
  399. />
  400. </el-col>
  401. <el-col :span="4" class="slider-num">{{
  402. shadingBackground.spacing[1]
  403. }}</el-col>
  404. </el-row>
  405. <el-row>
  406. <el-col :span="7" class="slider-name"
  407. >{{ $t("style.rotationAngle") }}:</el-col
  408. >
  409. <el-col :span="13">
  410. <el-slider
  411. class="common-slider"
  412. :min="0"
  413. :max="180"
  414. :step="1"
  415. v-model="shadingBackground.angle"
  416. @change="changeShadingAngle"
  417. />
  418. </el-col>
  419. <el-col :span="4" class="slider-num">{{
  420. shadingBackground.angle
  421. }}</el-col>
  422. </el-row>
  423. <el-row>
  424. <el-col :span="7" class="slider-name"
  425. >{{ $t("style.colorNumber") }}:</el-col
  426. >
  427. <el-col :span="13">
  428. <el-slider
  429. class="common-slider"
  430. :min="2"
  431. :max="shadingColorLib.colors"
  432. :step="1"
  433. v-model="shadingBackground.colorCounts"
  434. @change="changeShadingColors"
  435. />
  436. </el-col>
  437. <el-col :span="4" class="slider-num">{{
  438. shadingBackground.colorCounts
  439. }}</el-col>
  440. </el-row>
  441. <div class="row">
  442. <div
  443. v-for="(color, index) in shadingBackground.colors"
  444. :key="index"
  445. :class="
  446. index + 1 <= shadingBackground.colorCounts
  447. ? 'color-item'
  448. : 'color-non'
  449. "
  450. :style="{ backgroundColor: color }"
  451. >
  452. <el-popover trigger="click" placement="bottom" :width="265">
  453. <template #reference>
  454. <div class="color-select"></div>
  455. </template>
  456. <ColorPicker
  457. :modelValue="color"
  458. @update:modelValue="(color: string) => changeShadingIndexColor(index, color)"
  459. />
  460. </el-popover>
  461. </div>
  462. </div>
  463. <div class="background-shading-body">
  464. <div
  465. v-for="item in shadingColorLibs"
  466. :key="item.title"
  467. class="shading-box"
  468. :style="{
  469. backgroundImage: `url(&quot;${shadingSvgPattern(
  470. item.width,
  471. item.height,
  472. item.path,
  473. item.mode
  474. )}&quot;)`,
  475. }"
  476. @click="changeShadingElement(item)"
  477. >
  478. <!-- <span>{{item.title}}</span> -->
  479. </div>
  480. </div>
  481. </div>
  482. <GridFill
  483. v-model:visible="gridColorDialog"
  484. @close="hideGridColorSelf"
  485. @save="saveGridColorSelf"
  486. ></GridFill>
  487. </div>
  488. </template>
  489. <script lang="ts" setup>
  490. import { ref, computed, watch, onMounted } from "vue";
  491. import { useMainStore, useTemplatesStore } from "@/store";
  492. import { storeToRefs } from "pinia";
  493. import { debounce } from "lodash-es";
  494. import { Gradient, Pattern, Image, util } from "fabric";
  495. import {
  496. TransparentFill,
  497. BackgroundFillMode,
  498. BackgroundFillImageMode,
  499. BackgroundFillGridMode,
  500. BackgroundFillGradientMode,
  501. } from "@/configs/background";
  502. import { GridColorLibs } from "@/configs/colorGrid";
  503. import { GradientColorLibs } from "@/configs/colorGradient";
  504. import {
  505. ShadingLigntColors,
  506. ShadingColorLibInit,
  507. ShadingBackgroudInit,
  508. } from "@/configs/colorShading";
  509. import { GradientCoords } from "@/types/elements";
  510. import { ShadingBackground, ShadingColorLib } from "@/types/elements";
  511. import { WorkSpaceDrawType, propertiesToInclude } from "@/configs/canvas";
  512. import { ImageElement, WorkSpaceElement } from "@/types/canvas";
  513. import { getRandomNum } from "@/utils/common";
  514. import { getImageDataURL } from "@/utils/image";
  515. import { getColorShading } from "@/api/color";
  516. import trianglify from "@/plugins/trianglify/trianglify";
  517. import useCanvas from "@/views/Canvas/useCanvas";
  518. import GridFill from "./GridFill.vue";
  519. import GradientFill from "./GradientFill.vue";
  520. import useHandleBackground from "@/hooks/useHandleBackground";
  521. const templatesStore = useTemplatesStore();
  522. const { setBackgroudImage } = useHandleBackground();
  523. const { currentTemplate } = storeToRefs(templatesStore);
  524. // 渐变偏移
  525. const gradientOpacity = ref(1);
  526. const gradientRotate = ref(0);
  527. const gradientOffsetX = ref(0);
  528. const gradientOffsetY = ref(0);
  529. // 网格 预定义 参数
  530. const RECENT_GRIDS = "RECENT_GRIDS";
  531. const gridColorRecent = ref<[string[]]>([[]]);
  532. const isGridLibData = ref(true);
  533. const gridColorMode = ref<"interpolateLinear" | "sparkle" | "shadows">(
  534. "sparkle"
  535. );
  536. const gridSizeRef = ref(0.15);
  537. const gridColorsRef = ref<string[]>(GridColorLibs[0].color);
  538. const gridStrengthRef = ref(0.5);
  539. const gridVarianceRef = ref(0.5);
  540. const gridColorDialog = ref(false);
  541. const shadingColorLibs = ref<ShadingColorLib[]>([]);
  542. const shadingColorLib = ref<ShadingColorLib>(ShadingColorLibInit); // 底纹 预定义 参数
  543. const shadingBackground = ref<ShadingBackground>(ShadingBackgroudInit);
  544. // 加载缓存最近添加的网格
  545. onMounted(async () => {
  546. const recentGridCache = localStorage.getItem(RECENT_GRIDS);
  547. if (recentGridCache) gridColorRecent.value = JSON.parse(recentGridCache);
  548. // const res = await getColorShading();
  549. // if (res) {
  550. // shadingColorLibs.value = res.data;
  551. // shadingColorLib.value = shadingColorLibs.value[0];
  552. // }
  553. });
  554. const background = computed(() => {
  555. if (!currentTemplate.value) {
  556. return {
  557. fillType: 0,
  558. fill: TransparentFill,
  559. backgroundColor: "#fff",
  560. } as WorkSpaceElement;
  561. }
  562. if (!currentTemplate.value.workSpace) {
  563. return {
  564. fillType: 0,
  565. fill: TransparentFill,
  566. backgroundColor: "#fff",
  567. } as WorkSpaceElement;
  568. }
  569. return currentTemplate.value.workSpace;
  570. });
  571. // 设置背景图片隐藏
  572. const removeBackgroundElement = () => {
  573. const [canvas] = useCanvas();
  574. canvas.set("backgroundImage", null);
  575. canvas.renderAll();
  576. };
  577. // 设置背景模式:纯色,图片,渐变,网格,形状,智能
  578. const changeBackgroundType = (type: number) => {
  579. // 纯色
  580. if (type === 0) {
  581. const templateBackground: WorkSpaceElement = {
  582. ...background.value,
  583. fillType: type,
  584. fill: background.value.color || "#fff",
  585. };
  586. removeBackgroundElement();
  587. updateBackground(templateBackground);
  588. }
  589. // 图片
  590. else if (type === 1) {
  591. const templateBackground: WorkSpaceElement = {
  592. ...background.value,
  593. fillType: type,
  594. fill: "#fff",
  595. imageURL: background.value.imageURL || "",
  596. imageSize: background.value.imageSize || "cover",
  597. };
  598. removeBackgroundElement();
  599. updateBackground(templateBackground);
  600. if (background.value.imageURL) {
  601. changeBackgroundImage(background.value.imageURL);
  602. }
  603. }
  604. // 网格
  605. else if (type === 3) {
  606. const templateBackground: WorkSpaceElement = {
  607. ...background.value,
  608. fillType: type,
  609. backgroundColor: TransparentFill,
  610. gaidImageURL: background.value.gaidImageURL || "",
  611. };
  612. updateBackground(templateBackground);
  613. generateGridBackground();
  614. }
  615. // 底纹
  616. else if (type === 4) {
  617. const templateBackground: WorkSpaceElement = {
  618. ...background.value,
  619. fillType: type,
  620. backgroundColor: TransparentFill,
  621. shadingImageURL: background.value.shadingImageURL || "",
  622. };
  623. removeBackgroundElement();
  624. updateBackground(templateBackground);
  625. generateShadingBackground();
  626. }
  627. // 渐变
  628. else {
  629. const templateBackground: WorkSpaceElement = {
  630. ...background.value,
  631. fillType: 2,
  632. gradientType: background.value.gradientType || "linear",
  633. gradientColor:
  634. background.value.gradientColor || GradientColorLibs[0].colors,
  635. gradientName: background.value.gradientName || GradientColorLibs[0].name,
  636. };
  637. updateBackground(templateBackground);
  638. generateGradientBackground();
  639. }
  640. };
  641. // 设置背景
  642. const updateBackground = (props: Partial<WorkSpaceElement>) => {
  643. const [canvas] = useCanvas();
  644. const workSpaceDraw = canvas.getObjects().filter((item) => item.id === WorkSpaceDrawType)[0];
  645. if (!workSpaceDraw) return;
  646. workSpaceDraw.set({ ...props });
  647. if (props.fill instanceof Pattern) {
  648. props.fill = props.fill.toObject() as Pattern
  649. }
  650. templatesStore.updateWorkSpace({ workSpace: { ...background.value, ...props }});
  651. const workProps = workSpaceDraw.toObject(propertiesToInclude as any[]);
  652. templatesStore.updateElement({ id: workSpaceDraw.id, props: { ...workProps, ...props }});
  653. canvas.renderAll();
  654. };
  655. // 修改上传背景
  656. const changeBackgroundImage = async (imageURL: string) => {
  657. if (background.value.imageSize === "repeat") {
  658. const backgroundImage = await util.loadImage(imageURL);
  659. const workSpacePattern = new Pattern({
  660. source: backgroundImage,
  661. repeat: "repeat",
  662. });
  663. updateBackground({ fill: workSpacePattern, imageURL });
  664. } else {
  665. setBackgroudImage(imageURL);
  666. updateBackground({ fill: TransparentFill, imageURL });
  667. }
  668. };
  669. // 上传背景图片
  670. const uploadBackgroundImage = (files: any) => {
  671. // const imageFile = files[0];
  672. // if (!imageFile) return;
  673. // getImageDataURL(imageFile).then((imageURL) => {
  674. // changeBackgroundImage(imageURL);
  675. // });
  676. changeBackgroundImage(files.fileLink)
  677. };
  678. // 修改背景图片
  679. const changeImageSize = () => {
  680. if (!background.value.imageURL) return;
  681. changeBackgroundImage(background.value.imageURL);
  682. };
  683. // 修改渐变名字
  684. const changeGradientName = (gradientName: string) => {
  685. const gradientColorLib = GradientColorLibs.filter(
  686. (item) => item.name === gradientName
  687. )[0];
  688. if (gradientColorLib) {
  689. background.value.gradientName = gradientName;
  690. updateBackground({ gradientColor: gradientColorLib.colors });
  691. generateGradientBackground();
  692. }
  693. };
  694. // 修改渐变类型
  695. const changeGradientType = () => {
  696. updateBackground({ gradientType: background.value.gradientType });
  697. generateGradientBackground();
  698. };
  699. // 修改渐变颜色
  700. const updateGradientBackground = (index: number, color: string) => {
  701. const gradientBackgroundColor = background.value.gradientColor;
  702. if (gradientBackgroundColor) {
  703. gradientBackgroundColor[index].color = color;
  704. updateBackground({ gradientColor: gradientBackgroundColor });
  705. generateGradientBackground();
  706. }
  707. };
  708. // 生成渐变背景
  709. const generateGradientBackground = () => {
  710. const [canvas] = useCanvas();
  711. const workSpaceDraw = canvas
  712. .getObjects()
  713. .filter((item) => item.id === WorkSpaceDrawType)[0];
  714. if (!workSpaceDraw) return;
  715. const width = workSpaceDraw.width;
  716. const height = workSpaceDraw.height;
  717. if (!width || !height) return;
  718. let coords: GradientCoords = { x1: 0, y1: 0, x2: width, y2: 0 };
  719. if (background.value.gradientType !== "linear") {
  720. coords = {
  721. r1: 0,
  722. r2: height / 2,
  723. x1: width / 2,
  724. y1: height / 2,
  725. x2: width / 2,
  726. y2: height / 2,
  727. };
  728. }
  729. const rotateCos = Math.cos((gradientRotate.value * Math.PI) / 180.0);
  730. const rotateSin = Math.sin((gradientRotate.value * Math.PI) / 180.0);
  731. const gradient = new Gradient({
  732. type: background.value.gradientType,
  733. colorStops: background.value.gradientColor || GradientColorLibs[0].colors,
  734. coords: coords,
  735. offsetX: gradientOffsetX.value * width,
  736. offsetY: gradientOffsetY.value * height,
  737. gradientTransform: [rotateCos, rotateSin, -1 * rotateSin, rotateCos, 0, 0],
  738. });
  739. updateBackground({ fill: gradient, opacity: gradientOpacity.value });
  740. };
  741. // 更新缓存保存最大的网格
  742. const updateGridColorRecentCache = debounce(
  743. function () {
  744. const maxLength = 10;
  745. if (gridColorRecent.value.length > maxLength) {
  746. gridColorRecent.value = gridColorRecent.value.slice(0, maxLength) as [
  747. string[]
  748. ];
  749. }
  750. },
  751. 300,
  752. { trailing: true }
  753. );
  754. // 保存缓存最近添加的网格
  755. watch(
  756. gridColorRecent,
  757. () => {
  758. const recentGridCache = JSON.stringify(gridColorRecent.value);
  759. localStorage.setItem(RECENT_GRIDS, recentGridCache);
  760. },
  761. { deep: true }
  762. );
  763. // 修改网格图片强度
  764. const changeGridStrength = (value: number) => {
  765. gridStrengthRef.value = value;
  766. generateGridBackground();
  767. };
  768. // 修改网格图片方差
  769. const changeGridVariance = (value: number) => {
  770. gridVarianceRef.value = value;
  771. generateGridBackground();
  772. };
  773. // 修改网格图片尺寸
  774. const changeGridSize = (value: number) => {
  775. gridSizeRef.value = value;
  776. generateGridBackground();
  777. };
  778. // 随机数字生成网格
  779. const generateGridBackgroundRandom = () => {
  780. gridStrengthRef.value = Math.floor(getRandomNum(0, 1) * 100) / 100;
  781. gridVarianceRef.value = Math.floor(getRandomNum(0, 1) * 100) / 100;
  782. gridSizeRef.value = Math.floor(getRandomNum(0, 0.25) * 100) / 100;
  783. generateGridBackground();
  784. };
  785. // 随机颜色生成网格
  786. const generateGridBackgroundRandColor = () => {
  787. generateGridBackground("random");
  788. };
  789. // 显示网格自定义
  790. const showGridColorSelf = () => {
  791. gridColorDialog.value = true;
  792. };
  793. // 隐藏网格自定义
  794. const hideGridColorSelf = () => {
  795. gridColorDialog.value = false;
  796. };
  797. // 保存网格自定义
  798. const saveGridColorSelf = (colors: string[]) => {
  799. gridColorRecent.value.unshift(colors);
  800. updateGridColorRecentCache();
  801. };
  802. // 选择网格图片色彩
  803. const changeGridColor = (colors: string[]) => {
  804. gridColorsRef.value = colors;
  805. generateGridBackground();
  806. };
  807. const changeGridColorMode = (
  808. mode: "interpolateLinear" | "sparkle" | "shadows"
  809. ) => {
  810. gridColorMode.value = mode;
  811. generateGridBackground();
  812. };
  813. // 获取网格图片颜色模式
  814. const getGridColorFunction = () => {
  815. if (gridColorMode.value === "interpolateLinear") {
  816. return trianglify.colorFunctions.interpolateLinear(gridStrengthRef.value);
  817. } else if (gridColorMode.value === "sparkle") {
  818. return trianglify.colorFunctions.sparkle(gridStrengthRef.value);
  819. } else if (gridColorMode.value === "shadows") {
  820. return trianglify.colorFunctions.shadows(gridStrengthRef.value);
  821. }
  822. return trianglify.colorFunctions.sparkle(gridStrengthRef.value);
  823. };
  824. // 生成网格图片
  825. const generateGridBackground = async (status?: string) => {
  826. const [canvas] = useCanvas();
  827. const workSpaceDraw = canvas
  828. .getObjects()
  829. .filter((item) => item.id === WorkSpaceDrawType)[0];
  830. if (!workSpaceDraw || !workSpaceDraw.width) return;
  831. const gridColors =
  832. gridColorsRef.value && gridColorsRef.value.length > 0 && status !== "random"
  833. ? gridColorsRef.value
  834. : "random";
  835. const defaultOptions = {
  836. width: workSpaceDraw.width,
  837. height: workSpaceDraw.height,
  838. cellSize: gridSizeRef.value * workSpaceDraw.width,
  839. variance: gridVarianceRef.value,
  840. seed: null,
  841. xColors: gridColors,
  842. yColors: "match",
  843. fill: true,
  844. palette: trianglify.utils.colorbrewer,
  845. colorSpace: "lab",
  846. colorFunction: getGridColorFunction(),
  847. strokeWidth: 0,
  848. points: null,
  849. };
  850. const trianglifier = trianglify(defaultOptions);
  851. const canvasBackground = trianglifier.toSVG(undefined, undefined);
  852. const serialize = new XMLSerializer();
  853. const imageURL = `data:image/svg+xml;base64,${btoa(serialize.serializeToString(canvasBackground))}`;
  854. const backgroundImage = await Image.fromURL(imageURL, {crossOrigin: "anonymous"}, {
  855. left: workSpaceDraw.left,
  856. top: workSpaceDraw.top,
  857. angle: workSpaceDraw.angle,
  858. scaleX: workSpaceDraw.scaleX,
  859. scaleY: workSpaceDraw.scaleY,
  860. width: workSpaceDraw.width,
  861. height: workSpaceDraw.height,
  862. });
  863. canvas.set("backgroundImage", backgroundImage);
  864. templatesStore.setBackgroundImage(backgroundImage.toObject());
  865. updateBackground({ fill: TransparentFill, gaidImageURL: imageURL });
  866. };
  867. // 底纹样式读取
  868. const shadingSvgPattern = (
  869. width: number,
  870. height: number,
  871. path: string,
  872. mode: string
  873. ) => {
  874. let strokeGroup = "";
  875. for (let i = 0; i < path.split("~").length; i++) {
  876. const svgColor = ShadingLigntColors[i + 1];
  877. let strokeFill = `stroke-width='1' stroke='${svgColor}' fill='none'`;
  878. if (mode === "fill") strokeFill = `stroke='none' fill='${svgColor}'`;
  879. strokeGroup += path.split("~")[i].replace("/>", ` ${strokeFill}/>`);
  880. }
  881. const patternData =
  882. "<svg width='100%' height='100%' xmlns='http://www.w3.org/2000/svg'><defs>" +
  883. "<pattern id='a' patternUnits='userSpaceOnUse' width='" +
  884. width +
  885. "' height='" +
  886. height +
  887. "'><rect x='0' y='0' width='" +
  888. width +
  889. "' height='" +
  890. height +
  891. "' fill='" +
  892. ShadingLigntColors[0] +
  893. "'/>" +
  894. strokeGroup +
  895. "</pattern></defs><rect width='100%' height='100%' fill='url(%23a)'/></svg>";
  896. const svgShading = `data:image/svg+xml;base64,${btoa(patternData)}`;
  897. return svgShading;
  898. };
  899. // 多笔画底纹
  900. const multiStroke = (
  901. index: number,
  902. vHeight: number,
  903. maxColors: number,
  904. mode: string,
  905. path: string,
  906. item: ShadingBackground
  907. ) => {
  908. const colors = item.colors;
  909. const colorCounts = item.colorCounts;
  910. const join = item.join;
  911. const spacing = item.spacing;
  912. const stroke = item.stroke;
  913. let defColor = colors[index + 1];
  914. let strokeFill = "",
  915. joinMode = "";
  916. if (vHeight === 0 && maxColors > 2) {
  917. if (colorCounts === 3 && maxColors === 4 && index === 2)
  918. defColor = colors[1];
  919. else if (colorCounts === 4 && maxColors === 5 && index === 3)
  920. defColor = colors[1];
  921. else if (colorCounts === 3 && maxColors === 5 && index === 3)
  922. defColor = colors[1];
  923. else if (colorCounts === 3 && maxColors === 5 && index === 2)
  924. defColor = colors[1];
  925. else if (colorCounts === 2) defColor = colors[1];
  926. }
  927. if (mode === "stroke-join") {
  928. strokeFill = " stroke='" + defColor + "' fill='none'";
  929. joinMode =
  930. join === 2
  931. ? "stroke-linejoin='round' stroke-linecap='round' "
  932. : "stroke-linecap='square' ";
  933. } else if (mode === "stroke") {
  934. strokeFill = " stroke='" + defColor + "' fill='none'";
  935. } else {
  936. strokeFill = " stroke='none' fill='" + defColor + "'";
  937. }
  938. return path
  939. .split("~")
  940. [index].replace(
  941. "/>",
  942. " transform='translate(" +
  943. spacing[0] / 2 +
  944. ",0)' " +
  945. joinMode +
  946. "stroke-width='" +
  947. stroke +
  948. "'" +
  949. strokeFill +
  950. "/>"
  951. )
  952. .replace("transform='translate(0,0)' ", " ");
  953. };
  954. // 底纹样式背景生成
  955. const generateShadingBackground = async () => {
  956. const [canvas] = useCanvas();
  957. const workSpaceDraw = canvas
  958. .getObjects()
  959. .filter((item) => item.id === WorkSpaceDrawType)[0];
  960. if (!workSpaceDraw) return;
  961. const item = shadingColorLib.value;
  962. const maxColors = item.path.split("~").length + 1;
  963. const width = item.width;
  964. const height = item.height;
  965. const vHeight = item.vHeight;
  966. const path = item.path;
  967. const mode = item.mode;
  968. const svgWidth = width + shadingBackground.value.spacing[0];
  969. const svgHeight =
  970. height -
  971. vHeight * (maxColors - shadingBackground.value.colorCounts) +
  972. shadingBackground.value.spacing[1];
  973. const imageWidth = workSpaceDraw.width,
  974. imageHeight = workSpaceDraw.height;
  975. let strokeGroup = "";
  976. for (let i = 0; i < maxColors - 1; i++) {
  977. strokeGroup += multiStroke(
  978. i,
  979. vHeight,
  980. maxColors,
  981. mode,
  982. path,
  983. shadingBackground.value
  984. );
  985. }
  986. const translateX =
  987. shadingBackground.value.scale * shadingBackground.value.moveLeft;
  988. const translateY =
  989. shadingBackground.value.scale * shadingBackground.value.moveTop;
  990. const svg = `
  991. <svg id='patternId' width='${imageWidth}' height='${imageHeight}' xmlns='http://www.w3.org/2000/svg'>
  992. <defs>
  993. <pattern id='a' patternUnits='userSpaceOnUse'
  994. width='${svgWidth}'
  995. height='${svgHeight}'
  996. patternTransform='scale(${shadingBackground.value.scale}) rotate(${shadingBackground.value.angle})'
  997. >
  998. <rect x='0' y='0' width='100%' height='100%' fill='${shadingBackground.value.colors[0]}'/>
  999. ${strokeGroup}
  1000. </pattern>
  1001. </defs>
  1002. <rect x="0" y="0" width='${imageWidth}' height='${imageHeight}' transform='translate(${translateX},${translateY})' fill='url(%23a)' />
  1003. </svg>
  1004. `;
  1005. const imageURL = `data:image/svg+xml;base64,${btoa(svg)}`;
  1006. const backgroundImage = await Image.fromURL(imageURL, {crossOrigin: "anonymous"}, {});
  1007. const left = workSpaceDraw.left,
  1008. top = workSpaceDraw.top,
  1009. angle = workSpaceDraw.angle,
  1010. scaleX = workSpaceDraw.scaleX,
  1011. scaleY = workSpaceDraw.scaleY;
  1012. backgroundImage.set({
  1013. left,
  1014. top,
  1015. angle,
  1016. scaleX,
  1017. scaleY,
  1018. width: imageWidth,
  1019. height: imageHeight,
  1020. });
  1021. canvas.set("backgroundImage", backgroundImage);
  1022. updateBackground({ shadingImageURL: imageURL, fill: TransparentFill });
  1023. templatesStore.setBackgroundImage(backgroundImage.toObject());
  1024. };
  1025. // // 选择底纹填充
  1026. const changeShadingElement = (item: ShadingColorLib) => {
  1027. shadingColorLib.value = item;
  1028. shadingBackground.value.colorCounts = item.colors;
  1029. generateShadingBackground();
  1030. };
  1031. // 修改底纹缩放
  1032. const changeShadingZoom = (value: number) => {
  1033. shadingBackground.value.scale = value;
  1034. generateShadingBackground();
  1035. };
  1036. // 修改底纹水平位置
  1037. const changeShadingHorizontal = (value: number) => {
  1038. shadingBackground.value.moveLeft = value;
  1039. generateShadingBackground();
  1040. };
  1041. // 修改底纹垂直位置
  1042. const changeShadingVertical = (value: number) => {
  1043. shadingBackground.value.moveTop = value;
  1044. generateShadingBackground();
  1045. };
  1046. // 修改底纹线条粗细
  1047. const changeShadingStroke = (value: number) => {
  1048. shadingBackground.value.stroke = value;
  1049. generateShadingBackground();
  1050. };
  1051. // 修改底纹水平间隔
  1052. const changeShadingHSpacing = (value: number) => {
  1053. shadingBackground.value.spacing[0] = value;
  1054. generateShadingBackground();
  1055. };
  1056. // 修改底纹垂直间隔
  1057. const changeShadingVSpacing = (value: number) => {
  1058. shadingBackground.value.spacing[1] = value;
  1059. generateShadingBackground();
  1060. };
  1061. // 修改底纹填充旋转角度
  1062. const changeShadingAngle = (value: number) => {
  1063. shadingBackground.value.angle = value;
  1064. generateShadingBackground();
  1065. };
  1066. // 修改底纹填充颜色数量
  1067. const changeShadingColors = (value: number) => {
  1068. shadingBackground.value.colorCounts = value;
  1069. generateShadingBackground();
  1070. };
  1071. // 修改底纹填充颜色
  1072. const changeShadingIndexColor = (index: number, color: string) => {
  1073. // shadingBackground.value.colors[index] = color
  1074. generateShadingBackground();
  1075. };
  1076. // 随机底纹填充形状
  1077. const generateShadingBackgroundRandom = () => {
  1078. const item =
  1079. shadingColorLibs.value[
  1080. Math.floor(getRandomNum(0, shadingColorLibs.value.length - 1))
  1081. ];
  1082. shadingColorLib.value = item;
  1083. if (item.colors) shadingBackground.value.colorCounts = item.colors;
  1084. generateShadingBackground();
  1085. };
  1086. // 设置背景图片
  1087. // const generateBackgroundImage = async (backgroundImage: Image, url: string) => {
  1088. // const [ canvas ] = useCanvas()
  1089. // canvas.set('backgroundImage', backgroundImage)
  1090. // // if (canvasObject.value && canvasObject.value.name === 'backgroundImage') {
  1091. // // const imageElement = canvasObject.value as Image
  1092. // // await imageElement.setSrc(url)
  1093. // // }
  1094. // // else {
  1095. // // canvas.backgroundImage = backgroundImage
  1096. // // }
  1097. // }
  1098. </script>
  1099. <style lang="scss" scoped>
  1100. .icon-btn {
  1101. cursor: pointer;
  1102. }
  1103. .canvas-design-panel {
  1104. user-select: none;
  1105. }
  1106. .row {
  1107. width: 100%;
  1108. display: flex;
  1109. align-items: center;
  1110. margin-bottom: 10px;
  1111. }
  1112. .title {
  1113. margin-bottom: 10px;
  1114. }
  1115. .fixed-ratio {
  1116. display: flex;
  1117. flex-direction: column;
  1118. justify-content: center;
  1119. }
  1120. .slider-name {
  1121. display: flex;
  1122. align-items: center;
  1123. }
  1124. .slider-num {
  1125. display: flex;
  1126. align-items: center;
  1127. justify-content: center;
  1128. }
  1129. .mb-10 {
  1130. margin-bottom: 10px;
  1131. }
  1132. .full-row {
  1133. flex: 1;
  1134. width: 100%;
  1135. }
  1136. .full-group {
  1137. display: flex;
  1138. flex: 1;
  1139. .el-button {
  1140. width: 50%;
  1141. }
  1142. }
  1143. .full-ratio {
  1144. display: flex;
  1145. flex: 1;
  1146. .el-radio-button {
  1147. width: 50%;
  1148. }
  1149. .el-radio-button__inner {
  1150. width: 100%;
  1151. }
  1152. }
  1153. .background-image {
  1154. height: 0;
  1155. padding-bottom: 56.25%;
  1156. border: 1px dashed var(--el-border-color);
  1157. border-radius: $borderRadius;
  1158. position: relative;
  1159. transition: all $transitionDelay;
  1160. &:hover {
  1161. border-color: var(--el-color-primary);
  1162. color: var(--el-color-primary);
  1163. }
  1164. .content {
  1165. @include absolute-0();
  1166. display: flex;
  1167. justify-content: center;
  1168. align-items: center;
  1169. background-position: center;
  1170. background-size: contain;
  1171. background-repeat: no-repeat;
  1172. cursor: pointer;
  1173. }
  1174. }
  1175. .theme-list {
  1176. @include flex-grid-layout();
  1177. }
  1178. .theme-item {
  1179. @include flex-grid-layout-children(2, 48%);
  1180. padding-bottom: 30%;
  1181. border-radius: $borderRadius;
  1182. position: relative;
  1183. cursor: pointer;
  1184. .theme-item-content {
  1185. @include absolute-0();
  1186. display: flex;
  1187. flex-direction: column;
  1188. justify-content: center;
  1189. padding: 8px;
  1190. border: 1px solid $borderColor;
  1191. }
  1192. .text {
  1193. font-size: 16px;
  1194. }
  1195. .colors {
  1196. display: flex;
  1197. }
  1198. .color-block {
  1199. margin-top: 8px;
  1200. width: 12px;
  1201. height: 12px;
  1202. margin-right: 2px;
  1203. }
  1204. &:hover .btns {
  1205. display: flex;
  1206. }
  1207. .btns {
  1208. @include absolute-0();
  1209. flex-direction: column;
  1210. justify-content: center;
  1211. align-items: center;
  1212. display: none;
  1213. background-color: rgba($color: #000, $alpha: 0.25);
  1214. }
  1215. .btn {
  1216. width: 72px;
  1217. padding: 5px 0;
  1218. text-align: center;
  1219. background-color: $themeColor;
  1220. color: #fff;
  1221. font-size: 12px;
  1222. border-radius: $borderRadius;
  1223. &:hover {
  1224. background-color: #c42f19;
  1225. }
  1226. & + .btn {
  1227. margin-top: 5px;
  1228. }
  1229. }
  1230. }
  1231. .slider {
  1232. flex: 3;
  1233. }
  1234. .mt-10 {
  1235. margin-top: 10px;
  1236. }
  1237. .color-group {
  1238. display: flex;
  1239. flex: 1 1;
  1240. }
  1241. .color-box {
  1242. flex: 1 1;
  1243. height: 25px;
  1244. }
  1245. .color-contianer:hover {
  1246. box-shadow: 0 0 20px 2px rgb(0 0 0 / 40%);
  1247. width: calc(100% - 5px) !important;
  1248. cursor: pointer;
  1249. }
  1250. .config-strength {
  1251. flex: 10;
  1252. }
  1253. .config-variance {
  1254. flex: 10;
  1255. }
  1256. .config-size {
  1257. flex: 10;
  1258. }
  1259. .gradient-box {
  1260. display: flex;
  1261. flex: 1;
  1262. .el-button {
  1263. width: 100%;
  1264. }
  1265. }
  1266. .background-gradient-body {
  1267. height: 300px;
  1268. overflow: auto;
  1269. }
  1270. .gradient-content {
  1271. display: flex;
  1272. justify-content: center;
  1273. padding-bottom: 2px;
  1274. }
  1275. .gradient-content:hover {
  1276. width: calc(100% - 2px) !important;
  1277. border-color: $themeColor;
  1278. cursor: pointer;
  1279. }
  1280. .background-shading-body {
  1281. height: 500px;
  1282. overflow: auto;
  1283. }
  1284. .shading-box {
  1285. flex: 1;
  1286. height: 50px;
  1287. margin-bottom: 5px;
  1288. border: 1px solid transparent;
  1289. border-color: #d9d9d9;
  1290. border-radius: 5px;
  1291. }
  1292. .shading-box:hover {
  1293. // box-shadow: 0 0 20px 2px rgb(0 0 0 / 40%);
  1294. width: calc(100% - 2px) !important;
  1295. cursor: pointer;
  1296. border-color: $themeColor;
  1297. }
  1298. .color-item {
  1299. height: 42px;
  1300. border: 1px solid transparent;
  1301. border-color: #d9d9d9;
  1302. border-radius: 5px;
  1303. flex: 1;
  1304. display: inline-block;
  1305. cursor: pointer;
  1306. margin: 0 2px;
  1307. transition: transform 0.2s ease, box-shadow 0.2s ease;
  1308. }
  1309. .color-item:hover {
  1310. border-color: $themeColor;
  1311. }
  1312. .color-non {
  1313. display: none;
  1314. }
  1315. .color-select {
  1316. width: 100%;
  1317. height: 100%;
  1318. }
  1319. .common-slider {
  1320. width: 90%;
  1321. margin: 0 auto;
  1322. }
  1323. </style>
  1324. <style scoped>
  1325. :deep(.el-input .el-input-group__prepend) {
  1326. padding: 0 5px;
  1327. }
  1328. :deep(.el-input .el-input-group__append) {
  1329. padding: 0 5px;
  1330. }
  1331. :deep(.full-ratio .el-radio-button__inner) {
  1332. width: 100%;
  1333. }
  1334. </style>