PenProps.vue 58 KB

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