index.vue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  1. <template>
  2. <div class="layout">
  3. <div
  4. v-if="toolIsShow"
  5. class="layout-left"
  6. :style="{ width: widthLeftForTools + 'px' }"
  7. >
  8. <el-tabs class="layout-left" type="border-card" :stretch="true">
  9. <!-- 左侧组件栏-->
  10. <el-tab-pane label="工具栏">
  11. <span slot="label"><i class="el-icon-date icon"></i>工具栏</span>
  12. <div class="chart-type">
  13. <el-tabs class="type-left" tab-position="left">
  14. <el-tab-pane
  15. v-for="(item, index) in widgetTools"
  16. :key="index"
  17. :label="item.name"
  18. >
  19. <li
  20. v-for="(it, idx) in item.list"
  21. :key="idx"
  22. draggable="true"
  23. @dragstart="dragStart(it.code)"
  24. @dragend="dragEnd()"
  25. >
  26. <div class="tools-item">
  27. <span class="tools-item-icon">
  28. <i class="iconfont" :class="it.icon"></i>
  29. </span>
  30. <span class="tools-item-text">{{ it.label }}</span>
  31. </div>
  32. </li>
  33. </el-tab-pane>
  34. </el-tabs>
  35. </div>
  36. </el-tab-pane>
  37. <!-- 左侧图层-->
  38. <el-tab-pane label="图层">
  39. <draggable
  40. v-model="layerWidget"
  41. @update="datadragEnd"
  42. :options="{ animation: 300 }"
  43. >
  44. <transition-group>
  45. <div
  46. v-for="(item, index) in layerWidget"
  47. :key="'item' + index"
  48. class="tools-item"
  49. :class="widgetIndex == index ? 'is-active' : ''"
  50. @click="layerClick(index)"
  51. >
  52. <span class="tools-item-icon">
  53. <i class="iconfont" :class="item.icon"></i>
  54. </span>
  55. <span class="tools-item-text">{{ item.label }}</span>
  56. </div>
  57. </transition-group>
  58. </draggable>
  59. </el-tab-pane>
  60. </el-tabs>
  61. </div>
  62. <div
  63. class="layout-left-fold"
  64. :style="{ width: widthLeftForToolsHideButton + 'px' }"
  65. @click="toolIsShow = !toolIsShow"
  66. >
  67. <i class="el-icon-arrow-right" />
  68. </div>
  69. <div
  70. class="layout-middle"
  71. :style="{ width: middleWidth + 'px', height: middleHeight + 'px' }"
  72. >
  73. <div class="top-button">
  74. <span class="btn" @click="saveData">
  75. <el-tooltip
  76. class="item"
  77. effect="dark"
  78. content="保存"
  79. placement="bottom"
  80. >
  81. <i class="iconfont iconsave"></i>
  82. </el-tooltip>
  83. </span>
  84. <span class="btn" @click="viewScreen">
  85. <el-tooltip
  86. class="item"
  87. effect="dark"
  88. content="预览"
  89. placement="bottom"
  90. >
  91. <i class="iconfont iconyulan"></i>
  92. </el-tooltip>
  93. </span>
  94. <span class="btn" @click="handleUndo">
  95. <el-tooltip
  96. class="item"
  97. effect="dark"
  98. content="撤销"
  99. placement="bottom"
  100. >
  101. <i class="iconfont iconundo"></i>
  102. </el-tooltip>
  103. </span>
  104. <span class="btn" @click="handleRedo">
  105. <el-tooltip
  106. class="item"
  107. effect="dark"
  108. content="恢复"
  109. placement="bottom"
  110. >
  111. <i class="iconfont iconhuifubeifen"></i>
  112. </el-tooltip>
  113. </span>
  114. <span
  115. :class="{
  116. btn: true,
  117. 'btn-disable': currentSizeRangeIndex === 0,
  118. }"
  119. @click="setSize(0)"
  120. >
  121. <el-tooltip
  122. class="item"
  123. :disabled="currentSizeRangeIndex === 0"
  124. effect="dark"
  125. content="缩小"
  126. placement="bottom"
  127. >
  128. <i class="el-icon-minus" style="font-size: 16px" />
  129. </el-tooltip>
  130. </span>
  131. <span
  132. :class="{
  133. btn: true,
  134. 'scale-num': true,
  135. 'btn-disable': currentSizeRangeIndex === defaultSize.index,
  136. }"
  137. @click="setSize(2)"
  138. >
  139. <el-tooltip
  140. class="item"
  141. :disabled="currentSizeRangeIndex === defaultSize.index"
  142. effect="dark"
  143. content="默认比例"
  144. placement="bottom"
  145. >
  146. <span> {{ parseInt(scaleNum) }}% </span>
  147. </el-tooltip>
  148. </span>
  149. <span
  150. :class="{
  151. btn: true,
  152. 'btn-disable': currentSizeRangeIndex === 8,
  153. }"
  154. @click="setSize(1)"
  155. >
  156. <el-tooltip
  157. class="item"
  158. :disabled="currentSizeRangeIndex === 8"
  159. effect="dark"
  160. content="放大"
  161. placement="bottom"
  162. >
  163. <i class="el-icon-plus" style="font-size: 16px" />
  164. </el-tooltip>
  165. </span>
  166. <span class="btn" v-permission="'bigScreenManage:export'">
  167. <el-tooltip
  168. class="item"
  169. effect="dark"
  170. content="导入"
  171. placement="bottom"
  172. >
  173. <el-upload
  174. class="el-upload"
  175. ref="upload"
  176. :action="uploadUrl"
  177. :headers="headers"
  178. accept=".zip"
  179. :on-success="handleUpload"
  180. :on-error="handleError"
  181. :show-file-list="false"
  182. :limit="1"
  183. >
  184. <i class="iconfont icondaoru"></i>
  185. </el-upload>
  186. </el-tooltip>
  187. </span>
  188. <span class="btn border-left" v-permission="'bigScreenManage:import'">
  189. <ul class="nav">
  190. <li>
  191. <i class="iconfont icondaochu"></i
  192. ><i class="el-icon-arrow-down"></i>
  193. <ul>
  194. <li>
  195. <el-tooltip
  196. class="item"
  197. effect="dark"
  198. content="适合当前系统"
  199. placement="right"
  200. >
  201. <div @click="exportDashboard(1)">导出(包含数据集)</div>
  202. </el-tooltip>
  203. </li>
  204. <li>
  205. <el-tooltip
  206. class="item"
  207. effect="dark"
  208. content="适合跨系统"
  209. placement="right"
  210. >
  211. <div @click="exportDashboard(0)">导出(不包含数据集)</div>
  212. </el-tooltip>
  213. </li>
  214. </ul>
  215. </li>
  216. </ul>
  217. </span>
  218. </div>
  219. <!-- 中间操作内容 主体 -->
  220. <div class="workbench-container" @mousedown="handleMouseDown">
  221. <div
  222. :style="{
  223. width: (+bigscreenWidth + 18) * bigscreenScaleInWorkbench + 'px',
  224. height: (+bigscreenHeight + 18) * bigscreenScaleInWorkbench + 'px',
  225. }"
  226. class="vue-ruler-tool-wrap"
  227. >
  228. <!-- 大屏设计页面的标尺插件 -->
  229. <vue-ruler-tool
  230. ref="vue-ruler-tool"
  231. v-model="dashboard.presetLine"
  232. class="vueRuler"
  233. :step-length="50"
  234. :parent="true"
  235. :position="'relative'"
  236. :is-scale-revise="true"
  237. :visible.sync="dashboard.presetLineVisible"
  238. :style="{
  239. width: +bigscreenWidth + 18 + 'px',
  240. height: +bigscreenHeight + 18 + 'px',
  241. transform:
  242. currentSizeRangeIndex === defaultSize.index
  243. ? workbenchTransform
  244. : `scale(${sizeRange[currentSizeRangeIndex] / 100})`,
  245. transformOrigin: '0 0',
  246. }"
  247. >
  248. <div
  249. id="workbench"
  250. class="workbench"
  251. :style="{
  252. width: bigscreenWidth + 'px',
  253. height: bigscreenHeight + 'px',
  254. 'background-color': dashboard.backgroundColor,
  255. 'background-image': 'url(' + dashboard.backgroundImage + ')',
  256. 'background-position': '0% 0%',
  257. 'background-size': '100% 100%',
  258. 'background-repeat': 'initial',
  259. 'background-attachment': 'initial',
  260. 'background-origin': 'initial',
  261. 'background-clip': 'initial',
  262. }"
  263. @click.self="setOptionsOnClickScreen"
  264. @drop="widgetOnDragged($event)"
  265. @dragover="dragOver($event)"
  266. >
  267. <div v-if="grade" class="bg-grid"></div>
  268. <widget
  269. ref="widgets"
  270. v-for="(widget, index) in widgets"
  271. :key="index"
  272. v-model="widget.value"
  273. :index="index"
  274. :step="step"
  275. :type="widget.type"
  276. :bigscreen="{ bigscreenWidth, bigscreenHeight }"
  277. @onActivated="setOptionsOnClickWidget"
  278. @contextmenu.prevent.native="rightClick($event, index)"
  279. @mousedown.prevent.native="widgetsClick(index)"
  280. @mouseup.prevent.native="widgetsMouseup"
  281. />
  282. </div>
  283. </vue-ruler-tool>
  284. </div>
  285. </div>
  286. </div>
  287. <div class="layout-right" :style="{ width: widthLeftForOptions + 'px' }">
  288. <el-tabs v-model="activeName" type="border-card" :stretch="true">
  289. <el-tab-pane
  290. v-if="
  291. isNotNull(widgetOptions.setup) || isNotNull(widgetOptions.collapse)
  292. "
  293. name="first"
  294. label="配置"
  295. >
  296. <dynamicForm
  297. ref="formData"
  298. :options="widgetOptions.setup"
  299. :layer-widget="layerWidget"
  300. :widget-index="widgetIndex"
  301. :widget-params-config="widgetParamsConfig"
  302. @onChanged="(val) => widgetValueChanged('setup', val)"
  303. />
  304. </el-tab-pane>
  305. <el-tab-pane
  306. v-if="isNotNull(widgetOptions.data)"
  307. name="second"
  308. label="数据"
  309. >
  310. <dynamicForm
  311. ref="formData"
  312. :options="widgetOptions.data"
  313. @onChanged="(val) => widgetValueChanged('data', val)"
  314. />
  315. </el-tab-pane>
  316. <el-tab-pane
  317. v-if="isNotNull(widgetOptions.position)"
  318. name="third"
  319. label="坐标"
  320. >
  321. <dynamicForm
  322. ref="formData"
  323. :options="widgetOptions.position"
  324. @onChanged="(val) => widgetValueChanged('position', val)"
  325. />
  326. </el-tab-pane>
  327. </el-tabs>
  328. </div>
  329. <content-menu
  330. :visible.sync="visibleContentMenu"
  331. :style-obj="styleObj"
  332. @deletelayer="deletelayer"
  333. @lockLayer="lockLayer"
  334. @noLockLayer="noLockLayer"
  335. @copylayer="copylayer"
  336. @istopLayer="istopLayer"
  337. @setlowLayer="setlowLayer"
  338. @moveupLayer="moveupLayer"
  339. @movedownLayer="movedownLayer"
  340. />
  341. </div>
  342. </template>
  343. <script>
  344. import { widgetTools, getToolByCode } from "./tools/index";
  345. import mixin from "@/utils/screenMixins";
  346. import widget from "./widget/widget.vue";
  347. import dynamicForm from "./components/dynamicForm.vue";
  348. import draggable from "vuedraggable";
  349. import VueRulerTool from "vue-ruler-tool"; // 大屏设计页面的标尺插件
  350. import contentMenu from "./components/contentMenu";
  351. export default {
  352. name: "Login",
  353. components: {
  354. draggable,
  355. VueRulerTool,
  356. widget,
  357. dynamicForm,
  358. contentMenu,
  359. },
  360. mixins: [mixin],
  361. data() {
  362. return {
  363. grade: false,
  364. layerWidget: [],
  365. widgetTools: widgetTools, // 左侧工具栏的组件图标,将js变量加入到当前作用域
  366. widthLeftForTools: 200, // 左侧工具栏宽度
  367. widthLeftForToolsHideButton: 15, // 左侧工具栏折叠按钮宽度
  368. widthLeftForOptions: 300, // 右侧属性配置区
  369. widthPaddingTools: 18,
  370. toolIsShow: true, // 左侧工具栏是否显示
  371. bigscreenWidth: 1920, // 大屏设计的大小
  372. bigscreenHeight: 1080,
  373. revoke: null, //处理历史记录 2022-02-22
  374. dashboard: {},
  375. // 大屏的标记
  376. screenCode: "",
  377. dragWidgetCode: "", //从工具栏拖拽的组件code
  378. // 大屏画布中的组件
  379. widgets: [
  380. {
  381. // type和value最终存到数据库中去,保存到gaea_report_dashboard_widget中
  382. type: "widget-text",
  383. value: {
  384. setup: {},
  385. data: {},
  386. position: {
  387. width: 100,
  388. height: 100,
  389. left: 0,
  390. top: 0,
  391. zIndex: 0,
  392. },
  393. },
  394. // options属性是从工具栏中拿到的tools中拿到
  395. options: [],
  396. },
  397. ], // 工作区中拖放的组件
  398. // 当前激活组件
  399. widgetIndex: 0,
  400. // 当前激活组件右侧配置属性
  401. widgetOptions: {
  402. setup: [], // 配置
  403. data: [], // 数据
  404. position: [], // 坐标
  405. },
  406. flagWidgetClickStopPropagation: false, // 点击组件时阻止事件冒泡传递到画布click事件上
  407. styleObj: {
  408. left: 0,
  409. top: 0,
  410. },
  411. visibleContentMenu: false,
  412. activeName: "first",
  413. scaleNum: 0, // 当前缩放百分比的值
  414. sizeRange: [20, 40, 60, 80, 100, 150, 200, 300, 400], // 缩放百分比
  415. currentSizeRangeIndex: -1, // 当前是哪个缩放比分比,
  416. currentWidgetTotal: 0,
  417. widgetParamsConfig: [], // 各组件动态数据集的参数配置情况
  418. };
  419. },
  420. computed: {
  421. // 左侧折叠切换时,动态计算中间区的宽度
  422. middleWidth() {
  423. let widthLeftAndRight = 0;
  424. if (this.toolIsShow) {
  425. widthLeftAndRight += this.widthLeftForTools; // 左侧工具栏宽度
  426. }
  427. widthLeftAndRight += this.widthLeftForToolsHideButton; // 左侧工具栏折叠按钮宽度
  428. widthLeftAndRight += this.widthLeftForOptions; // 右侧配置栏宽度
  429. let middleWidth = this.bodyWidth - widthLeftAndRight;
  430. return middleWidth;
  431. },
  432. middleHeight() {
  433. return this.bodyHeight;
  434. },
  435. // 设计台按大屏的缩放比例
  436. bigscreenScaleInWorkbench() {
  437. let widthScale =
  438. (this.middleWidth - this.widthPaddingTools) / this.bigscreenWidth;
  439. let heightScale =
  440. (this.middleHeight - this.widthPaddingTools) / this.bigscreenHeight;
  441. return Math.min(widthScale, heightScale);
  442. },
  443. workbenchTransform() {
  444. return `scale(${this.bigscreenScaleInWorkbench}, ${this.bigscreenScaleInWorkbench})`;
  445. },
  446. // 大屏在设计模式的大小
  447. bigscreenWidthInWorkbench() {
  448. return this.getPXUnderScale(this.bigscreenWidth) + this.widthPaddingTools;
  449. },
  450. bigscreenHeightInWorkbench() {
  451. return (
  452. this.getPXUnderScale(this.bigscreenHeight) + this.widthPaddingTools
  453. );
  454. },
  455. },
  456. watch: {
  457. widgets: {
  458. handler(val) {
  459. this.handlerLayerWidget(val);
  460. this.handlerdynamicDataParamsConfig(val);
  461. //以下部分是记录历史
  462. this.$nextTick(() => {
  463. this.revoke.push(this.widgets);
  464. });
  465. },
  466. deep: true,
  467. },
  468. },
  469. mounted() {
  470. this.widgets = [];
  471. window.addEventListener("mouseup", () => {
  472. this.grade = false;
  473. });
  474. this.$nextTick(() => {
  475. this.initVueRulerTool(); // 初始化 修正插件样式
  476. });
  477. },
  478. methods: {
  479. handlerLayerWidget(val) {
  480. const layerWidgetArr = [];
  481. for (let i = 0; i < val.length; i++) {
  482. const obj = {};
  483. const myItem = getToolByCode(val[i].type);
  484. obj.icon = myItem.icon;
  485. obj.code = myItem.code; // 组件类型code
  486. obj.widgetId = val[i].value.widgetId || ""; // 唯一id
  487. if (val[i].value.paramsKeys) {
  488. obj.paramsKeys = val[i].value.paramsKeys;
  489. }
  490. const options = val[i].options["setup"];
  491. options.forEach((el) => {
  492. if (el.name == "layerName") {
  493. obj.label = el.value;
  494. }
  495. });
  496. layerWidgetArr.push(obj);
  497. }
  498. this.layerWidget = layerWidgetArr;
  499. },
  500. // 返回每个组件的动态数据集参数配置情况
  501. handlerdynamicDataParamsConfig(val) {
  502. this.widgetParamsConfig = val.map((item) => {
  503. return item.value.data;
  504. });
  505. },
  506. handleBigScreen(data) {
  507. const optionScreen = getToolByCode("screen").options;
  508. const setup = optionScreen.setup;
  509. for (const key in data) {
  510. for (let i = 0; i < setup.length; i++) {
  511. if (key == setup[i].name) {
  512. setup[i].value = data[key];
  513. }
  514. }
  515. }
  516. this.setOptionsOnClickScreen();
  517. return {
  518. backgroundColor:
  519. (data && data.backgroundColor) || (!data ? "#1e1e1e" : ""),
  520. backgroundImage: (data && data.backgroundImage) || "",
  521. height: (data && data.height) || "1080",
  522. title: (data && data.title) || "",
  523. width: (data && data.width) || "1920",
  524. };
  525. },
  526. handleInitEchartsData(data) {
  527. const widgets = data.dashboard ? data.dashboard.widgets : [];
  528. const widgetsData = [];
  529. for (let i = 0; i < widgets.length; i++) {
  530. let obj = {};
  531. obj.type = widgets[i].type;
  532. obj.value = {
  533. setup: widgets[i].value.setup,
  534. data: widgets[i].value.data,
  535. position: widgets[i].value.position,
  536. };
  537. const tool = this.deepClone(getToolByCode(widgets[i].type));
  538. if (!tool) {
  539. const message =
  540. "暂未提供该组件或该组件下线了,组件code: " + widgets[i].type;
  541. console.error(message);
  542. if (process.env.NODE_ENV === "development") {
  543. // 40@remarks 看生产要不要提示
  544. this.$message.error(message);
  545. }
  546. continue; // 找不到就跳过,避免整个报表都加载不出来
  547. }
  548. const option = tool.options;
  549. const options = this.handleOptionsData(widgets[i].value, option);
  550. obj.options = options;
  551. obj.value.widgetId = obj.value.setup.widgetId;
  552. widgetsData.push(obj);
  553. }
  554. return widgetsData;
  555. },
  556. handleOptionsData(data, option) {
  557. for (const key in data.setup) {
  558. for (let i = 0; i < option.setup.length; i++) {
  559. let item = option.setup[i];
  560. if (this.isObjectFn(item)) {
  561. if (key == option.setup[i].name) {
  562. option.setup[i].value = data.setup[key];
  563. }
  564. } else if (this.isArrayFn(item)) {
  565. for (let j = 0; j < item.length; j++) {
  566. const list = item[j].list;
  567. list.forEach((el) => {
  568. if (key == el.name) {
  569. el.value = data.setup[key];
  570. }
  571. });
  572. }
  573. }
  574. }
  575. }
  576. // position
  577. for (const key in data.position) {
  578. for (let i = 0; i < option.position.length; i++) {
  579. if (key == option.position[i].name) {
  580. option.position[i].value = data.position[key];
  581. }
  582. }
  583. }
  584. // data
  585. for (const key in data.data) {
  586. for (let i = 0; i < option.data.length; i++) {
  587. if (key == option.data[i].name) {
  588. option.data[i].value = data.data[key];
  589. }
  590. }
  591. }
  592. return option;
  593. },
  594. // 在缩放模式下的大小
  595. getPXUnderScale(px) {
  596. return this.bigscreenScaleInWorkbench * px;
  597. },
  598. dragStart(widgetCode) {
  599. this.dragWidgetCode = widgetCode;
  600. this.currentWidgetTotal = this.widgets.length; // 当前操作面板上有多少各组件
  601. },
  602. dragEnd() {
  603. this.dragWidgetCode = "";
  604. /**
  605. * 40@remarks 新增组件到操作面板后,右边的配置有更新,但是当前选中的组件没更新,导致配置错乱的bug;
  606. * 由于拖动组件拖到非操作面板上是不会添加组件,还需判断是否添加组件到操作面板上;
  607. */
  608. this.$nextTick(() => {
  609. if (this.widgets.length === this.currentWidgetTotal + 1) {
  610. // 确实新增了一个组件到操作面板上
  611. console.log(
  612. `新添加 '${
  613. this.widgets[this.currentWidgetTotal].value.setup.layerName
  614. }' 组件到操作面板`
  615. );
  616. const uuid = Number(Math.random().toString().substr(2)).toString(36);
  617. this.widgets[this.currentWidgetTotal].value.widgetId = uuid;
  618. this.layerWidget[this.currentWidgetTotal].widgetId = uuid;
  619. const index = this.widgets.length - 1;
  620. this.layerClick(index); // 选中当前新增的组件
  621. this.grade = false; // 去除网格线
  622. }
  623. });
  624. },
  625. dragOver(evt) {
  626. evt.preventDefault();
  627. evt.stopPropagation();
  628. evt.dataTransfer.dropEffect = "copy";
  629. },
  630. // 拖动一个组件放到工作区中去,在拖动结束时,放到工作区对应的坐标点上去
  631. widgetOnDragged(evt) {
  632. let widgetType = this.dragWidgetCode;
  633. // 获取结束坐标和列名
  634. let eventX = evt.clientX; // 结束在屏幕的x坐标
  635. let eventY = evt.clientY; // 结束在屏幕的y坐标
  636. let workbenchPosition = this.getDomTopLeftById("workbench");
  637. let widgetTopInWorkbench = eventY - workbenchPosition.top;
  638. let widgetLeftInWorkbench = eventX - workbenchPosition.left;
  639. const targetScale =
  640. this.currentSizeRangeIndex === this.defaultSize.index
  641. ? this.bigscreenScaleInWorkbench
  642. : this.sizeRange[this.currentSizeRangeIndex] / 100;
  643. // 计算在缩放模式下的x y
  644. // const x = widgetLeftInWorkbench / this.bigscreenScaleInWorkbench
  645. // const y = widgetTopInWorkbench / this.bigscreenScaleInWorkbench
  646. const x = widgetLeftInWorkbench / targetScale;
  647. const y = widgetTopInWorkbench / targetScale;
  648. // 复制一个组件
  649. let tool = getToolByCode(widgetType);
  650. let widgetJson = {
  651. type: widgetType,
  652. value: {
  653. setup: {},
  654. data: {},
  655. position: {
  656. width: 0,
  657. height: 0,
  658. left: 0,
  659. top: 0,
  660. zIndex: 0,
  661. },
  662. },
  663. options: tool.options,
  664. };
  665. // 处理默认值
  666. const widgetJsonValue = this.handleDefaultValue(widgetJson);
  667. //2022年02月22日 修复:可以拖拽放到鼠标的位置
  668. widgetJsonValue.value.position.left =
  669. x - widgetJsonValue.value.position.width / 2;
  670. widgetJsonValue.value.position.top =
  671. y - widgetJsonValue.value.position.height / 2;
  672. // 将选中的复制组件,放到工作区中去
  673. this.widgets.push(this.deepClone(widgetJsonValue));
  674. // 激活新组件的配置属性
  675. this.setOptionsOnClickWidget(this.widgets.length - 1);
  676. },
  677. // 对组件默认值处理
  678. handleDefaultValue(widgetJson) {
  679. console.log(widgetJson);
  680. for (const key in widgetJson) {
  681. if (key == "options") {
  682. // collapse、data、position、setup
  683. // setup 处理
  684. for (let i = 0; i < widgetJson.options.setup.length; i++) {
  685. const item = widgetJson.options.setup[i];
  686. if (this.isObjectFn(item)) {
  687. widgetJson.value.setup[item.name] = item.value;
  688. } else if (this.isArrayFn(item)) {
  689. for (let j = 0; j < item.length; j++) {
  690. const list = item[j].list;
  691. list.forEach((el) => {
  692. widgetJson.value.setup[el.name] = el.value;
  693. });
  694. }
  695. }
  696. }
  697. // position
  698. for (let i = 0; i < widgetJson.options.position.length; i++) {
  699. const item = widgetJson.options.position[i];
  700. if (item.value) {
  701. widgetJson.value.position[item.name] = item.value;
  702. }
  703. }
  704. // data 处理
  705. if (widgetJson.options.data && widgetJson.options.data.length > 0) {
  706. for (let i = 0; i < widgetJson.options.data.length; i++) {
  707. const item = widgetJson.options.data[i];
  708. if (item.value) {
  709. widgetJson.value.data[item.name] = item.value;
  710. }
  711. }
  712. }
  713. }
  714. }
  715. return widgetJson;
  716. },
  717. layerClick(index) {
  718. this.widgetIndex = index;
  719. this.widgetsClick(index);
  720. },
  721. // 如果是点击大屏设计器中的底层,加载大屏底层属性
  722. setOptionsOnClickScreen() {
  723. this.screenCode = "screen";
  724. // 选中不同的组件 右侧都显示第一栏
  725. this.activeName = "first";
  726. this.widgetOptions = getToolByCode("screen")["options"];
  727. },
  728. // 如果是点击某个组件,获取该组件的配置项
  729. setOptionsOnClickWidget(obj) {
  730. this.screenCode = "";
  731. if (typeof obj == "number") {
  732. this.widgetOptions = this.deepClone(this.widgets[obj]["options"]);
  733. return;
  734. }
  735. if (obj.index < 0 || obj.index >= this.widgets.length) {
  736. return;
  737. }
  738. this.widgetIndex = obj.index;
  739. this.widgets[obj.index].value.position = obj;
  740. this.widgets[obj.index].options.position.forEach((el) => {
  741. for (const key in obj) {
  742. if (el.name == key) {
  743. el.value = obj[key];
  744. }
  745. }
  746. });
  747. this.widgetOptions = this.deepClone(this.widgets[obj.index]["options"]);
  748. },
  749. widgetsClick(index) {
  750. const draggableArr = this.$refs.widgets;
  751. for (let i = 0; i < draggableArr.length; i++) {
  752. if (i == index) {
  753. this.$refs.widgets[i].$refs.draggable.setActive(true);
  754. } else {
  755. this.$refs.widgets[i].$refs.draggable.setActive(false);
  756. }
  757. }
  758. this.setOptionsOnClickWidget(index);
  759. this.grade = true;
  760. },
  761. widgetsMouseup(e) {
  762. this.grade = false;
  763. },
  764. handleMouseDown() {
  765. const draggableArr = this.$refs.widgets;
  766. for (let i = 0; i < draggableArr.length; i++) {
  767. this.$refs.widgets[i].$refs.draggable.setActive(false);
  768. }
  769. },
  770. // 将当前选中的组件,右侧属性值更新
  771. widgetValueChanged(key, val) {
  772. console.log("key", key);
  773. console.log("val", val);
  774. console.log(this.widgetOptions);
  775. if (this.screenCode == "screen") {
  776. let newSetup = [];
  777. this.dashboard = this.deepClone(val);
  778. console.log("asd", this.dashboard);
  779. console.log(this.widgetOptions);
  780. if (this.bigscreenWidth != this.dashboard.width) {
  781. this.bigscreenWidth = this.dashboard.width;
  782. }
  783. if (this.bigscreenHeight != this.dashboard.height) {
  784. this.bigscreenHeight = this.dashboard.height;
  785. }
  786. this.widgetOptions.setup.forEach((el) => {
  787. if (el.name == "width") {
  788. el.value = this.bigscreenWidth;
  789. } else if (el.name == "height") {
  790. el.value = this.bigscreenHeight;
  791. } else if (this.dashboard.hasOwnProperty(el.name)) {
  792. el["value"] = this.dashboard[el.name];
  793. }
  794. newSetup.push(el);
  795. });
  796. console.log(newSetup);
  797. this.widgetOptions.setup = newSetup;
  798. } else {
  799. for (let i = 0; i < this.widgets.length; i++) {
  800. if (this.widgetIndex == i) {
  801. this.widgets[i].value[key] = this.deepClone(val);
  802. this.setDefaultValue(this.widgets[i].options[key], val);
  803. }
  804. }
  805. }
  806. },
  807. setDefaultValue(options, val) {
  808. for (let i = 0; i < options.length; i++) {
  809. if (this.isObjectFn(options[i])) {
  810. for (const k in val) {
  811. if (options[i].name == k) {
  812. options[i].value = val[k];
  813. }
  814. }
  815. } else if (this.isArrayFn(options[i])) {
  816. for (let j = 0; j < options[i].length; j++) {
  817. const list = options[i][j].list;
  818. for (let z = 0; z < list.length; z++) {
  819. for (const k in val) {
  820. if (list[z].name == k) {
  821. list[z].value = val[k];
  822. }
  823. }
  824. }
  825. }
  826. }
  827. }
  828. },
  829. datadragEnd(evt) {
  830. evt.preventDefault();
  831. this.widgets = this.swapArr(this.widgets, evt.oldIndex, evt.newIndex);
  832. },
  833. },
  834. };
  835. </script>
  836. <style scoped lang="scss">
  837. @import "@/assets/styles/screen.scss";
  838. </style>