screenMixins.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. import { Revoke } from "@/utils/revoke";
  2. import { getToken } from "@/utils/auth";
  3. import { getToolByCode } from "@/views/bigscreenDesigner/designer/tools/index";
  4. import { insertDashboard, detailDashboard, exportDashboard, } from "@/api/bigscreen";
  5. const mixin = {
  6. data() {
  7. return {
  8. reportCode: this.$route.query.reportCode,
  9. uploadUrl: process.env.BASE_API + "/reportDashboard/import/" + this.reportCode,
  10. revoke: null, //处理历史记录
  11. rightClickIndex: -1,
  12. }
  13. },
  14. computed: {
  15. step() {
  16. return Number(100 / (this.bigscreenScaleInWorkbench * 100));
  17. },
  18. headers() {
  19. return {
  20. Authorization: getToken(),
  21. };
  22. },
  23. // 初始的缩放百分比 和 下标
  24. defaultSize() {
  25. const obj = {
  26. index: -1,
  27. size: "50",
  28. };
  29. this.sizeRange.some((item, index) => {
  30. if (item <= 100 * this.bigscreenScaleInWorkbench) {
  31. obj.index = index;
  32. obj.size = 100 * this.bigscreenScaleInWorkbench;
  33. }
  34. });
  35. if (obj.index === -1) {
  36. obj.index = 0;
  37. obj.size = this.sizeRange[0];
  38. }
  39. return obj;
  40. },
  41. },
  42. watch: {
  43. defaultSize: {
  44. handler(val) {
  45. if (val !== -1) {
  46. this.currentSizeRangeIndex = val.index;
  47. this.scaleNum = val.size;
  48. }
  49. },
  50. immediate: true,
  51. },
  52. bigscreenWidth() {
  53. this.initVueRulerTool();
  54. },
  55. bigscreenHeight() {
  56. this.initVueRulerTool();
  57. },
  58. },
  59. created() {
  60. this.revoke = new Revoke();
  61. this.getData();
  62. },
  63. methods: {
  64. /**
  65. * @param num: 0缩小 1放大 2默认比例
  66. * sizeRange: [20, 40, 60, 72, 100, 150, 200, 300, 400]
  67. */
  68. setSize(num) {
  69. switch (num) {
  70. case 0: this.currentSizeRangeIndex === 0 ? '' : this.currentSizeRangeIndex -= 1;
  71. break;
  72. case 1: this.currentSizeRangeIndex === 8 ? '' : this.currentSizeRangeIndex += 1;
  73. break;
  74. case 2: this.currentSizeRangeIndex = this.defaultSize.index;
  75. }
  76. this.scaleNum = this.currentSizeRangeIndex === this.defaultSize.index ? this.defaultSize.size : this.sizeRange[this.currentSizeRangeIndex];
  77. },
  78. // 初始化 修正插件样式
  79. initVueRulerTool() {
  80. const vueRulerToolDom = this.$refs["vue-ruler-tool"].$el; // 操作面板 第三方插件工具
  81. const contentDom = vueRulerToolDom.querySelector(".vue-ruler-content");
  82. const vueRulerX = vueRulerToolDom.querySelector(".vue-ruler-h"); // 横向标尺
  83. const vueRulerY = vueRulerToolDom.querySelector(".vue-ruler-v"); // 纵向标尺
  84. contentDom.style.width = "100%";
  85. contentDom.style.height = "100%";
  86. let xHtmlContent = "";
  87. let yHtmlContent = "";
  88. let currentNum = 0;
  89. while (currentNum < +this.bigscreenWidth) {
  90. xHtmlContent += `<span class="n" style="left: ${currentNum + 2}px;">${currentNum}</span>`;
  91. currentNum += 50;
  92. }
  93. currentNum = 0;
  94. while (currentNum < +this.bigscreenHeight) {
  95. yHtmlContent += `<span class="n" style="top: ${currentNum + 2}px;">${currentNum}</span>`;
  96. currentNum += 50;
  97. }
  98. vueRulerX.innerHTML = xHtmlContent;
  99. vueRulerY.innerHTML = yHtmlContent;
  100. },
  101. // 初始化接口数据
  102. async getData() {
  103. const { code, data } = await detailDashboard(this.reportCode);
  104. if (code != 200) return;
  105. this.widgets = this.initWidgetsData(data);
  106. this.dashboard = this.initScreenData(data.dashboard);
  107. this.bigscreenWidth = this.dashboard.width;
  108. this.bigscreenHeight = this.dashboard.height;
  109. },
  110. // 组件数据
  111. initWidgetsData(data) {
  112. const widgets = data.dashboard ? data.dashboard.widgets : [];
  113. const widgetsData = [];
  114. for (let i = 0; i < widgets.length; i++) {
  115. const widget = widgets[i]
  116. const { setup, data, position } = { ...widget.value }
  117. const obj = {
  118. type: widget.type,
  119. value: { setup, data, position }
  120. };
  121. const tool = this.deepClone(getToolByCode(widget.type));
  122. if (!tool) {
  123. const message = "暂未提供该组件或该组件下线了,组件code: " + widget.type;
  124. if (process.env.NODE_ENV === "development") {
  125. this.$message.error(message);
  126. }
  127. continue; // 找不到就跳过,避免整个报表都加载不出来
  128. }
  129. obj.options = this.setDefaultWidgetConfigValue(widget.value, tool.options);
  130. obj.value.widgetId = obj.value.setup.widgetId;
  131. widgetsData.push(obj);
  132. }
  133. return widgetsData;
  134. },
  135. // 重写默认数据
  136. setDefaultWidgetConfigValue(data, option) {
  137. this.setConfigValue(data.setup, option.setup)
  138. this.setConfigValue(data.position, option.position)
  139. this.setConfigValue(data.data, option.data)
  140. return option;
  141. },
  142. setConfigValue(objValue, setup) {
  143. Object.keys(objValue).forEach(key => {
  144. setup.forEach(item => {
  145. if (this.isObjectFn(item) && key == item.name) {
  146. item.value = objValue[key]
  147. }
  148. if (this.isArrayFn(item)) {
  149. item.forEach(itemChild => {
  150. itemChild.list.forEach(el => {
  151. if (key == el.name) {
  152. el.value = objValue[key]
  153. }
  154. })
  155. })
  156. }
  157. })
  158. })
  159. },
  160. // 大屏数据
  161. initScreenData(data) {
  162. const optionScreen = getToolByCode("screen").options;
  163. this.setConfigValue(data, optionScreen.setup)
  164. this.setOptionsOnClickScreen();
  165. return {
  166. backgroundColor:
  167. (data && data.backgroundColor) || (!data ? "#1e1e1e" : ""),
  168. backgroundImage: (data && data.backgroundImage) || "",
  169. height: (data && data.height) || "1080",
  170. title: (data && data.title) || "",
  171. width: (data && data.width) || "1920",
  172. };
  173. },
  174. // 保存数据
  175. async saveData() {
  176. if (!this.widgets || this.widgets.length == 0) {
  177. return this.$message.error("请添加组件");
  178. }
  179. const { title, width, height, backgroundColor, backgroundImage } = { ...this.dashboard }
  180. const screenData = {
  181. reportCode: this.reportCode,
  182. dashboard: { title, width, height, backgroundColor, backgroundImage },
  183. widgets: this.widgets,
  184. };
  185. screenData.widgets.forEach((widget) => {
  186. widget.value.setup.widgetId = widget.value.widgetId;
  187. });
  188. const { code, data } = await insertDashboard(screenData);
  189. if (code == "200") return this.$message.success("保存成功!");
  190. },
  191. // 预览
  192. viewScreen() {
  193. let routeUrl = this.$router.resolve({
  194. path: "/bigscreen/viewer",
  195. query: { reportCode: this.reportCode },
  196. });
  197. window.open(routeUrl.href, "_blank");
  198. },
  199. async exportDashboard(val) {
  200. const fileName = this.reportCode + ".zip";
  201. const param = {
  202. reportCode: this.reportCode,
  203. showDataSet: val,
  204. };
  205. exportDashboard(param).then((res) => {
  206. const that = this;
  207. const type = res.type;
  208. if (type == "application/json") {
  209. let reader = new FileReader();
  210. reader.readAsText(res, "utf-8");
  211. reader.onload = function () {
  212. const data = JSON.parse(reader.result);
  213. that.$message.error(data.message);
  214. };
  215. return;
  216. }
  217. const blob = new Blob([res], { type: "application/octet-stream" });
  218. if (window.navigator.msSaveOrOpenBlob) {
  219. //msSaveOrOpenBlob方法返回bool值
  220. navigator.msSaveBlob(blob, fileName); //本地保存
  221. } else {
  222. const link = document.createElement("a"); //a标签下载
  223. link.href = window.URL.createObjectURL(blob);
  224. link.download = fileName;
  225. link.click();
  226. window.URL.revokeObjectURL(link.href);
  227. }
  228. });
  229. },
  230. handleUndo() {
  231. const record = this.revoke.undo();
  232. if (!record) return false;
  233. this.widgets = record;
  234. },
  235. handleRedo() {
  236. const record = this.revoke.redo();
  237. if (!record) return false;
  238. this.widgets = record;
  239. },
  240. handleUpload(response, file, fileList) {
  241. this.$refs.upload.clearFiles();
  242. this.getData();
  243. if (response.code == "200") return this.$message.success('导入成功!')
  244. this.$message.error(response.message)
  245. },
  246. // 右键
  247. rightClick(event, index) {
  248. this.rightClickIndex = index;
  249. const left = event.clientX;
  250. const top = event.clientY;
  251. if (left || top) {
  252. this.styleObj = {
  253. left: left + "px",
  254. top: top + "px",
  255. display: "block",
  256. };
  257. }
  258. this.visibleContentMenu = true;
  259. return false;
  260. },
  261. // 数组 元素互换位置
  262. swapArr(arr, oldIndex, newIndex) {
  263. arr[oldIndex] = arr.splice(newIndex, 1, arr[oldIndex])[0];
  264. return arr;
  265. },
  266. // 删除
  267. deletelayer() {
  268. this.widgets.splice(this.rightClickIndex, 1);
  269. },
  270. // 锁定
  271. lockLayer() {
  272. const obj = this.widgets[this.rightClickIndex];
  273. this.$set(obj.value.position, "disabled", true);
  274. },
  275. // 解除锁定
  276. noLockLayer() {
  277. const obj = this.widgets[this.rightClickIndex];
  278. this.$set(obj.value.position, "disabled", false);
  279. },
  280. // 复制
  281. copylayer() {
  282. const obj = this.deepClone(this.widgets[this.rightClickIndex]);
  283. obj.value.position.top += 40; // 复制的元素向右下角偏移一点
  284. obj.value.position.left += 40;
  285. obj.value.widgetId = Number(Math.random().toString().substr(2)).toString(
  286. 36
  287. );
  288. this.widgets.splice(this.widgets.length, 0, obj);
  289. this.$nextTick(() => {
  290. this.layerClick(this.widgets.length - 1); // 复制后定位到最新的组件
  291. });
  292. },
  293. // 置顶
  294. istopLayer() {
  295. if (this.rightClickIndex + 1 < this.widgets.length) {
  296. const temp = this.widgets.splice(this.rightClickIndex, 1)[0];
  297. this.widgets.push(temp);
  298. }
  299. },
  300. // 置底
  301. setlowLayer() {
  302. if (this.rightClickIndex != 0) {
  303. this.widgets.unshift(this.widgets.splice(this.rightClickIndex, 1)[0]);
  304. }
  305. },
  306. // 上移一层
  307. moveupLayer() {
  308. if (this.rightClickIndex != 0) {
  309. this.widgets[this.rightClickIndex] = this.widgets.splice(
  310. this.rightClickIndex - 1,
  311. 1,
  312. this.widgets[this.rightClickIndex]
  313. )[0];
  314. } else {
  315. this.widgets.push(this.widgets.shift());
  316. }
  317. },
  318. // 下移一层
  319. movedownLayer() {
  320. if (this.rightClickIndex != this.widgets.length - 1) {
  321. this.widgets[this.rightClickIndex] = this.widgets.splice(
  322. this.rightClickIndex + 1,
  323. 1,
  324. this.widgets[this.rightClickIndex]
  325. )[0];
  326. } else {
  327. this.widgets.unshift(this.widgets.splice(this.rightClickIndex, 1)[0]);
  328. }
  329. }
  330. }
  331. }
  332. export default mixin