index.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. <template>
  2. <div class="layout">
  3. <!-- 操作栏 -->
  4. <div class="layout-bar">
  5. <div class="bar-item" @click="saveData">
  6. <i class="iconfont iconsave"></i>保存
  7. </div>
  8. <div class="bar-item" @click="viewScreen">
  9. <i class="iconfont iconyulan"></i>预览
  10. </div>
  11. <div class="bar-item" @click="handleUndo">
  12. <i class="iconfont iconundo"></i>撤销
  13. </div>
  14. <div class="bar-item" @click="handleRedo">
  15. <i class="iconfont iconhuifubeifen"></i>恢复
  16. </div>
  17. <div class="bar-item">
  18. <el-upload
  19. class="el-upload"
  20. ref="upload"
  21. :action="uploadUrl"
  22. :headers="headers"
  23. accept=".zip"
  24. :on-success="handleUpload"
  25. :on-error="handleError"
  26. :show-file-list="false"
  27. :limit="1"
  28. >
  29. <i class="iconfont icondaoru"></i>
  30. </el-upload>
  31. 导入
  32. </div>
  33. <div class="bar-item">
  34. <i class="iconfont icondaochu"></i>
  35. <el-dropdown @command="exportDashboard">
  36. <span class="el-dropdown-link">
  37. 导出<i class="el-icon-arrow-down el-icon--right"></i>
  38. </span>
  39. <el-dropdown-menu slot="dropdown">
  40. <el-dropdown-item command="1">导出(包含数据集)</el-dropdown-item>
  41. <el-dropdown-item command="0">导出(不包含数据集)</el-dropdown-item>
  42. </el-dropdown-menu>
  43. </el-dropdown>
  44. </div>
  45. </div>
  46. <div class="layout-container">
  47. <!-- 图表 -->
  48. <el-tabs class="layout-left" type="border-card">
  49. <el-tab-pane>
  50. <span slot="label"><i class="el-icon-date icon"></i>工具栏</span>
  51. <div class="chart-type">
  52. <el-tabs class="type-left" tab-position="left">
  53. <el-tab-pane
  54. v-for="(item, index) in widgetTools"
  55. :key="index"
  56. :label="item.name"
  57. >
  58. <draggable
  59. v-for="(it, idx) in item.list"
  60. :key="idx"
  61. @end="evt => widgetOnDragged(evt, it.code)"
  62. >
  63. <div class="tools-item">
  64. <span class="tools-item-icon">
  65. <i class="iconfont" :class="it.icon"></i>
  66. </span>
  67. <span class="tools-item-text">{{ it.label }}</span>
  68. </div>
  69. </draggable>
  70. </el-tab-pane>
  71. </el-tabs>
  72. </div>
  73. </el-tab-pane>
  74. <el-tab-pane>
  75. <span slot="label" class="icon"
  76. ><i class="el-icon-date icon"></i>图层</span
  77. >
  78. <div
  79. v-for="(item, index) in layerWidget"
  80. :key="'item' + index"
  81. class="tools-item"
  82. :class="widgetIndex == index ? 'is-active' : ''"
  83. @click="layerClick(index)"
  84. >
  85. <span class="tools-item-icon">
  86. <i class="iconfont" :class="item.icon"></i>
  87. </span>
  88. <span class="tools-item-text">{{ item.label }}</span>
  89. </div>
  90. </el-tab-pane>
  91. </el-tabs>
  92. <!-- 设计器 -->
  93. <div
  94. class="layout-middle"
  95. :style="{ width: middleWidth + 'px', height: middleHeight + 'px' }"
  96. >
  97. <div
  98. class="workbench-container"
  99. :style="{
  100. width: bigscreenWidthInWorkbench + 'px',
  101. height: bigscreenHeightInWorkbench + 'px'
  102. }"
  103. @mousedown="handleMouseDown"
  104. >
  105. <vue-ruler-tool
  106. v-model="dashboard.presetLine"
  107. class="vueRuler"
  108. :step-length="50"
  109. :parent="true"
  110. :position="'relative'"
  111. :is-scale-revise="true"
  112. :visible.sync="dashboard.presetLineVisible"
  113. >
  114. <div
  115. id="workbench"
  116. class="workbench"
  117. :style="{
  118. transform: workbenchTransform,
  119. width: bigscreenWidth + 'px',
  120. height: bigscreenHeight + 'px',
  121. 'background-color': dashboard.backgroundColor,
  122. 'background-image': 'url(' + dashboard.backgroundImage + ')',
  123. 'background-position': '0% 0%',
  124. 'background-size': '100% 100%',
  125. 'background-repeat': 'initial',
  126. 'background-attachment': 'initial',
  127. 'background-origin': 'initial',
  128. 'background-clip': 'initial'
  129. }"
  130. @click.self="setOptionsOnClickScreen"
  131. >
  132. <div v-if="grade" class="bg-grid"></div>
  133. <widget
  134. ref="widgets"
  135. v-for="(widget, index) in widgets"
  136. :key="index"
  137. v-model="widget.value"
  138. :index="index"
  139. :step="step"
  140. :type="widget.type"
  141. :bigscreen="{ bigscreenWidth, bigscreenHeight }"
  142. @onActivated="setOptionsOnClickWidget"
  143. @contextmenu.prevent.native="rightClick($event, index)"
  144. @mousedown.prevent.native="widgetsClick(index)"
  145. @mouseup.prevent.native="widgetsMouseup"
  146. />
  147. </div>
  148. </vue-ruler-tool>
  149. </div>
  150. </div>
  151. <!-- 设置 -->
  152. <div class="layout-right">
  153. <el-tabs v-model="activeName" type="border-card" :stretch="true">
  154. <el-tab-pane
  155. v-if="
  156. isNotNull(widgetOptions.setup) ||
  157. isNotNull(widgetOptions.collapse)
  158. "
  159. name="first"
  160. label="配置"
  161. >
  162. <dynamicForm
  163. ref="formData"
  164. :options="widgetOptions.setup"
  165. @onChanged="val => widgetValueChanged('setup', val)"
  166. />
  167. </el-tab-pane>
  168. <el-tab-pane
  169. v-if="isNotNull(widgetOptions.data)"
  170. name="second"
  171. label="数据"
  172. >
  173. <dynamicForm
  174. ref="formData"
  175. :options="widgetOptions.data"
  176. @onChanged="val => widgetValueChanged('data', val)"
  177. />
  178. </el-tab-pane>
  179. <el-tab-pane
  180. v-if="isNotNull(widgetOptions.position)"
  181. name="third"
  182. label="坐标"
  183. >
  184. <dynamicForm
  185. ref="formData"
  186. :options="widgetOptions.position"
  187. @onChanged="val => widgetValueChanged('position', val)"
  188. />
  189. </el-tab-pane>
  190. </el-tabs>
  191. </div>
  192. </div>
  193. <content-menu
  194. :visible.sync="visibleContentMenu"
  195. :style-obj="styleObj"
  196. @deletelayer="deletelayer"
  197. @copylayer="copylayer"
  198. @istopLayer="istopLayer"
  199. @setlowLayer="setlowLayer"
  200. @moveupLayer="moveupLayer"
  201. @movedownLayer="movedownLayer"
  202. />
  203. </div>
  204. </template>
  205. <script>
  206. import {
  207. insertDashboard,
  208. detailDashboard,
  209. importDashboard,
  210. exportDashboard
  211. } from "@/api/bigscreen";
  212. import {
  213. swapArr,
  214. setDefaultValue,
  215. handleDefaultValue,
  216. getPXUnderScale,
  217. handleInitEchartsData,
  218. handleBigScreen,
  219. handlerLayerWidget
  220. } from "./util/screen";
  221. import { screenConfig } from "./config/texts/screenConfig.js";
  222. import { widgetTools, getToolByCode } from "./config/index.js";
  223. import VueRulerTool from "vue-ruler-tool"; // 大屏设计页面的标尺插件
  224. import widget from "./widget/index.vue";
  225. import dynamicForm from "./components/dynamicForm.vue";
  226. import draggable from "vuedraggable";
  227. import contentMenu from "./components/contentMenu";
  228. import { getToken } from "@/utils/auth";
  229. import { Revoke } from "@/utils/revoke"; //处理历史记录 2022-02-22
  230. export default {
  231. components: {
  232. VueRulerTool,
  233. widget,
  234. dynamicForm,
  235. draggable,
  236. contentMenu
  237. },
  238. data() {
  239. return {
  240. uploadUrl:
  241. process.env.BASE_API +
  242. "/reportDashboard/import/" +
  243. this.$route.query.reportCode,
  244. grade: false,
  245. layerWidget: [],
  246. widgetTools: widgetTools, // 左侧工具栏的组件图标,将js变量加入到当前作用域
  247. widthLeftForTools: 200, // 左侧工具栏宽度
  248. widthLeftForToolsHideButton: 15, // 左侧工具栏折叠按钮宽度
  249. widthLeftForOptions: 300, // 右侧属性配置区
  250. widthPaddingTools: 18,
  251. toolIsShow: true, // 左侧工具栏是否显示
  252. bigscreenWidth: 1920, // 大屏设计的大小
  253. bigscreenHeight: 1080,
  254. revoke: null, //处理历史记录 2022-02-22
  255. // 工作台大屏画布,保存到表gaea_report_dashboard中
  256. dashboard: {
  257. id: null,
  258. title: "", // 大屏页面标题
  259. width: 1920, // 大屏设计宽度
  260. height: 1080, // 大屏设计高度
  261. backgroundColor: "", // 大屏背景色
  262. backgroundImage: "", // 大屏背景图片
  263. refreshSeconds: null, // 大屏刷新时间间隔
  264. presetLine: [], // 辅助线
  265. presetLineVisible: true // 辅助线是否显示
  266. },
  267. // 大屏的标记
  268. screenCode: "",
  269. // 大屏画布中的组件
  270. widgets: [
  271. {
  272. // type和value最终存到数据库中去,保存到gaea_report_dashboard_widget中
  273. type: "widget-text",
  274. value: {
  275. setup: {},
  276. data: {},
  277. position: {
  278. width: 100,
  279. height: 100,
  280. left: 0,
  281. top: 0,
  282. zIndex: 0
  283. }
  284. },
  285. // options属性是从工具栏中拿到的tools中拿到
  286. options: []
  287. }
  288. ], // 工作区中拖放的组件
  289. // 当前激活组件
  290. widgetIndex: 0,
  291. // 当前激活组件右侧配置属性
  292. widgetOptions: {
  293. setup: [], // 配置
  294. data: [], // 数据
  295. position: [] // 坐标
  296. },
  297. flagWidgetClickStopPropagation: false, // 点击组件时阻止事件冒泡传递到画布click事件上
  298. styleObj: {
  299. left: 0,
  300. top: 0
  301. },
  302. visibleContentMenu: false,
  303. rightClickIndex: -1,
  304. activeName: "first"
  305. };
  306. },
  307. computed: {
  308. step() {
  309. return Number(100 / (this.bigscreenScaleInWorkbench * 100));
  310. },
  311. headers() {
  312. return {
  313. Authorization: getToken() // 直接从本地获取token就行
  314. };
  315. },
  316. // 左侧折叠切换时,动态计算中间区的宽度
  317. middleWidth() {
  318. let widthLeftAndRight = 0;
  319. if (this.toolIsShow) {
  320. widthLeftAndRight += this.widthLeftForTools; // 左侧工具栏宽度
  321. }
  322. widthLeftAndRight += this.widthLeftForToolsHideButton; // 左侧工具栏折叠按钮宽度
  323. widthLeftAndRight += this.widthLeftForOptions; // 右侧配置栏宽度
  324. let middleWidth = this.bodyWidth - widthLeftAndRight;
  325. return middleWidth;
  326. },
  327. middleHeight() {
  328. return this.bodyHeight;
  329. },
  330. // 设计台按大屏的缩放比例
  331. bigscreenScaleInWorkbench() {
  332. let widthScale =
  333. (this.middleWidth - this.widthPaddingTools) / this.bigscreenWidth;
  334. let heightScale =
  335. (this.middleHeight - this.widthPaddingTools) / this.bigscreenHeight;
  336. return Math.min(widthScale, heightScale);
  337. },
  338. workbenchTransform() {
  339. return `scale(${this.bigscreenScaleInWorkbench}, ${
  340. this.bigscreenScaleInWorkbench
  341. })`;
  342. },
  343. // 大屏在设计模式的大小
  344. bigscreenWidthInWorkbench() {
  345. return (
  346. getPXUnderScale(this.bigscreenScaleInWorkbench, this.bigscreenWidth) +
  347. this.widthPaddingTools
  348. );
  349. },
  350. bigscreenHeightInWorkbench() {
  351. return (
  352. getPXUnderScale(this.bigscreenScaleInWorkbench, this.bigscreenHeight) +
  353. this.widthPaddingTools
  354. );
  355. }
  356. },
  357. watch: {
  358. widgets: {
  359. handler(val) {
  360. this.layerWidget = handlerLayerWidget(val, getToolByCode);
  361. //以下部分是记录历史
  362. this.$nextTick(() => {
  363. this.revoke.push(this.widgets);
  364. });
  365. },
  366. deep: true
  367. }
  368. },
  369. created() {
  370. /* 以下是记录历史的 */
  371. this.revoke = new Revoke();
  372. },
  373. mounted() {
  374. this.initScreen();
  375. // 如果是新的设计工作台
  376. // this.initEchartData();
  377. this.widgets = [];
  378. window.addEventListener("mouseup", () => {
  379. this.grade = false;
  380. });
  381. },
  382. methods: {
  383. // 初始化大屏
  384. initScreen() {
  385. this.widgetOptions = screenConfig["options"];
  386. },
  387. // 初始化 echrats
  388. async initEchartData() {
  389. const reportCode = this.$route.query.reportCode;
  390. const { code, data } = await detailDashboard(reportCode);
  391. if (code != 200) return;
  392. const processData = handleInitEchartsData(data, getToolByCode);
  393. const screenData = handleBigScreen(
  394. data.dashboard,
  395. getToolByCode,
  396. this.setOptionsOnClickScreen
  397. );
  398. this.widgets = processData;
  399. this.dashboard = screenData;
  400. this.bigscreenWidth = this.dashboard.width;
  401. this.bigscreenHeight = this.dashboard.height;
  402. },
  403. // 拖动一个组件放到工作区中去,在拖动结束时,放到工作区对应的坐标点上去
  404. widgetOnDragged(evt, widgetCode) {
  405. let widgetType = widgetCode;
  406. // 获取结束坐标和列名
  407. let eventX = evt.originalEvent.clientX; // 结束在屏幕的x坐标
  408. let eventY = evt.originalEvent.clientY; // 结束在屏幕的y坐标
  409. let workbenchPosition = this.getDomTopLeftById("workbench");
  410. let widgetTopInWorkbench = eventY - workbenchPosition.top;
  411. let widgetLeftInWorkbench = eventX - workbenchPosition.left;
  412. // 计算在缩放模式下的x y
  413. let x = widgetLeftInWorkbench / this.bigscreenScaleInWorkbench;
  414. let y = widgetTopInWorkbench / this.bigscreenScaleInWorkbench;
  415. // 复制一个组件
  416. let tool = getToolByCode(widgetType);
  417. let widgetJson = {
  418. type: widgetType,
  419. value: {
  420. setup: {},
  421. data: {},
  422. position: {
  423. width: 0,
  424. height: 0,
  425. left: 0,
  426. top: 0,
  427. zIndex: 0
  428. }
  429. },
  430. options: tool.options
  431. };
  432. // 处理默认值
  433. const widgetJsonValue = handleDefaultValue(widgetJson);
  434. //2022年02月22日 修复:可以拖拽放到鼠标的位置
  435. widgetJsonValue.value.position.left =
  436. x - widgetJsonValue.value.position.width / 2;
  437. widgetJsonValue.value.position.top =
  438. y - widgetJsonValue.value.position.height / 2;
  439. // 将选中的复制组件,放到工作区中去
  440. this.widgets.push(this.deepClone(widgetJsonValue));
  441. // 激活新组件的配置属性
  442. this.setOptionsOnClickWidget(this.widgets.length - 1);
  443. },
  444. // 如果是点击大屏设计器中的底层,加载大屏底层属性
  445. setOptionsOnClickScreen() {
  446. this.screenCode = "screen";
  447. // 选中不同的组件 右侧都显示第一栏
  448. this.activeName = "first";
  449. this.widgetOptions = screenConfig["options"];
  450. },
  451. layerClick(index) {
  452. this.widgetIndex = index;
  453. this.widgetsClick(index);
  454. },
  455. // 如果是点击某个组件,获取该组件的配置项
  456. setOptionsOnClickWidget(obj) {
  457. console.log(obj);
  458. this.screenCode = "";
  459. if (typeof obj == "number") {
  460. this.widgetOptions = this.deepClone(this.widgets[obj]["options"]);
  461. return;
  462. }
  463. if (obj.index < 0 || obj.index >= this.widgets.length) {
  464. return;
  465. }
  466. this.widgetIndex = obj.index;
  467. this.widgets[obj.index].value.position = obj;
  468. this.widgets[obj.index].options.position.forEach(el => {
  469. for (const key in obj) {
  470. if (el.name == key) {
  471. el.value = obj[key];
  472. }
  473. }
  474. });
  475. this.widgetOptions = this.deepClone(this.widgets[obj.index]["options"]);
  476. },
  477. widgetsClick(index) {
  478. const draggableArr = this.$refs.widgets;
  479. for (let i = 0; i < draggableArr.length; i++) {
  480. if (i == index) {
  481. this.$refs.widgets[i].$refs.draggable.setActive(true);
  482. } else {
  483. this.$refs.widgets[i].$refs.draggable.setActive(false);
  484. }
  485. }
  486. this.setOptionsOnClickWidget(index);
  487. this.grade = true;
  488. },
  489. widgetsMouseup(e) {
  490. this.grade = false;
  491. },
  492. handleMouseDown() {
  493. const draggableArr = this.$refs.widgets;
  494. for (let i = 0; i < draggableArr.length; i++) {
  495. this.$refs.widgets[i].$refs.draggable.setActive(false);
  496. }
  497. },
  498. // 将当前选中的组件,右侧属性值更新
  499. widgetValueChanged(key, val) {
  500. if (this.screenCode == "screen") {
  501. let newSetup = new Array();
  502. this.dashboard = this.deepClone(val);
  503. if (this.bigscreenWidth != this.dashboard.width) {
  504. this.bigscreenWidth = this.dashboard.width;
  505. }
  506. if (this.bigscreenHeight != this.dashboard.height) {
  507. this.bigscreenHeight = this.dashboard.height;
  508. }
  509. this.widgetOptions.setup.forEach(el => {
  510. if (el.name == "width") {
  511. el.value = this.bigscreenWidth;
  512. } else if (el.name == "height") {
  513. el.value = this.bigscreenHeight;
  514. }
  515. newSetup.push(el);
  516. });
  517. this.widgetOptions.setup = newSetup;
  518. } else {
  519. for (let i = 0; i < this.widgets.length; i++) {
  520. if (this.widgetIndex == i) {
  521. this.widgets[i].value[key] = this.deepClone(val);
  522. setDefaultValue(this.widgets[i].options[key], val);
  523. }
  524. }
  525. }
  526. },
  527. rightClick(event, index) {
  528. this.rightClickIndex = index;
  529. const left = event.clientX;
  530. const top = event.clientY;
  531. if (left || top) {
  532. this.styleObj = {
  533. left: left + "px",
  534. top: top + "px",
  535. display: "block"
  536. };
  537. }
  538. this.visibleContentMenu = true;
  539. return false;
  540. },
  541. datadragEnd(evt) {
  542. evt.preventDefault();
  543. this.widgets = swapArr(this.widgets, evt.oldIndex, evt.newIndex);
  544. },
  545. // 保存
  546. async saveData() {
  547. if (!this.widgets || this.widgets.length == 0) {
  548. this.$message.error("请添加组件");
  549. return;
  550. }
  551. const screenData = {
  552. reportCode: this.$route.query.reportCode,
  553. dashboard: {
  554. title: this.dashboard.title,
  555. width: this.dashboard.width,
  556. height: this.dashboard.height,
  557. backgroundColor: this.dashboard.backgroundColor,
  558. backgroundImage: this.dashboard.backgroundImage
  559. },
  560. widgets: this.widgets
  561. };
  562. const { code, data } = await insertDashboard(screenData);
  563. if (code == "200") {
  564. this.$message.success("保存成功!");
  565. }
  566. },
  567. // 预览
  568. viewScreen() {
  569. let routeUrl = this.$router.resolve({
  570. path: "/screen/preview",
  571. query: { reportCode: this.$route.query.reportCode }
  572. });
  573. window.open(routeUrl.href, "_blank");
  574. },
  575. // 撤销
  576. handleRedo() {
  577. const record = this.revoke.redo();
  578. if (!record) {
  579. return false;
  580. }
  581. this.widgets = record;
  582. },
  583. // 恢复
  584. handleUndo() {
  585. const record = this.revoke.undo();
  586. if (!record) {
  587. return false;
  588. }
  589. this.widgets = record;
  590. },
  591. // 导入 成功回调
  592. handleUpload(response, file, fileList) {
  593. //清除el-upload组件中的文件
  594. this.$refs.upload.clearFiles();
  595. //刷新大屏页面
  596. this.initEchartData();
  597. if (response.code == "200") {
  598. this.$message({
  599. message: "导入成功!",
  600. type: "success"
  601. });
  602. } else {
  603. this.$message({
  604. message: response.message,
  605. type: "error"
  606. });
  607. }
  608. },
  609. // 导入失败
  610. handleError(err) {
  611. this.$message({
  612. message: "上传失败!",
  613. type: "error"
  614. });
  615. },
  616. // 导出
  617. async exportDashboard(val) {
  618. console.log(val);
  619. const fileName = this.$route.query.reportCode + ".zip";
  620. const param = {
  621. reportCode: this.$route.query.reportCode,
  622. showDataSet: val
  623. };
  624. exportDashboard(param).then(res => {
  625. const that = this;
  626. const type = res.type;
  627. if (type == "application/json") {
  628. let reader = new FileReader();
  629. reader.readAsText(res, "utf-8");
  630. reader.onload = function() {
  631. const data = JSON.parse(reader.result);
  632. that.$message.error(data.message);
  633. };
  634. return;
  635. }
  636. const blob = new Blob([res], { type: "application/octet-stream" });
  637. if (window.navigator.msSaveOrOpenBlob) {
  638. //msSaveOrOpenBlob方法返回bool值
  639. navigator.msSaveBlob(blob, fileName); //本地保存
  640. } else {
  641. const link = document.createElement("a"); //a标签下载
  642. link.href = window.URL.createObjectURL(blob);
  643. link.download = fileName;
  644. link.click();
  645. window.URL.revokeObjectURL(link.href);
  646. }
  647. });
  648. },
  649. // 删除
  650. deletelayer() {
  651. this.widgets.splice(this.rightClickIndex, 1);
  652. },
  653. // 复制
  654. copylayer() {
  655. const obj = this.deepClone(this.widgets[this.rightClickIndex]);
  656. this.widgets.splice(this.widgets.length, 0, obj);
  657. },
  658. // 置顶
  659. istopLayer() {
  660. if (this.rightClickIndex + 1 < this.widgets.length) {
  661. const temp = this.widgets.splice(this.rightClickIndex, 1)[0];
  662. this.widgets.push(temp);
  663. }
  664. },
  665. // 置底
  666. setlowLayer() {
  667. if (this.rightClickIndex != 0) {
  668. this.widgets.unshift(this.widgets.splice(this.rightClickIndex, 1)[0]);
  669. }
  670. },
  671. // 上移一层
  672. moveupLayer() {
  673. if (this.rightClickIndex != 0) {
  674. this.widgets[this.rightClickIndex] = this.widgets.splice(
  675. this.rightClickIndex - 1,
  676. 1,
  677. this.widgets[this.rightClickIndex]
  678. )[0];
  679. } else {
  680. this.widgets.push(this.widgets.shift());
  681. }
  682. },
  683. // 下移一层
  684. movedownLayer() {
  685. if (this.rightClickIndex != this.widgets.length - 1) {
  686. this.widgets[this.rightClickIndex] = this.widgets.splice(
  687. this.rightClickIndex + 1,
  688. 1,
  689. this.widgets[this.rightClickIndex]
  690. )[0];
  691. } else {
  692. this.widgets.unshift(this.widgets.splice(this.rightClickIndex, 1)[0]);
  693. }
  694. }
  695. }
  696. };
  697. </script>
  698. <style scoped lang="scss">
  699. @import "../../assets/styles/screenDesigner.scss";
  700. </style>