Custom.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  1. <template>
  2. <t-space direction="vertical" size="small" class="w-full">
  3. <div v-for="item in props.pen.props.custom" class="form-item">
  4. <label :title="item.label">{{ item.label }}</label>
  5. <t-checkbox
  6. class="ml-8"
  7. v-if="item.type === 'bool'"
  8. v-model="props.pen[item.key]"
  9. @change="changeValue(item.key)"
  10. />
  11. <t-input-number
  12. class="w-full"
  13. v-else-if="item.type === 'number'"
  14. v-model.number="props.pen[item.key]"
  15. theme="column"
  16. :max="item.max"
  17. :min="item.min"
  18. @change="changeValue(item.key)"
  19. :placeholder="item.placeholder"
  20. :allowInputOverLimit="false"
  21. :decimalPlaces="2"
  22. />
  23. <t-color-picker
  24. class="w-full"
  25. v-else-if="item.type === 'color'"
  26. :enable-alpha="true"
  27. :recent-colors="null"
  28. format="CSS"
  29. :swatch-colors="defaultPureColor"
  30. :color-modes="['monochrome']"
  31. :show-primary-color-preview="false"
  32. v-model="props.pen[item.key]"
  33. @change="changeValue(item.key)"
  34. :placeholder="item.placeholder"
  35. />
  36. <t-select
  37. class="w-full"
  38. v-else-if="item.type === 'select'"
  39. size="small"
  40. :options="item.options"
  41. v-model="props.pen[item.key]"
  42. @change="changeValue(item.key)"
  43. :placeholder="item.placeholder"
  44. />
  45. <!-- <t-button
  46. class="ml-8"
  47. v-else-if="item.type === 'code'"
  48. shape="square"
  49. variant="outline"
  50. style="width: 24px"
  51. @click="showPropsEdit(item)"
  52. >
  53. <ellipsis-icon slot="icon"/>
  54. </t-button> -->
  55. <t-button
  56. class="ml-8"
  57. v-else-if="item.type === 'code'"
  58. shape="square"
  59. variant="outline"
  60. style="width: 24px"
  61. @click="showDrawer(item)"
  62. >
  63. <ChevronLeftDoubleIcon slot="icon" />
  64. </t-button>
  65. <t-slider
  66. v-else-if="item.type === 'slider'"
  67. v-model="props.pen[item.key]"
  68. :min="0"
  69. :max="1"
  70. :step="0.01"
  71. @change="changeValue(item.key)"
  72. />
  73. <t-switch
  74. size="small"
  75. class="mt-8 ml-8"
  76. v-else-if="item.type === 'switch'"
  77. v-model="props.pen[item.key]"
  78. @change="changeValue(item.key)"
  79. />
  80. <t-input
  81. class="w-full"
  82. v-else
  83. v-model="props.pen[item.key]"
  84. @change="changeValue(item.key)"
  85. :placeholder="item.placeholder"
  86. />
  87. </div>
  88. <div v-if="props.pen.name === 'tablePlus'">
  89. <div
  90. class="form-cell"
  91. v-if="cell.row !== undefined && cell.col !== undefined"
  92. >
  93. 选中单元格(第{{ cell.row }}行,第{{ cell.col }}列)样式
  94. </div>
  95. <div
  96. class="form-cell"
  97. v-else-if="cell.row !== undefined && cell.col === undefined"
  98. >
  99. 第{{ cell.row }}行样式
  100. </div>
  101. <div
  102. class="form-cell"
  103. v-if="cell.row === undefined && cell.col !== undefined"
  104. >
  105. 第{{ cell.col }}列样式
  106. </div>
  107. <t-space direction="vertical" size="small" class="w-full">
  108. <div class="form-item">
  109. <label>背景颜色</label>
  110. <t-color-picker
  111. class="w-full"
  112. :enable-alpha="true"
  113. :recent-colors="null"
  114. format="CSS"
  115. :swatch-colors="defaultPureColor"
  116. :color-modes="['monochrome']"
  117. :show-primary-color-preview="false"
  118. v-model="cell.background"
  119. @change="changeStyles('background')"
  120. />
  121. </div>
  122. <div class="form-item">
  123. <label>文字颜色</label>
  124. <t-color-picker
  125. class="w-full"
  126. :enable-alpha="true"
  127. :recent-colors="null"
  128. format="CSS"
  129. :swatch-colors="defaultPureColor"
  130. :color-modes="['monochrome']"
  131. :show-primary-color-preview="false"
  132. v-model="cell.textColor"
  133. @change="changeStyles('textColor')"
  134. />
  135. </div>
  136. <div class="form-item">
  137. <label>文字大小</label>
  138. <t-input-number
  139. class="w-full"
  140. v-model.number="cell.fontSize"
  141. theme="column"
  142. :min="0"
  143. @change="changeStyles('fontSize')"
  144. :allowInputOverLimit="false"
  145. :decimalPlaces="2"
  146. />
  147. </div>
  148. </t-space>
  149. </div>
  150. </t-space>
  151. <t-drawer
  152. v-model:visible="drawer.visible"
  153. :header="drawer.header"
  154. cancelBtn="关闭"
  155. confirmBtn="运行"
  156. @confirm="onConfirmDrawer"
  157. :closeOnOverlayClick="false"
  158. :sizeDraggable="true"
  159. >
  160. <div style="height: 100%">
  161. <CodeEditor
  162. style="height: 100%"
  163. :key="drawer.randomkey"
  164. :json="true"
  165. :language="'json'"
  166. v-model="drawer.value"
  167. />
  168. </div>
  169. <div class="gray" style="font-size: 12px">
  170. {{ drawer.placeholder }}
  171. </div>
  172. </t-drawer>
  173. </template>
  174. <script lang="ts" setup>
  175. import { reactive, defineComponent, ref, onMounted, onUnmounted } from 'vue';
  176. import {
  177. getter,
  178. setter,
  179. queryURLParams,
  180. deepClone,
  181. getAllChildren,
  182. Pen,
  183. } from '@meta2d/core';
  184. import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
  185. import { updatePen } from './pen';
  186. import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
  187. import { MessagePlugin } from 'tdesign-vue-next';
  188. import { s8 } from '@/services/random';
  189. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  190. import { ChevronLeftDoubleIcon } from 'tdesign-icons-vue-next';
  191. const props = defineProps<{
  192. pen: any;
  193. }>();
  194. const changeValue = (prop: string) => {
  195. updatePen(props.pen, prop);
  196. // selections.pen[prop] = getter(props.pen, prop);
  197. if (prop === 'iframe') {
  198. getThumbImg();
  199. }
  200. if (prop === 'apiEnable') {
  201. meta2d.penNetwork(props.pen);
  202. meta2d.connectNetwork();
  203. }
  204. };
  205. const getThumbImg = async () => {
  206. //改iframe地址后
  207. let arr = props.pen.iframe.split('?');
  208. let id = queryURLParams(arr[1]).id;
  209. if (!id) {
  210. return;
  211. }
  212. // let projection = {
  213. // image: 1,
  214. // _id: 1,
  215. // name: 1,
  216. // };
  217. let projection = 'image,id,name';
  218. let res: any;
  219. if (
  220. arr[0].indexOf('2d.le5le') !== -1 ||
  221. arr[0].indexOf('le5le.com/2d') !== -1
  222. ) {
  223. res = await getLe5le2d(id, projection);
  224. } else if (
  225. arr[0].indexOf('v.le5le') !== -1 ||
  226. arr[0].indexOf('le5le.com/v') !== -1
  227. ) {
  228. res = await getLe5leV(id, projection);
  229. } else if (
  230. arr[0].indexOf('3d.le5le') !== -1 ||
  231. arr[0].indexOf('le5le.com/3d') !== -1
  232. ) {
  233. res = await getLe5le3d(id, projection);
  234. }
  235. if (res) {
  236. props.pen.thumbImg = res.image;
  237. props.pen.calculative && (props.pen.calculative.img = null);
  238. }
  239. props.pen.onRenderPenRaw?.(props.pen);
  240. };
  241. const drawer = reactive<any>({
  242. visible: false,
  243. });
  244. const showDrawer = (item: any) => {
  245. drawer.key = item.key;
  246. drawer.header = `${item.label}(${item.key})`;
  247. drawer.value = deepClone(props.pen[item.key]);
  248. drawer.placeholder = item.placeholder;
  249. drawer.randomkey = s8(); //props.pen.id;
  250. drawer.visible = true;
  251. };
  252. const onConfirmDrawer = () => {
  253. if (!drawer.value) {
  254. MessagePlugin.error('数据不满足json格式');
  255. return;
  256. }
  257. props.pen[drawer.key] = drawer.value;
  258. updatePen(props.pen, drawer.key);
  259. };
  260. const cell = ref({
  261. col: undefined,
  262. row: undefined,
  263. background: undefined,
  264. textColor: undefined,
  265. fontSize: undefined,
  266. });
  267. const getPenData = (data: any) => {
  268. if (props.pen.name === 'tablePlus') {
  269. if (!props.pen.styles) {
  270. props.pen.styles = [];
  271. }
  272. if (props.pen.calculative.activeCell) {
  273. cell.value.col = props.pen.calculative.activeCell.col;
  274. cell.value.row = props.pen.calculative.activeCell.row;
  275. let found = props.pen.styles.findIndex((item: any) => {
  276. return item.row === cell.value.row && item.col === cell.value.col;
  277. });
  278. if (found !== -1) {
  279. cell.value.background = props.pen.styles[found].background;
  280. cell.value.textColor = props.pen.styles[found].textColor;
  281. cell.value.fontSize = props.pen.styles[found].fontSize;
  282. } else {
  283. cell.value.background = undefined;
  284. cell.value.textColor = undefined;
  285. cell.value.fontSize = undefined;
  286. }
  287. } else if (props.pen.calculative.activeCol) {
  288. cell.value.col = props.pen.calculative.activeCol;
  289. cell.value.row = undefined;
  290. let found = props.pen.styles.findIndex((item: any) => {
  291. return item.row === undefined && item.col === cell.value.col;
  292. });
  293. if (found !== -1) {
  294. cell.value.background = props.pen.styles[found].background;
  295. cell.value.textColor = props.pen.styles[found].textColor;
  296. cell.value.fontSize = props.pen.styles[found].fontSize;
  297. } else {
  298. cell.value.background = undefined;
  299. cell.value.textColor = undefined;
  300. cell.value.fontSize = undefined;
  301. }
  302. } else if (props.pen.calculative.activeRow) {
  303. cell.value.col = undefined;
  304. cell.value.row = props.pen.calculative.activeRow;
  305. let found = props.pen.styles.findIndex((item: any) => {
  306. return item.row === cell.value.row && item.col === undefined;
  307. });
  308. if (found !== -1) {
  309. cell.value.background = props.pen.styles[found].background;
  310. cell.value.textColor = props.pen.styles[found].textColor;
  311. cell.value.fontSize = props.pen.styles[found].fontSize;
  312. } else {
  313. cell.value.background = undefined;
  314. cell.value.textColor = undefined;
  315. cell.value.fontSize = undefined;
  316. }
  317. } else {
  318. cell.value.col = undefined;
  319. cell.value.row = undefined;
  320. cell.value.background = undefined;
  321. cell.value.textColor = undefined;
  322. cell.value.fontSize = undefined;
  323. }
  324. }
  325. };
  326. const changeStyles = (key) => {
  327. //更新属性
  328. if (!props.pen.styles) {
  329. props.pen.styles = [];
  330. }
  331. let found = props.pen.styles.findIndex((item: any) => {
  332. return item.row === cell.value.row && item.col === cell.value.col;
  333. });
  334. if (found !== -1) {
  335. props.pen.styles[found][key] = cell.value[key];
  336. } else {
  337. props.pen.styles.push({
  338. row: cell.value.row,
  339. col: cell.value.col,
  340. [key]: cell.value[key],
  341. });
  342. }
  343. };
  344. onMounted(() => {
  345. meta2d.on('click', getPenData);
  346. getPenData({});
  347. });
  348. onUnmounted(() => {
  349. meta2d.off('click', getPenData);
  350. });
  351. </script>
  352. <style lang="postcss" scoped>
  353. .form-cell {
  354. font-size: 13px;
  355. /* font-weight: 700; */
  356. color: var(--color);
  357. padding-top: 16px;
  358. padding-bottom: 8px;
  359. }
  360. </style>