PenProps.vue 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844
  1. <template>
  2. <div class="props">
  3. <t-tabs v-model="data.tab">
  4. <t-tab-panel :value="1" label="外观">
  5. <t-space direction="vertical" class="py-16 w-full">
  6. <div class="form-item px-12">
  7. <label style="width: 50px">ID</label>
  8. <t-input
  9. class="w-full"
  10. placeholder="ID"
  11. :value="data.pen.id"
  12. @change="changeID($event)"
  13. />
  14. </div>
  15. <div class="form-item px-12" style="margin-top: -12px">
  16. <label style="width: 50px">名称</label>
  17. <!-- <t-input
  18. class="w-full"
  19. placeholder="名称"
  20. disabled
  21. v-model.number="data.pen.name"
  22. @change="changeValue('name')"
  23. /> -->
  24. <div style="padding-left: 8px; line-height: 30px">
  25. {{ data.pen.name }}
  26. </div>
  27. </div>
  28. <div class="form-item px-12" style="margin-top: -12px">
  29. <label style="width: 50px">分组</label>
  30. <t-select-input
  31. v-model:inputValue="data.inputTag"
  32. :value="data.pen.tags"
  33. allow-input
  34. placeholder="请输入或选择分组"
  35. multiple
  36. @tag-change="onChangeInputTag"
  37. @focus="data.tagPopupVisible = true"
  38. @blur="data.tagPopupVisible = false"
  39. :tag-input-props="{ excessTagsDisplayType: 'break-line' }"
  40. >
  41. <template #panel>
  42. <ul style="padding: 8px 12px">
  43. <li
  44. v-for="item in data.groups"
  45. :key="item"
  46. @click="onSelectTag(item)"
  47. >
  48. {{ item }}
  49. </li>
  50. </ul>
  51. </template>
  52. </t-select-input>
  53. </div>
  54. <div v-if="isDom" class="form-item px-12" style="margin-top: -12px">
  55. <label style="width: 50px">z-index</label>
  56. <t-input-number
  57. v-model="data.pen.zIndex"
  58. theme="column"
  59. :min="0"
  60. placeholder="默认5"
  61. @change="changeValue('zIndex')"
  62. />
  63. </div>
  64. <div v-else class="form-item px-12" style="margin-top: -12px">
  65. <label style="width: 50px">画布层</label>
  66. <!-- <t-switch
  67. class="mt-8 ml-8"
  68. v-model="data.pen.template"
  69. size="small"
  70. @change="changeValue('template')"
  71. /> -->
  72. <t-select
  73. v-model="data.pen.canvasLayer"
  74. @change="changeValue('canvasLayer')"
  75. >
  76. <t-option :key="4" :disabled="data.pen.name!=='image'" :value="4" label="上层图片层"> 上层图片层 </t-option>
  77. <t-option :key="3" :value="3" label="主画布层"> 主画布层 </t-option>
  78. <t-option :key="2" :disabled="data.pen.name!=='image'" :value="2" label="下层图片层"> 下层图片层 </t-option>
  79. <t-option :key="1" :value="1" label="模板层"> 模板层 </t-option>
  80. </t-select>
  81. </div>
  82. <t-divider style="margin: -8px 0" />
  83. <div style="margin: 0 16px 16px 16px">
  84. <t-space direction="vertical" size="small" class="w-full">
  85. <div style="color: var(--color); margin-bottom: 2px">
  86. 大屏对齐
  87. </div>
  88. <div class="icons">
  89. <t-tooltip
  90. v-for="item in aligns"
  91. :content="item.label"
  92. placement="top"
  93. >
  94. <svg
  95. class="l-icon btn"
  96. aria-hidden="true"
  97. @click="align(item.value)"
  98. >
  99. <use :xlink:href="item.icon"></use>
  100. </svg>
  101. </t-tooltip>
  102. </div>
  103. </t-space>
  104. </div>
  105. <t-divider style="margin: -8px 0" />
  106. <div class="form-item" style="margin-top: -12px">
  107. <t-input
  108. class="ml-4"
  109. label="X"
  110. placeholder="X"
  111. v-model.number="data.rect.x"
  112. style="width: 80px"
  113. :format="decimalPlaces"
  114. @change="changeRectValue('x')"
  115. />
  116. <link-icon class="hidden ml-4"/>
  117. <!-- <t-icon name="link" class="hidden ml-4" /> -->
  118. <t-input
  119. class="ml-4"
  120. label="Y"
  121. placeholder="Y"
  122. v-model.number="data.rect.y"
  123. style="width: 80px"
  124. :format="decimalPlaces"
  125. @change="changeRectValue('y')"
  126. />
  127. <t-input
  128. class="ml-16"
  129. v-model.number="data.pen.rotate"
  130. placeholder="旋转"
  131. style="width: 80px"
  132. :format="decimalRound"
  133. @change="changeValue('rotate')"
  134. >
  135. <template #prefix-icon>
  136. <svg class="l-icon" aria-hidden="true">
  137. <use xlink:href="#l-rotate"></use>
  138. </svg>
  139. </template>
  140. </t-input>
  141. </div>
  142. <div class="form-item hover-icons" style="margin-top: -12px">
  143. <t-input
  144. class="ml-4"
  145. label="W"
  146. v-model.number="data.rect.width"
  147. placeholder="宽"
  148. min="1"
  149. style="width: 80px"
  150. :format="decimalPlaces"
  151. @change="changeRectValue('width')"
  152. />
  153. <t-tooltip v-if="data.pen.ratio" content="固定比例" placement="top">
  154. <link-icon
  155. class="ml-4 hover"
  156. @click="data.pen.ratio = !data.pen.ratio"/>
  157. <!-- <t-icon
  158. name="link"
  159. class="ml-4 hover"
  160. @click="data.pen.ratio = !data.pen.ratio"
  161. /> -->
  162. </t-tooltip>
  163. <t-tooltip v-else content="不固定比例" placement="top">
  164. <link-unlink-icon class="ml-4 hover icon"
  165. @click="data.pen.ratio = !data.pen.ratio"/>
  166. <!-- <t-icon
  167. name="link-unlink"
  168. class="ml-4 hover icon"
  169. @click="data.pen.ratio = !data.pen.ratio"
  170. /> -->
  171. </t-tooltip>
  172. <t-input
  173. class="ml-4"
  174. label="H"
  175. placeholder="高"
  176. v-model.number="data.rect.height"
  177. min="1"
  178. style="width: 80px"
  179. :format="decimalPlaces"
  180. @change="changeRectValue('height')"
  181. />
  182. <t-input
  183. class="ml-16"
  184. v-model.number="data.pen.borderRadius"
  185. placeholder="圆角"
  186. style="width: 80px"
  187. @change="changeValue('borderRadius')"
  188. >
  189. <template #prefix-icon>
  190. <svg class="l-icon" aria-hidden="true">
  191. <use xlink:href="#l-border-radius"></use>
  192. </svg>
  193. </template>
  194. </t-input>
  195. </div>
  196. <t-divider style="margin: -8px 0" />
  197. <div class="form-item px-16" style="margin-top: -12px">
  198. <label>透明度</label>
  199. <t-slider
  200. v-model="data.pen.globalAlpha"
  201. :min="0"
  202. :max="1"
  203. :step="0.01"
  204. @change="changeValue('globalAlpha')"
  205. />
  206. <span class="ml-16" style="width: 50px; line-height: 30px">
  207. {{ data.pen.globalAlpha }}
  208. </span>
  209. </div>
  210. <template
  211. v-if="
  212. data.pen.name === 'combine' && data.pen.showChild !== undefined
  213. "
  214. >
  215. <t-divider style="margin: -8px 0" />
  216. <div class="form-item px-16" style="margin-top: -12px">
  217. <label>状态</label>
  218. <t-select
  219. v-model="data.pen.showChild"
  220. placeholder="状态"
  221. @change="changeValue('showChild')"
  222. style="width: 150px"
  223. >
  224. <t-option
  225. v-for="(a, index) in data.pen.children"
  226. :key="index"
  227. :value="index"
  228. >
  229. 状态{{ index + 1 }}</t-option
  230. >
  231. </t-select>
  232. </div>
  233. </template>
  234. <t-collapse
  235. :defaultValue="['1', '2', '3', '4', '5']"
  236. expandIconPlacement="right"
  237. :borderless="true"
  238. >
  239. <t-collapse-panel
  240. v-if="data.pen.props.look !== false"
  241. value="1"
  242. header="外观"
  243. >
  244. <t-space direction="vertical" size="small" class="w-full">
  245. <div class="form-item">
  246. <t-color-picker
  247. class="simple mt-8 mr-4"
  248. format="CSS"
  249. :enable-alpha="true"
  250. :recent-colors="null"
  251. :swatch-colors="defaultPureColor"
  252. :color-modes="['monochrome']"
  253. :show-primary-color-preview="false"
  254. :clearable="true"
  255. v-model="data.pen.color"
  256. @change="changeValue('color')"
  257. />
  258. <label style="width: 64px">前景颜色</label>
  259. <t-color-picker
  260. class="simple mt-8 mr-4"
  261. format="CSS"
  262. :enable-alpha="true"
  263. :recent-colors="null"
  264. :swatch-colors="defaultPureColor"
  265. :color-modes="['monochrome']"
  266. :show-primary-color-preview="false"
  267. v-model="data.pen.hoverColor"
  268. @change="changeValue('hoverColor')"
  269. />
  270. <label style="width: 64px">悬停颜色</label>
  271. <t-color-picker
  272. class="simple mt-8 mr-4"
  273. format="CSS"
  274. :enable-alpha="true"
  275. :recent-colors="null"
  276. :swatch-colors="defaultPureColor"
  277. :color-modes="['monochrome']"
  278. :show-primary-color-preview="false"
  279. v-model="data.pen.activeColor"
  280. @change="changeValue('activeColor')"
  281. />
  282. <label style="width: 64px">选中颜色</label>
  283. </div>
  284. <div class="form-item">
  285. <label style="width: 32px">线条 </label>
  286. <t-select
  287. v-model="data.pen.dash"
  288. placeholder="线条样式"
  289. @change="changeValue('dash')"
  290. style="width: 80px"
  291. >
  292. <template #valueDisplay="{ value }">
  293. <svg
  294. xmlns="http://www.w3.org/2000/svg"
  295. version="1.1"
  296. style="width: 100%; height: 20px"
  297. >
  298. <g fill="none" stroke="var(--color)" stroke-width="1">
  299. <path v-if="value === 0" d="M0 9 l85 0" />
  300. <path
  301. v-else-if="value === 1"
  302. stroke-dasharray="5 5"
  303. d="M0 9 l85 0"
  304. />
  305. <path
  306. v-else-if="value === 2"
  307. stroke-dasharray="10 10"
  308. d="M0 9 l85 0"
  309. />
  310. <path
  311. v-else-if="value === 3"
  312. stroke-dasharray="10 10 2 10"
  313. d="M0 9 l85 0"
  314. />
  315. </g>
  316. </svg>
  317. </template>
  318. <t-option :key="0" :value="0">
  319. <svg
  320. xmlns="http://www.w3.org/2000/svg"
  321. version="1.1"
  322. style="width: 80px; height: 14px"
  323. >
  324. <g fill="none" stroke="var(--color)" stroke-width="1">
  325. <path d="M0 9 l85 0" />
  326. </g>
  327. </svg>
  328. </t-option>
  329. <t-option :key="1" :value="1">
  330. <svg
  331. xmlns="http://www.w3.org/2000/svg"
  332. version="1.1"
  333. style="width: 80px; height: 14px"
  334. >
  335. <g fill="none" stroke="var(--color)" stroke-width="1">
  336. <path stroke-dasharray="5 5" d="M0 9 l85 0" />
  337. </g>
  338. </svg>
  339. </t-option>
  340. <t-option :key="2" :value="2">
  341. <svg
  342. xmlns="http://www.w3.org/2000/svg"
  343. version="1.1"
  344. style="width: 80px; height: 14px"
  345. >
  346. <g fill="none" stroke="var(--color)" stroke-width="1">
  347. <path stroke-dasharray="10 10" d="M0 9 l85 0" />
  348. </g>
  349. </svg>
  350. </t-option>
  351. <t-option :key="3" :value="3">
  352. <svg
  353. xmlns="http://www.w3.org/2000/svg"
  354. version="1.1"
  355. style="width: 80px; height: 14px"
  356. >
  357. <g fill="none" stroke="var(--color)" stroke-width="1">
  358. <path stroke-dasharray="10 10 2 10" d="M0 9 l85 0" />
  359. </g>
  360. </svg>
  361. </t-option>
  362. </t-select>
  363. <t-input-number
  364. theme="normal"
  365. placeholder="线条宽度"
  366. v-model="data.pen.lineWidth"
  367. :min="0"
  368. :decimalPlaces="0"
  369. @change="changeValue('lineWidth')"
  370. class="ml-4"
  371. style="width: 40px"
  372. />
  373. <t-tooltip
  374. v-if="['polyline','line'].includes(data.pen.lineName)"
  375. content="平滑度"
  376. placement="top"
  377. >
  378. <t-input-number
  379. theme="normal"
  380. placeholder="1-3"
  381. v-model="data.pen.lineSmooth"
  382. :min="0"
  383. :decimalPlaces="0"
  384. @change="changeValue('lineSmooth')"
  385. class="ml-4"
  386. style="width: 44px"
  387. />
  388. </t-tooltip>
  389. <t-tooltip content="线条渐变" placement="top">
  390. <div class="flex middle ml-8">
  391. <t-checkbox
  392. v-model="data.pen.strokeType"
  393. @change="changeValue('strokeType')"
  394. style="width: 22px"
  395. />
  396. <t-color-picker
  397. v-if="data.pen.strokeType"
  398. class="simple mr-4"
  399. format="CSS"
  400. :swatch-colors="defaultGradientColor"
  401. :color-modes="['linear-gradient']"
  402. :show-primary-color-preview="false"
  403. :recent-colors="null"
  404. :enableAlpha="true"
  405. v-model="data.pen.lineGradientColors"
  406. @change="changeValue('lineGradientColors')"
  407. placeholder="无"
  408. />
  409. </div>
  410. </t-tooltip>
  411. </div>
  412. <div class="form-item">
  413. <label style="width: 52px">起点箭头 </label>
  414. <t-select
  415. v-model="data.pen.fromArrow"
  416. placeholder="线条样式"
  417. @change="changeValue('fromArrow')"
  418. style="width: 80px"
  419. >
  420. <template #valueDisplay="{ value }">
  421. <svg v-if="value" class="l-icon" aria-hidden="true">
  422. <use :xlink:href="fromArrows.find(item=>item.value===value).icon"></use>
  423. </svg>
  424. </template>
  425. <t-option v-for="item in fromArrows" :key="item.value" :value="item.value">
  426. <svg class="l-icon" aria-hidden="true">
  427. <use :xlink:href="item.icon"></use>
  428. </svg>
  429. </t-option>
  430. </t-select>
  431. <label style="width: 52px" class="ml-4">终点箭头 </label>
  432. <t-select
  433. v-model="data.pen.toArrow"
  434. placeholder="线条样式"
  435. @change="changeValue('toArrow')"
  436. style="width: 80px"
  437. >
  438. <template #valueDisplay="{ value }">
  439. <svg v-if="value" class="l-icon" aria-hidden="true">
  440. <use :xlink:href="toArrows.find(item=>item.value===value).icon"></use>
  441. </svg>
  442. </template>
  443. <t-option v-for="item in toArrows" :key="item.value" :value="item.value">
  444. <svg class="l-icon" aria-hidden="true">
  445. <use :xlink:href="item.icon"></use>
  446. </svg>
  447. </t-option>
  448. </t-select>
  449. </div>
  450. <div class="flex" style="margin-left: 40px">
  451. <div class="flex column middle">
  452. <t-radio-group
  453. size="small"
  454. v-model="data.pen.lineCap"
  455. default-value="butt"
  456. @change="changeValue('lineCap')"
  457. >
  458. <t-radio-button value="butt">
  459. <t-tooltip content="默认" placement="top">
  460. <svg class="l-icon" aria-hidden="true">
  461. <use xlink:href="#l-duandian1"></use>
  462. </svg>
  463. </t-tooltip>
  464. </t-radio-button>
  465. <t-radio-button value="round">
  466. <t-tooltip content="圆形" placement="top">
  467. <svg class="l-icon" aria-hidden="true">
  468. <use xlink:href="#l-duandian2"></use>
  469. </svg>
  470. </t-tooltip>
  471. </t-radio-button>
  472. <t-radio-button value="square">
  473. <t-tooltip content="方形" placement="top">
  474. <svg class="l-icon" aria-hidden="true">
  475. <use xlink:href="#l-duandian3"></use>
  476. </svg>
  477. </t-tooltip>
  478. </t-radio-button>
  479. </t-radio-group>
  480. <div class="mt-4" style="font-size: 12px">末端样式</div>
  481. </div>
  482. <div class="flex column middle ml-16">
  483. <t-radio-group
  484. size="small"
  485. v-model="data.pen.lineJoin"
  486. default-value="miter"
  487. @change="changeValue('lineJoin')"
  488. >
  489. <t-radio-button value="miter">
  490. <t-tooltip content="默认" placement="top">
  491. <svg class="l-icon" aria-hidden="true">
  492. <use xlink:href="#l-jiedian1"></use>
  493. </svg>
  494. </t-tooltip>
  495. </t-radio-button>
  496. <t-radio-button value="round">
  497. <t-tooltip content="圆形" placement="top">
  498. <svg class="l-icon" aria-hidden="true">
  499. <use xlink:href="#l-jiedian2"></use>
  500. </svg>
  501. </t-tooltip>
  502. </t-radio-button>
  503. <t-radio-button value="bevel">
  504. <t-tooltip content="斜角" placement="top">
  505. <svg class="l-icon" aria-hidden="true">
  506. <use xlink:href="#l-jiedian3"></use>
  507. </svg>
  508. </t-tooltip>
  509. </t-radio-button>
  510. </t-radio-group>
  511. <div class="mt-4" style="font-size: 12px">连接样式</div>
  512. </div>
  513. </div>
  514. <div class="form-item" v-if="!data.pen.type">
  515. <label style="width: 32px">背景</label>
  516. <div class="ml-8">
  517. <t-radio-group
  518. size="small"
  519. v-model="data.pen.bkType"
  520. :default-value="0"
  521. @change="changeValue('bkType')"
  522. >
  523. <t-radio-button :value="0"> 纯色 </t-radio-button>
  524. <t-radio-button :value="1"> 线性渐变 </t-radio-button>
  525. <t-radio-button :value="2"> 径向渐变 </t-radio-button>
  526. </t-radio-group>
  527. <div v-if="data.pen.bkType === 0" class="mt-8 -ml-8">
  528. <t-color-picker
  529. class="w-full"
  530. format="CSS"
  531. :swatch-colors="defaultPureColor"
  532. :color-modes="['monochrome']"
  533. :recent-colors="null"
  534. :enable-alpha="true"
  535. :show-primary-color-preview="false"
  536. v-model="data.pen.background"
  537. @change="changeValue('background')"
  538. />
  539. </div>
  540. <div
  541. v-else-if="data.pen.bkType === 1"
  542. class="mt-8 -ml-8"
  543. style="width: 200px"
  544. >
  545. <t-color-picker
  546. class="w-full"
  547. format="CSS"
  548. :enable-alpha="true"
  549. :recent-colors="null"
  550. :swatch-colors="defaultGradientColor"
  551. :color-modes="['linear-gradient']"
  552. :show-primary-color-preview="false"
  553. v-model="data.pen.gradientColors"
  554. @change="changeValue('gradientColors')"
  555. />
  556. </div>
  557. <div
  558. v-else-if="data.pen.bkType === 2"
  559. class="mt-8 flex middle"
  560. >
  561. <t-color-picker
  562. class="simple"
  563. format="CSS"
  564. :enable-alpha="true"
  565. :recent-colors="null"
  566. :swatch-colors="defaultGradientColor"
  567. :color-modes="['linear-gradient']"
  568. :show-primary-color-preview="false"
  569. v-model="data.pen.gradientColors"
  570. @change="changeValue('gradientColors')"
  571. />
  572. <t-input-number
  573. theme="column"
  574. placeholder="渐变半径"
  575. v-model="data.pen.gradientRadius"
  576. :min="0"
  577. :max="1"
  578. :step="0.1"
  579. @change="changeValue('gradientRadius')"
  580. class="ml-8"
  581. style="width: 100px"
  582. />
  583. </div>
  584. </div>
  585. </div>
  586. <div class="form-item">
  587. <label style="width: 32px">阴影 </label>
  588. <div class="flex middle ml-8">
  589. <t-checkbox
  590. v-model="data.pen.shadow"
  591. @change="changeValue('shadow')"
  592. style="width: 22px"
  593. />
  594. <t-color-picker
  595. v-if="data.pen.shadow"
  596. class="simple"
  597. format="CSS"
  598. :enable-alpha="true"
  599. :recent-colors="null"
  600. :swatch-colors="defaultPureColor"
  601. :color-modes="['monochrome']"
  602. :show-primary-color-preview="false"
  603. v-model="data.pen.shadowColor"
  604. @change="changeValue('shadowColor')"
  605. />
  606. </div>
  607. <label
  608. v-if="data.pen.shadow"
  609. style="width: 50px; margin-left: 25px"
  610. >文字阴影
  611. </label>
  612. <div v-if="data.pen.shadow" class="flex middle ml-8">
  613. <t-checkbox
  614. v-model="data.pen.textHasShadow"
  615. @change="changeValue('textHasShadow')"
  616. style="width: 22px"
  617. />
  618. </div>
  619. </div>
  620. <div class="form-item" v-if="data.pen.shadow">
  621. <label style="width: 28px"></label>
  622. <div class="flex" style="margin-top: -8px">
  623. <t-input
  624. class="ml-4"
  625. label="X"
  626. placeholder="0"
  627. v-model.number="data.pen.shadowOffsetX"
  628. style="width: 60px"
  629. @change="changeValue('shadowOffsetX')"
  630. title="X偏移"
  631. />
  632. <t-input
  633. class="ml-4"
  634. label="Y"
  635. placeholder="0"
  636. v-model.number="data.pen.shadowOffsetY"
  637. style="width: 60px"
  638. @change="changeValue('shadowOffsetY')"
  639. title="Y偏移"
  640. />
  641. <t-input
  642. class="ml-4"
  643. label="模糊"
  644. placeholder="0"
  645. v-model.number="data.pen.shadowBlur"
  646. style="width: 64px"
  647. @change="changeValue('shadowBlur')"
  648. title="模糊大小"
  649. />
  650. </div>
  651. </div>
  652. </t-space>
  653. </t-collapse-panel>
  654. <t-collapse-panel
  655. v-if="data.pen.props.text"
  656. value="2"
  657. header="文字"
  658. >
  659. <t-space direction="vertical" size="small" class="w-full">
  660. <div class="form-item">
  661. <div class="flex middle" style="margin-left: -10px">
  662. <t-select-input
  663. :value="data.pen.fontFamily"
  664. :popup-visible="data.fontFamilyPopupVisible"
  665. placeholder="字体名"
  666. allow-input
  667. style="width: 170px"
  668. @change="changeValue('fontFamily')"
  669. @enter="changeValue('fontFamily')"
  670. @blur="changeValue('fontFamily')"
  671. @popup-visible-change="onFontPopupVisible"
  672. :popup-props="{
  673. overlayInnerStyle: { width: 'auto' },
  674. }"
  675. >
  676. <template #panel>
  677. <ul style="padding: 12px">
  678. <li
  679. v-for="item in fonts"
  680. :key="item"
  681. @click="onFontFamily(item)"
  682. >
  683. {{ item }}
  684. </li>
  685. </ul>
  686. </template>
  687. <template #suffixIcon>
  688. <chevron-down-icon />
  689. <!-- <t-icon name="chevron-down" /> -->
  690. </template>
  691. </t-select-input>
  692. <t-input
  693. class="ml-8"
  694. placeholder="字体大小"
  695. v-model.number="data.pen.fontSize"
  696. style="width: 80px"
  697. :format="decimalRound"
  698. @change="changeValue('fontSize')"
  699. />
  700. </div>
  701. </div>
  702. <div class="flex middle">
  703. <t-radio-group
  704. size="small"
  705. v-model="data.pen.textAlign"
  706. default-value="center"
  707. @change="changeValue('textAlign')"
  708. >
  709. <t-radio-button value="left">
  710. <t-tooltip content="居左" placement="top">
  711. <format-vertical-align-left-icon />
  712. <!-- <t-icon name="format-vertical-align-left" /> -->
  713. </t-tooltip>
  714. </t-radio-button>
  715. <t-radio-button value="center">
  716. <t-tooltip content="水平居中" placement="top">
  717. <format-vertical-align-center-icon />
  718. <!-- <t-icon name="format-vertical-align-center" /> -->
  719. </t-tooltip>
  720. </t-radio-button>
  721. <t-radio-button value="right">
  722. <t-tooltip content="居右" placement="top">
  723. <format-vertical-align-right-icon />
  724. <!-- <t-icon name="format-vertical-align-right" /> -->
  725. </t-tooltip>
  726. </t-radio-button>
  727. </t-radio-group>
  728. <t-radio-group
  729. class="ml-8"
  730. size="small"
  731. v-model="data.pen.textBaseline"
  732. default-value="top"
  733. @change="changeValue('textBaseline')"
  734. >
  735. <t-radio-button value="top">
  736. <t-tooltip content="顶部对齐" placement="top">
  737. <format-horizontal-align-top-icon />
  738. <!-- <t-icon name="format-horizontal-align-top" /> -->
  739. </t-tooltip>
  740. </t-radio-button>
  741. <t-radio-button value="middle">
  742. <t-tooltip content="垂直居中" placement="top">
  743. <format-horizontal-align-center-icon />
  744. <!-- <t-icon name="format-horizontal-align-center" /> -->
  745. </t-tooltip>
  746. </t-radio-button>
  747. <t-radio-button value="bottom">
  748. <t-tooltip content="底部对齐" placement="top">
  749. <format-horizontal-align-bottom-icon />
  750. <!-- <t-icon name="format-horizontal-align-bottom" /> -->
  751. </t-tooltip>
  752. </t-radio-button>
  753. </t-radio-group>
  754. <t-button
  755. :class="{ active: data.pen.fontWeight === 'bold' }"
  756. class="ml-8 icon"
  757. shape="rectangle"
  758. variant="text"
  759. @click="
  760. data.pen.fontWeight === 'bold'
  761. ? (data.pen.fontWeight = 'normal')
  762. : (data.pen.fontWeight = 'bold');
  763. changeValue('fontWeight');
  764. "
  765. >
  766. B
  767. </t-button>
  768. <t-button
  769. :class="{ active: data.pen.fontStyle === 'italic' }"
  770. class="ml-4 icon"
  771. shape="rectangle"
  772. variant="text"
  773. @click="
  774. data.pen.fontStyle === 'italic'
  775. ? (data.pen.fontStyle = 'normal')
  776. : (data.pen.fontStyle = 'italic');
  777. changeValue('fontStyle');
  778. "
  779. style="font-style: italic; font-family: serif"
  780. >I</t-button
  781. >
  782. </div>
  783. <div class="form-item">
  784. <!-- <t-color-picker
  785. class="simple mt-8 mr-4"
  786. format="CSS"
  787. :enable-alpha="true"
  788. :recent-colors="null"
  789. :swatch-colors="defaultPureColor"
  790. :color-modes="['monochrome']"
  791. :show-primary-color-preview="false"
  792. v-model="data.pen.textColor"
  793. @change="changeValue('textColor')"
  794. />
  795. <label style="width: 44px">前景</label> -->
  796. <t-color-picker
  797. class="simple mt-8 mr-4"
  798. format="CSS"
  799. :enable-alpha="true"
  800. :recent-colors="null"
  801. :swatch-colors="defaultPureColor"
  802. :color-modes="['monochrome']"
  803. :show-primary-color-preview="false"
  804. v-model="data.pen.textBackground"
  805. @change="changeValue('textBackground')"
  806. />
  807. <label style="width: 64px">背景</label>
  808. <t-color-picker
  809. class="simple mt-8 mr-4"
  810. format="CSS"
  811. :enable-alpha="true"
  812. :recent-colors="null"
  813. :swatch-colors="defaultPureColor"
  814. :color-modes="['monochrome']"
  815. :show-primary-color-preview="false"
  816. v-model="data.pen.hoverTextColor"
  817. @change="changeValue('hoverTextColor')"
  818. />
  819. <label style="width: 64px">悬停</label>
  820. <t-color-picker
  821. class="simple mt-8 mr-4"
  822. format="CSS"
  823. :enable-alpha="true"
  824. :recent-colors="null"
  825. :swatch-colors="defaultPureColor"
  826. :color-modes="['monochrome']"
  827. :show-primary-color-preview="false"
  828. v-model="data.pen.activeTextColor"
  829. @change="changeValue('activeTextColor')"
  830. />
  831. <label style="width: 64px">选中</label>
  832. </div>
  833. <div class="form-item">
  834. <label style="width: 32px">前景</label>
  835. <div class="ml-8">
  836. <t-radio-group
  837. size="small"
  838. v-model="data.pen.textType"
  839. :default-value="0"
  840. @change="changeValue('textType')"
  841. >
  842. <t-radio-button :value="0"> 纯色 </t-radio-button>
  843. <t-radio-button :value="1"> 线性渐变 </t-radio-button>
  844. <t-radio-button :value="2"> 径向渐变 </t-radio-button>
  845. </t-radio-group>
  846. <div v-if="data.pen.textType === 0" class="mt-8 -ml-8">
  847. <t-color-picker
  848. class="w-full"
  849. format="CSS"
  850. :swatch-colors="defaultPureColor"
  851. :color-modes="['monochrome']"
  852. :recent-colors="null"
  853. :enable-alpha="true"
  854. :show-primary-color-preview="false"
  855. v-model="data.pen.textColor"
  856. @change="changeValue('textColor')"
  857. />
  858. </div>
  859. <div
  860. v-else-if="data.pen.textType === 1"
  861. class="mt-8 -ml-8"
  862. style="width: 200px"
  863. >
  864. <t-color-picker
  865. class="w-full"
  866. format="CSS"
  867. :enable-alpha="true"
  868. :recent-colors="null"
  869. :swatch-colors="defaultGradientColor"
  870. :color-modes="['linear-gradient']"
  871. :show-primary-color-preview="false"
  872. v-model="data.pen.textGradientColors"
  873. @change="changeValue('textGradientColors')"
  874. />
  875. </div>
  876. <div
  877. v-else-if="data.pen.textType === 2"
  878. class="mt-8 -ml-8"
  879. style="width: 200px"
  880. >
  881. <t-color-picker
  882. class="w-full"
  883. format="CSS"
  884. :enable-alpha="true"
  885. :recent-colors="null"
  886. :swatch-colors="defaultGradientColor"
  887. :color-modes="['linear-gradient']"
  888. :show-primary-color-preview="false"
  889. v-model="data.pen.textGradientColors"
  890. @change="changeValue('textGradientColors')"
  891. />
  892. </div>
  893. </div>
  894. </div>
  895. <div class="form-item">
  896. <t-checkbox
  897. :checked="data.pen.whiteSpace != 'nowrap' ? true : false"
  898. @change="changeValue('whiteSpace')"
  899. style="width: 64px"
  900. >
  901. 换行
  902. </t-checkbox>
  903. <t-checkbox
  904. v-model="data.pen.ellipsis"
  905. @change="changeValue('ellipsis')"
  906. style="width: 68px"
  907. >
  908. 省略号
  909. </t-checkbox>
  910. <t-tooltip content="行高">
  911. <t-input
  912. placeholder="行高"
  913. v-model.number="data.pen.lineHeight"
  914. style="width: 40px"
  915. @change="changeValue('lineHeight')"
  916. />
  917. </t-tooltip>
  918. <t-tooltip content="显示时保留小数位数">
  919. <t-input
  920. class="ml-4"
  921. placeholder="小数"
  922. v-model.number="data.pen.keepDecimal"
  923. style="width: 60px"
  924. @change="changeValue('keepDecimal')"
  925. />
  926. </t-tooltip>
  927. </div>
  928. <div class="form-item" style="margin-top: -4px">
  929. <t-tooltip content="水平偏移">
  930. <t-input
  931. placeholder="X"
  932. v-model.number="data.pen.textLeft"
  933. style="width: 60px; margin-left: -8px"
  934. @change="changeValue('textLeft')"
  935. />
  936. </t-tooltip>
  937. <t-tooltip content="垂直偏移">
  938. <t-input
  939. class="ml-4"
  940. placeholder="Y"
  941. v-model.number="data.pen.textTop"
  942. style="width: 60px"
  943. @change="changeValue('textTop')"
  944. />
  945. </t-tooltip>
  946. <t-tooltip content="宽">
  947. <t-input
  948. class="ml-4"
  949. placeholder="宽"
  950. v-model.number="data.pen.textWidth"
  951. style="width: 60px"
  952. @change="changeValue('textWidth')"
  953. />
  954. </t-tooltip>
  955. <t-tooltip content="高">
  956. <t-input
  957. class="ml-4"
  958. placeholder="高"
  959. v-model.number="data.pen.textHeight"
  960. style="width: 60px"
  961. @change="changeValue('textHeight')"
  962. />
  963. </t-tooltip>
  964. </div>
  965. <div class="flex middle">
  966. <t-checkbox
  967. v-model="data.pen.disableInput"
  968. @change="changeValue('disableInput')"
  969. style="width: 64px"
  970. >
  971. 只读
  972. </t-checkbox>
  973. <t-checkbox
  974. v-model="data.pen.hiddenText"
  975. @change="changeValue('hiddenText')"
  976. style="width: 90px"
  977. >
  978. 隐藏文字
  979. </t-checkbox>
  980. <t-checkbox
  981. v-model="data.pen.textAutoAdjust"
  982. @change="changeValue('textAutoAdjust')"
  983. style="width: 90px"
  984. >
  985. 自动调整
  986. </t-checkbox>
  987. </div>
  988. </t-space>
  989. </t-collapse-panel>
  990. <t-collapse-panel
  991. v-if="data.pen.props.image"
  992. value="3"
  993. header="图片"
  994. >
  995. <t-space direction="vertical" size="small" class="w-full">
  996. <div>
  997. <t-upload
  998. ref="uploadRef"
  999. v-model="data.images"
  1000. action="/api/image/upload"
  1001. theme="image"
  1002. accept="image/*"
  1003. :headers="headers"
  1004. :data="updataData"
  1005. :before-upload="beforeUpload"
  1006. draggable
  1007. @success="fileSuccessed"
  1008. @remove="fileRemoved"
  1009. >
  1010. <template #fileListDisplay>
  1011. <div style="z-index: 20">
  1012. <a class="mr-4" @click="upload"> 点击上传 </a>
  1013. / 拖拽图片到此区域
  1014. </div>
  1015. </template>
  1016. </t-upload>
  1017. </div>
  1018. <div class="form-item hover-icons" style="margin-left: -12px">
  1019. <t-input
  1020. class="ml-4"
  1021. label="W"
  1022. v-model.number="data.pen.iconWidth"
  1023. placeholder="自适应"
  1024. min="1"
  1025. style="width: 80px"
  1026. :format="decimalPlaces"
  1027. @change="changeValue('iconWidth')"
  1028. />
  1029. <t-tooltip
  1030. v-if="data.pen.imageRatio"
  1031. content="固定比例"
  1032. placement="top"
  1033. >
  1034. <link-icon class="ml-4 hover"
  1035. @click="data.pen.imageRatio = !data.pen.imageRatio"/>
  1036. <!-- <t-icon
  1037. name="link"
  1038. class="ml-4 hover"
  1039. @click="data.pen.imageRatio = !data.pen.imageRatio"
  1040. /> -->
  1041. </t-tooltip>
  1042. <t-tooltip v-else content="不固定比例" placement="top">
  1043. <link-unlink-icon class="ml-4 hover icon"
  1044. @click="data.pen.imageRatio = !data.pen.imageRatio"/>
  1045. <!-- <t-icon
  1046. name="link-unlink"
  1047. class="ml-4 hover icon"
  1048. @click="data.pen.imageRatio = !data.pen.imageRatio"
  1049. /> -->
  1050. </t-tooltip>
  1051. <t-input
  1052. class="ml-4"
  1053. label="H"
  1054. placeholder="自适应"
  1055. v-model.number="data.pen.iconHeight"
  1056. min="1"
  1057. style="width: 80px"
  1058. :format="decimalPlaces"
  1059. @change="changeValue('iconHeight')"
  1060. />
  1061. <t-checkbox
  1062. class="ml-8"
  1063. v-model="data.pen.toGif"
  1064. @change="changeValue('toGif')"
  1065. >
  1066. 转动图
  1067. </t-checkbox>
  1068. </div>
  1069. <div class="form-item">
  1070. <label style="width: 30px; color: var(--color)">Url:</label>
  1071. <!-- {{ data.pen.image }} -->
  1072. <t-input
  1073. class="w-full"
  1074. placeholder="图片地址"
  1075. v-model.number="data.pen.image"
  1076. @change="changeValue('image')"
  1077. />
  1078. </div>
  1079. </t-space>
  1080. </t-collapse-panel>
  1081. <t-collapse-panel
  1082. v-if="data.pen.props.icon"
  1083. value="4"
  1084. header="图标"
  1085. >
  1086. <t-space direction="vertical" size="small" class="w-full">
  1087. <div class="form-item">
  1088. <label style="width: 32px">图标 </label>
  1089. <i
  1090. class="ml-8"
  1091. :class="data.pen.iconFamily"
  1092. style="line-height: 30px; height: 30px; color: var(--color)"
  1093. >
  1094. {{ data.pen.icon }}
  1095. </i>
  1096. <a class="ml-12 mt-4" @click="iconsDrawer.show = true">
  1097. 选择
  1098. </a>
  1099. <t-drawer
  1100. v-model:visible="iconsDrawer.show"
  1101. header="选择图标"
  1102. :footer="null"
  1103. >
  1104. <Iconfonts :urls="data.iconUrls" @change="onChangeIcon" />
  1105. </t-drawer>
  1106. </div>
  1107. </t-space>
  1108. </t-collapse-panel>
  1109. <!-- <t-collapse-panel
  1110. v-if="data.pen.props.custom"
  1111. value="5"
  1112. header="属性"
  1113. >
  1114. <t-space direction="vertical" size="small" class="w-full">
  1115. <div v-for="item in data.pen.props.custom" class="form-item">
  1116. <label :title="item.label">{{ item.label }}</label>
  1117. <t-checkbox
  1118. class="ml-8"
  1119. v-if="item.type === 'bool'"
  1120. v-model="data.pen[item.key]"
  1121. @change="changeValue(item.key)"
  1122. />
  1123. <t-input-number
  1124. class="w-full"
  1125. v-else-if="item.type === 'number'"
  1126. v-model.number="data.pen[item.key]"
  1127. theme="column"
  1128. :max="item.max"
  1129. :min="item.min"
  1130. @change="changeValue(item.key)"
  1131. :placeholder="item.placeholder"
  1132. />
  1133. <t-color-picker
  1134. class="w-full"
  1135. v-else-if="item.type === 'color'"
  1136. :enable-alpha="true"
  1137. :recent-colors="null"
  1138. format="CSS"
  1139. :swatch-colors="defaultPureColor"
  1140. :color-modes="['monochrome']"
  1141. :show-primary-color-preview="false"
  1142. v-model="data.pen[item.key]"
  1143. @change="changeValue(item.key)"
  1144. :placeholder="item.placeholder"
  1145. />
  1146. <t-select
  1147. class="w-full"
  1148. v-else-if="item.type === 'select'"
  1149. size="small"
  1150. :options="item.options"
  1151. v-model="data.pen[item.key]"
  1152. @change="changeValue(item.key)"
  1153. :placeholder="item.placeholder"
  1154. />
  1155. <t-button
  1156. v-else-if="item.type === 'code'"
  1157. shape="square"
  1158. variant="outline"
  1159. style="width: 24px"
  1160. @click="showPropsEdit(item)"
  1161. >
  1162. <t-icon name="ellipsis" slot="icon"
  1163. /></t-button>
  1164. <t-slider
  1165. v-else-if="item.type === 'slider'"
  1166. v-model="data.pen[item.key]"
  1167. :min="0"
  1168. :max="1"
  1169. :step="0.01"
  1170. @change="changeValue(item.key)"
  1171. />
  1172. <t-switch
  1173. v-else-if="item.type === 'switch'"
  1174. v-model="data.pen[item.key]"
  1175. @change="changeValue(item.key)"
  1176. />
  1177. <t-input
  1178. class="w-full"
  1179. v-else
  1180. v-model="data.pen[item.key]"
  1181. @change="changeValue(item.key)"
  1182. :placeholder="item.placeholder"
  1183. />
  1184. </div>
  1185. </t-space>
  1186. </t-collapse-panel> -->
  1187. </t-collapse>
  1188. <template v-if="!data.pen.externElement && data.pen.name !== 'image'&& data.pen.name !== 'gif'">
  1189. <t-divider style="margin: -8px 0" />
  1190. <div class="form-item px-16">
  1191. <label>进度 </label>
  1192. <t-slider
  1193. v-model="data.pen.progress"
  1194. :min="0"
  1195. :max="1"
  1196. :step="0.01"
  1197. @change="changeValue('progress')"
  1198. />
  1199. <span class="ml-16" style="width: 50px; line-height: 30px">
  1200. {{ data.pen.progress }}
  1201. </span>
  1202. </div>
  1203. <div class="form-item" style="padding-left: 17px">
  1204. <t-color-picker
  1205. class="simple mr-25"
  1206. format="CSS"
  1207. :enable-alpha="true"
  1208. :recent-colors="null"
  1209. :swatch-colors="defaultPureColor"
  1210. :color-modes="['monochrome']"
  1211. :show-primary-color-preview="false"
  1212. v-model="data.pen.progressColor"
  1213. @change="changeValue('progressColor')"
  1214. />
  1215. <t-tooltip content="垂直进度" placement="top">
  1216. <t-checkbox
  1217. class="mr-25"
  1218. v-model="data.pen.verticalProgress"
  1219. @change="changeValue('verticalProgress')"
  1220. style="width: 22px"
  1221. />
  1222. </t-tooltip>
  1223. <t-tooltip content="反向进度" placement="top">
  1224. <t-checkbox
  1225. class="mr-25"
  1226. v-model="data.pen.reverseProgress"
  1227. @change="changeValue('reverseProgress')"
  1228. style="width: 22px"
  1229. />
  1230. </t-tooltip>
  1231. <t-tooltip content="进度渐变" placement="top">
  1232. <t-checkbox
  1233. class="mr-25"
  1234. v-model="data.pen.temProgressFlag"
  1235. @change="changetemProgressFlag(data.pen)"
  1236. style="width: 22px"
  1237. />
  1238. </t-tooltip>
  1239. <t-color-picker
  1240. v-if="data.pen.temProgressFlag"
  1241. class="simple"
  1242. format="CSS"
  1243. :swatch-colors="defaultGradientColor"
  1244. :color-modes="['linear-gradient']"
  1245. :show-primary-color-preview="false"
  1246. :recent-colors="null"
  1247. :enableAlpha="true"
  1248. v-model="data.pen.progressGradientColors"
  1249. @change="changeValue('progressGradientColors')"
  1250. placeholder="无"
  1251. />
  1252. </div>
  1253. </template>
  1254. <t-divider style="margin: -8px 0" />
  1255. <div class="form-item px-16" style="margin-top: -12px">
  1256. <t-checkbox
  1257. v-model="data.pen.flipX"
  1258. @change="changeValue('flipX')"
  1259. style="width: 90px"
  1260. >
  1261. 水平翻转
  1262. </t-checkbox>
  1263. <t-checkbox
  1264. v-model="data.pen.flipY"
  1265. @change="changeValue('flipY')"
  1266. style="width: 90px"
  1267. >
  1268. 垂直翻转
  1269. </t-checkbox>
  1270. <label style="width: 50px">锚点半径</label>
  1271. <input
  1272. class="ml-4"
  1273. v-model.number="data.pen.anchorRadius"
  1274. style="width: 20px"
  1275. @change="changeValue('anchorRadius')"
  1276. placeholder="4"
  1277. />
  1278. </div>
  1279. <t-divider style="margin: -8px 0" />
  1280. <div class="form-item px-16" style="margin-top: -12px">
  1281. <t-checkbox
  1282. v-model="data.pen.disableRotate"
  1283. @change="changeValue('disableRotate')"
  1284. style="width: 90px"
  1285. >
  1286. 禁止旋转
  1287. </t-checkbox>
  1288. <t-checkbox
  1289. v-model="data.pen.disableSize"
  1290. @change="changeValue('disableSize')"
  1291. style="width: 90px"
  1292. >
  1293. 禁止缩放
  1294. </t-checkbox>
  1295. <t-checkbox
  1296. v-model="data.pen.disableAnchor"
  1297. @change="changeValue('disableAnchor')"
  1298. style="width: 90px"
  1299. >
  1300. 禁用锚点
  1301. </t-checkbox>
  1302. </div>
  1303. <t-divider style="margin: -8px 0" />
  1304. <div class="form-item px-16" style="margin-top: -12px">
  1305. <label style="width: 60px">鼠标提示</label>
  1306. <t-button
  1307. shape="square"
  1308. variant="outline"
  1309. style="width: 24px"
  1310. @click="showTooltip"
  1311. >
  1312. <ellipsis-icon slot="icon"/>
  1313. <!-- <t-icon name="ellipsis" slot="icon" /> -->
  1314. </t-button>
  1315. </div>
  1316. <t-dialog
  1317. v-if="tooltipDialog.show"
  1318. :visible="true"
  1319. header="鼠标提示"
  1320. @confirm="onOkTooltip"
  1321. @close="tooltipDialog.show = false"
  1322. :width="700"
  1323. >
  1324. <t-radio-group v-model="tooltipDialog.type">
  1325. <t-radio value="1">文字</t-radio>
  1326. <t-radio value="2">函数</t-radio>
  1327. </t-radio-group>
  1328. <div class="py-8">
  1329. <CodeEditor
  1330. v-show="tooltipDialog.type == 1"
  1331. v-model="tooltipDialog.title"
  1332. style="height: 300px"
  1333. />
  1334. <div v-show="tooltipDialog.type == 2">
  1335. <div>function tooltip(pen) {</div>
  1336. <CodeEditor
  1337. v-model="tooltipDialog.titleFnJs"
  1338. class="mt-4"
  1339. style="height: 248px"
  1340. />
  1341. <div class="mt-4">}</div>
  1342. </div>
  1343. </div>
  1344. <div class="gray" style="font-size: 12px">支持Markdown格式</div>
  1345. </t-dialog>
  1346. <t-dialog
  1347. v-if="propsDialog.show"
  1348. :visible="true"
  1349. :header="propsDialog.header"
  1350. @confirm="onOkPropsEdit"
  1351. @close="propsDialog.show = false"
  1352. :width="700"
  1353. >
  1354. <div class="py-8">
  1355. <CodeEditor
  1356. :json="true"
  1357. :language="'json'"
  1358. v-model="propsDialog.value"
  1359. style="height: 300px"
  1360. />
  1361. </div>
  1362. <div class="gray" style="font-size: 12px">
  1363. {{ propsDialog.placeholder }}
  1364. </div>
  1365. </t-dialog>
  1366. <t-space />
  1367. </t-space>
  1368. </t-tab-panel>
  1369. <t-tab-panel :value="2" label="动画">
  1370. <PenAnimates :pen="data.pen" />
  1371. </t-tab-panel>
  1372. <t-tab-panel :value="3" label="数据">
  1373. <PenDatas :pen="data.pen" />
  1374. </t-tab-panel>
  1375. <t-tab-panel :value="4" label="交互">
  1376. <PenEvents :key="data.key" :pen="data.pen" />
  1377. </t-tab-panel>
  1378. <t-tab-panel :value="5" label="结构">
  1379. <ElementTree />
  1380. </t-tab-panel>
  1381. </t-tabs>
  1382. </div>
  1383. </template>
  1384. <script lang="ts" setup>
  1385. import { onBeforeMount, onUnmounted, reactive, ref, watch, computed } from 'vue';
  1386. import CodeEditor from './common/CodeEditor.vue';
  1387. import Iconfonts from './common/Iconfonts.vue';
  1388. import PenAnimates from './PenAnimates.vue';
  1389. import PenDatas from './PenDatas.vue';
  1390. import PenEvents from './PenEvents.vue';
  1391. import ElementTree from './ElementTree.vue';
  1392. import { getCookie } from '@/services/cookie';
  1393. import { useSelection } from '@/services/selections';
  1394. import { autoSave, fonts, inTreePanel } from '@/services/common';
  1395. import { updatePen } from './pen';
  1396. import { MessagePlugin } from 'tdesign-vue-next';
  1397. import { useUser } from '@/services/user';
  1398. import { getter, queryURLParams, isDomShapes } from '@meta2d/core';
  1399. import { defaultGradientColor, defaultPureColor, fromArrows, toArrows } from '@/services/defaults';
  1400. import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
  1401. import { s8 } from '@/services/random';
  1402. import { EllipsisIcon, LinkIcon, LinkUnlinkIcon, ChevronDownIcon, FormatVerticalAlignLeftIcon, FormatHorizontalAlignCenterIcon, FormatVerticalAlignCenterIcon, FormatVerticalAlignRightIcon, FormatHorizontalAlignTopIcon, FormatHorizontalAlignBottomIcon } from 'tdesign-icons-vue-next';
  1403. const { user } = useUser();
  1404. const headers = {
  1405. Authorization: 'Bearer ' + (getCookie('token') || ''),
  1406. };
  1407. const updataData = { directory: '/大屏/图片/默认' };
  1408. const uploadRef = ref();
  1409. const data = reactive<any>({
  1410. tab: 1,
  1411. pen: {},
  1412. rect: {},
  1413. key: s8(),
  1414. });
  1415. const { selections } = useSelection();
  1416. const tooltipDialog = reactive<any>({
  1417. show: false,
  1418. });
  1419. const propsDialog = reactive<any>({
  1420. show: false,
  1421. });
  1422. const iconsDrawer = reactive<any>({
  1423. show: false,
  1424. });
  1425. const aligns = [
  1426. {
  1427. value: 'left',
  1428. label: '左对齐',
  1429. icon: '#l-align-left',
  1430. },
  1431. {
  1432. value: 'center',
  1433. label: '垂直居中对齐',
  1434. icon: '#l-align-center',
  1435. },
  1436. {
  1437. value: 'right',
  1438. label: '右对齐',
  1439. icon: '#l-align-right',
  1440. },
  1441. {
  1442. value: 'top',
  1443. label: '顶部对齐',
  1444. icon: '#l-align-top',
  1445. },
  1446. {
  1447. value: 'middle',
  1448. label: '水平居中对齐',
  1449. icon: '#l-align-middle',
  1450. },
  1451. {
  1452. value: 'bottom',
  1453. label: '底部对齐',
  1454. icon: '#l-align-bottom',
  1455. },
  1456. ];
  1457. const align = (align: string) => {
  1458. meta2d.alignNodesV(align, meta2d.store.active);
  1459. getRect();
  1460. meta2d.render();
  1461. };
  1462. onBeforeMount(() => {
  1463. if (inTreePanel.value) {
  1464. data.tab = 5;
  1465. }
  1466. const d = meta2d.store.data as any;
  1467. if (!d.groups) {
  1468. d.groups = [];
  1469. }
  1470. if (!d.iconUrls) {
  1471. d.iconUrls = [];
  1472. }
  1473. data.iconUrls = d.iconUrls;
  1474. data.groups = d.groups;
  1475. initPenData();
  1476. meta2d.on('translatePens', getRect);
  1477. meta2d.on('resizePens',detailResizePens);
  1478. meta2d.on('rotatePens', getRect);
  1479. });
  1480. function initPenData() {
  1481. data.key = s8(); //触发更新
  1482. data.pen = selections.pen;
  1483. if (!data.pen.props) {
  1484. data.pen.props = {};
  1485. }
  1486. if (!data.pen.globalAlpha && data.pen.globalAlpha !== 0) {
  1487. data.pen.globalAlpha = 1;
  1488. }
  1489. if (!data.pen.dash) {
  1490. data.pen.dash = 0;
  1491. }
  1492. if (!data.pen.props.text) {
  1493. if (data.pen.text || data.pen.name === 'text') {
  1494. data.pen.props.text = true;
  1495. }
  1496. }
  1497. if (!data.pen.props.image) {
  1498. if (data.pen.image) {
  1499. data.pen.props.image = true;
  1500. }
  1501. }
  1502. if (!data.pen.props.icon) {
  1503. if (data.pen.icon) {
  1504. data.pen.props.icon = true;
  1505. }
  1506. }
  1507. if (data.pen.image) {
  1508. data.images = [
  1509. {
  1510. url: data.pen.image,
  1511. },
  1512. ];
  1513. }
  1514. if (!data.pen.tags) {
  1515. data.pen.tags = [];
  1516. }
  1517. if (data.pen.bkType == undefined) {
  1518. data.pen.bkType = 0;
  1519. }
  1520. if (data.pen.textType == undefined) {
  1521. data.pen.textType = 0;
  1522. }
  1523. if (!data.pen.animations) {
  1524. data.pen.animations = [];
  1525. }
  1526. if (!data.pen.whiteSpace) {
  1527. data.pen.whiteSpace = 'break-all';
  1528. }
  1529. if (data.pen.ellipsis == undefined) {
  1530. data.pen.ellipsis = false;
  1531. }
  1532. data.pen.shadow = !!data.pen.shadowColor;
  1533. getRect();
  1534. }
  1535. const watcher = watch(() => selections.pen.id, initPenData);
  1536. const getRect = () => {
  1537. data.rect = meta2d.getPenRect(data.pen);
  1538. };
  1539. const detailResizePens = () => {
  1540. getRect();
  1541. updateTabBtnData();
  1542. }
  1543. const updateTabBtnData = () => {//更新tab按钮的宽高
  1544. if(data.pen.name === 'tab') {
  1545. const len = data.pen.data.length;
  1546. const gap = data.pen.gap;
  1547. const {width: w, height: h} = data.rect;
  1548. let btnWidth = 0, btnHeight = 0;
  1549. if (data.pen.direction == 'horizontal') {
  1550. btnWidth = (w - (len + 1) * gap) / len;
  1551. btnHeight = h - gap * 2;
  1552. } else {
  1553. btnWidth = w - gap * 2;
  1554. btnHeight = (h - (len + 1) * gap) / len;
  1555. }
  1556. data.pen.btnWidth = btnWidth;
  1557. data.pen.btnHeight = btnHeight;
  1558. }
  1559. }
  1560. const decimalPlaces = (val: number) => {
  1561. if (!val) {
  1562. return 0;
  1563. }
  1564. return Math.round(+val * 100) / 100;
  1565. };
  1566. const decimalRound = (val: number) => {
  1567. return Math.round(+val || 0);
  1568. };
  1569. const changeValue = (prop: string) => {
  1570. if(prop.indexOf('radient')!==-1){
  1571. let collect = document.querySelectorAll('[class^="t-color-picker"]')
  1572. collect.forEach((i:HTMLElement)=> {
  1573. if(!i.dataset.meta2dIgnore){
  1574. i.dataset.meta2dIgnore = 'true';
  1575. }
  1576. })
  1577. }
  1578. if(prop === 'toGif'){
  1579. if(data.pen.toGif){
  1580. meta2d.setValue({id:data.pen.id,name:'gif'});
  1581. }else{
  1582. meta2d.setValue({id:data.pen.id,name:'image'});
  1583. }
  1584. return;
  1585. }
  1586. updatePen(data.pen, prop);
  1587. selections.pen[prop] = getter(data.pen, prop);
  1588. if (prop === 'iframe') {
  1589. getThumbImg();
  1590. }
  1591. if(prop === 'image'){
  1592. data.images = [
  1593. {
  1594. url: data.pen.image,
  1595. },
  1596. ];
  1597. }
  1598. };
  1599. const getThumbImg = async () => {
  1600. //改iframe地址后
  1601. let arr = data.pen.iframe.split('?');
  1602. let id = queryURLParams(arr[1]).id;
  1603. if (!id) {
  1604. return;
  1605. }
  1606. let projection = 'image,id,name';
  1607. let res: any;
  1608. if (arr[0].indexOf('2d.le5le') !== -1) {
  1609. res = await getLe5le2d(id, projection);
  1610. } else if (arr[0].indexOf('v.le5le') !== -1) {
  1611. res = await getLe5leV(id, projection);
  1612. } else if (arr[0].indexOf('3d.le5le') !== -1) {
  1613. res = await getLe5le3d(id, projection);
  1614. }
  1615. if (res) {
  1616. data.pen.thumbImg = res.image;
  1617. }
  1618. data.pen.onRenderPenRaw?.(data.pen);
  1619. };
  1620. const changeID = (value: any) => {
  1621. if (!value) {
  1622. initPenData();
  1623. MessagePlugin.error('id 不能为空');
  1624. return;
  1625. }
  1626. const oldID: string = data.pen.id;
  1627. try {
  1628. meta2d.changePenId(oldID, value);
  1629. initPenData();
  1630. } catch (error) {
  1631. console.warn(error.message);
  1632. MessagePlugin.error('id 修改失败,请检查 id 是否重复');
  1633. return;
  1634. }
  1635. };
  1636. const changeRectValue = (prop: string) => {
  1637. data.rect.id = data.pen.id;
  1638. data.rect.ratio = data.pen.ratio;
  1639. updatePen(data.rect, prop);
  1640. };
  1641. const onFontPopupVisible = (val: boolean) => {
  1642. data.fontFamilyPopupVisible = val;
  1643. };
  1644. const onFontFamily = (fontFamily: string) => {
  1645. data.pen.fontFamily = fontFamily;
  1646. data.fontFamilyPopupVisible = false;
  1647. changeValue('fontFamily');
  1648. };
  1649. const beforeUpload = (file: any) => {
  1650. // if (file.size > 5 * 1024 * 1024) {
  1651. // MessagePlugin.warning('上传的图片不能大于5M');
  1652. // return false;
  1653. // }
  1654. if (!(user && user.id)) {
  1655. MessagePlugin.warning('请先登录!');
  1656. return false;
  1657. }
  1658. return true;
  1659. };
  1660. const fileSuccessed = async (content: any) => {
  1661. // meta2d.store.patchFlagsBackground = true;
  1662. // meta2d.setBackgroundImage(content.response.url);
  1663. // meta2d.store.patchFlagsBackground = true;
  1664. data.pen.image = content.response.url || `/file${content.response.filename}`;
  1665. updatePen(data.pen, 'image');
  1666. meta2d.render();
  1667. };
  1668. const fileRemoved = () => {
  1669. // meta2d.setBackgroundImage('');
  1670. // meta2d.store.patchFlagsBackground = true;
  1671. data.pen.image = '';
  1672. updatePen(data.pen, 'image');
  1673. meta2d.render();
  1674. // data.background = [];
  1675. };
  1676. const upload = () => {
  1677. uploadRef.value.triggerUpload();
  1678. };
  1679. const onSelectTag = (tag: string) => {
  1680. data.tagPopupVisible = false;
  1681. if (data.pen.tags.includes(tag)) {
  1682. return;
  1683. }
  1684. data.pen.tags.push(tag);
  1685. changeValue('tags');
  1686. };
  1687. const onChangeInputTag = (currentTags: any, context: any) => {
  1688. const { trigger, index, item } = context;
  1689. if (['tag-remove', 'backspace'].includes(trigger)) {
  1690. data.pen.tags.splice(index, 1);
  1691. }
  1692. if (trigger === 'enter') {
  1693. onSelectTag(item);
  1694. const d = meta2d.store.data as any;
  1695. if (!d.groups.includes(item)) {
  1696. d.groups.push(item);
  1697. data.groups = d.groups;
  1698. }
  1699. data.inputTag = '';
  1700. }
  1701. data.tagPopupVisible = false;
  1702. };
  1703. const showTooltip = () => {
  1704. tooltipDialog.title = data.pen.title || '';
  1705. tooltipDialog.titleFnJs =
  1706. data.pen.titleFnJs || '// 例如:return `${pen.name}<br/>${pen.text}`;';
  1707. tooltipDialog.type = data.pen.titleFnJs ? '2' : '1';
  1708. tooltipDialog.show = true;
  1709. };
  1710. const onOkTooltip = () => {
  1711. data.pen.titleFn = null;
  1712. if (tooltipDialog.type === '1') {
  1713. data.pen.title = tooltipDialog.title;
  1714. data.pen.titleFnJs = '';
  1715. } else {
  1716. data.pen.title = '';
  1717. data.pen.titleFnJs = tooltipDialog.titleFnJs;
  1718. }
  1719. tooltipDialog.show = false;
  1720. };
  1721. const showPropsEdit = (item: any) => {
  1722. propsDialog.key = item.key;
  1723. propsDialog.header = `${item.label}(${item.key})`;
  1724. propsDialog.value = data.pen[item.key];
  1725. propsDialog.placeholder = item.placeholder;
  1726. propsDialog.show = true;
  1727. };
  1728. const onOkPropsEdit = () => {
  1729. if (!propsDialog.value) {
  1730. MessagePlugin.error('数据不满足json格式');
  1731. return;
  1732. }
  1733. data.pen[propsDialog.key] = propsDialog.value;
  1734. updatePen(data.pen, propsDialog.key);
  1735. propsDialog.show = false;
  1736. };
  1737. const onChangeIcon = (params: any) => {
  1738. Object.assign(data.pen, params);
  1739. meta2d.setValue({
  1740. id: data.pen.id,
  1741. icon: params.icon,
  1742. iconFamily: params.iconFamily,
  1743. });
  1744. autoSave(true);
  1745. };
  1746. const changetemProgressFlag = (pen: any) => {
  1747. if (pen.temProgressFlag) {
  1748. } else {
  1749. pen.progressGradientColors = undefined;
  1750. changeValue('progressGradientColors');
  1751. }
  1752. };
  1753. const isDom = computed(() => {
  1754. return isDomShapes.includes(data.pen.name) ||
  1755. data.pen.name.endsWith('Dom') ||
  1756. meta2d.store.options.domShapes.includes(data.pen.name)
  1757. });
  1758. onUnmounted(() => {
  1759. watcher();
  1760. meta2d.off('translatePens', getRect);
  1761. meta2d.off('resizePens', detailResizePens);
  1762. meta2d.off('rotatePens', getRect);
  1763. });
  1764. </script>
  1765. <style lang="postcss" scoped>
  1766. .props {
  1767. .icons {
  1768. display: flex;
  1769. svg:hover {
  1770. cursor: pointer;
  1771. color: var(--color-primary);
  1772. }
  1773. .btn {
  1774. font-size: 16px;
  1775. margin-right: 16px;
  1776. color: var(--color);
  1777. }
  1778. }
  1779. }
  1780. </style>