优化 大屏
parent
5d3993444e
commit
4cb06437d5
@ -0,0 +1,144 @@
|
||||
<!--
|
||||
* @Descripttion: 大屏左侧工具栏
|
||||
* @version:
|
||||
* @Author: qianlishi
|
||||
* @Date: 2022-05-12 11:05:21
|
||||
* @LastEditors: qianlishi
|
||||
* @LastEditTime: 2022-05-14 11:51:45
|
||||
-->
|
||||
<template>
|
||||
<el-tabs class="layout-left" type="border-card">
|
||||
<el-tab-pane>
|
||||
<span slot="label"><i class="el-icon-date icon"></i>工具栏</span>
|
||||
<div class="chart-type">
|
||||
<el-tabs class="type-left" tab-position="left">
|
||||
<el-tab-pane
|
||||
v-for="(item, index) in widgetTools"
|
||||
:key="index"
|
||||
:label="item.name"
|
||||
>
|
||||
<draggable
|
||||
v-for="(it, idx) in item.list"
|
||||
:key="idx"
|
||||
@end="evt => widgetOnDragged(evt, it.code)"
|
||||
>
|
||||
<div class="tools-item">
|
||||
<span class="tools-item-icon">
|
||||
<i class="iconfont" :class="it.icon"></i>
|
||||
</span>
|
||||
<span class="tools-item-text">{{ it.label }}</span>
|
||||
</div>
|
||||
</draggable>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane>
|
||||
<span slot="label" class="icon"
|
||||
><i class="el-icon-date icon"></i>图层</span
|
||||
>
|
||||
<div
|
||||
v-for="(item, index) in layerWidget"
|
||||
:key="'item' + index"
|
||||
class="tools-item"
|
||||
:class="widgetIndex == index ? 'is-active' : ''"
|
||||
@click="layerClick(index)"
|
||||
>
|
||||
<span class="tools-item-icon">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
</span>
|
||||
<span class="tools-item-text">{{ item.label }}</span>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
<script>
|
||||
import draggable from "vuedraggable";
|
||||
export default {
|
||||
components: {
|
||||
draggable
|
||||
},
|
||||
props: {
|
||||
widgetIndex: Number,
|
||||
widgetTools: Array,
|
||||
layerWidget: Array
|
||||
},
|
||||
methods: {
|
||||
widgetOnDragged(evt, code) {
|
||||
this.$emit("widgetOnDragged", evt, code);
|
||||
},
|
||||
layerClick(index) {
|
||||
this.$emit("layerClick", index);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
/deep/.el-dropdown-menu__item {
|
||||
max-width: none;
|
||||
}
|
||||
.layout-left {
|
||||
width: 200px;
|
||||
background: #242a30;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
.chart-type {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
.type-left {
|
||||
width: 100%;
|
||||
height: calc(100vh - 80px);
|
||||
text-align: center;
|
||||
/deep/.el-tabs__header {
|
||||
width: 30%;
|
||||
margin-right: 0;
|
||||
.el-tabs__nav-wrap {
|
||||
&::after {
|
||||
background: transparent;
|
||||
}
|
||||
.el-tabs__item {
|
||||
text-align: center;
|
||||
width: 100% !important;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
/deep/.el-tabs__content {
|
||||
width: 70%;
|
||||
}
|
||||
}
|
||||
}
|
||||
//工具栏一个元素
|
||||
.tools-item {
|
||||
display: flex;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
align-items: center;
|
||||
-webkit-box-align: center;
|
||||
padding: 0 6px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
margin-bottom: 1px;
|
||||
|
||||
.tools-item-icon {
|
||||
color: #409eff;
|
||||
margin-right: 10px;
|
||||
width: 53px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
display: block;
|
||||
border: 1px solid #3a4659;
|
||||
background: #282a30;
|
||||
}
|
||||
.tools-item-text {
|
||||
}
|
||||
}
|
||||
/deep/.el-tabs__content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,70 @@
|
||||
<!--
|
||||
* @Descripttion: 大屏右侧配置
|
||||
* @version:
|
||||
* @Author: qianlishi
|
||||
* @Date: 2022-05-12 11:05:54
|
||||
* @LastEditors: qianlishi
|
||||
* @LastEditTime: 2022-05-14 11:52:30
|
||||
-->
|
||||
<template>
|
||||
<div class="layout-right">
|
||||
<el-tabs v-model="activeName" type="border-card" :stretch="true">
|
||||
<el-tab-pane
|
||||
v-if="
|
||||
isNotNull(widgetOptions.setup) || isNotNull(widgetOptions.collapse)
|
||||
"
|
||||
name="first"
|
||||
label="配置"
|
||||
>
|
||||
<dynamicForm
|
||||
ref="formData"
|
||||
:options="widgetOptions.setup"
|
||||
@onChanged="val => widgetValueChanged('setup', val)"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="isNotNull(widgetOptions.data)"
|
||||
name="second"
|
||||
label="数据"
|
||||
>
|
||||
<dynamicForm
|
||||
ref="formData"
|
||||
:options="widgetOptions.data"
|
||||
@onChanged="val => widgetValueChanged('data', val)"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane
|
||||
v-if="isNotNull(widgetOptions.position)"
|
||||
name="third"
|
||||
label="坐标"
|
||||
>
|
||||
<dynamicForm
|
||||
ref="formData"
|
||||
:options="widgetOptions.position"
|
||||
@onChanged="val => widgetValueChanged('position', val)"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import dynamicForm from "../components/dynamicForm.vue";
|
||||
export default {
|
||||
components: {
|
||||
dynamicForm
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeName: "first"
|
||||
};
|
||||
},
|
||||
props: {
|
||||
widgetOptions: Object
|
||||
},
|
||||
methods: {
|
||||
widgetValueChanged(type, val) {
|
||||
this.$emit("widgetValueChanged", type, val);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
@ -0,0 +1,229 @@
|
||||
<!--
|
||||
* @Descripttion: 大屏顶部操操按钮
|
||||
* @version:
|
||||
* @Author: qianlishi
|
||||
* @Date: 2022-05-14 11:54:07
|
||||
* @LastEditors: qianlishi
|
||||
* @LastEditTime: 2022-05-14 12:52:58
|
||||
-->
|
||||
<template>
|
||||
<!-- 操作栏 -->
|
||||
<div class="layout-bar">
|
||||
<div class="bar-item" @click="saveData">
|
||||
<i class="iconfont iconsave"></i>保存
|
||||
</div>
|
||||
<div class="bar-item" @click="viewScreen">
|
||||
<i class="iconfont iconyulan"></i>预览
|
||||
</div>
|
||||
<div class="bar-item" @click="handleUndo">
|
||||
<i class="iconfont iconundo"></i>撤销
|
||||
</div>
|
||||
<div class="bar-item" @click="handleRedo">
|
||||
<i class="iconfont iconhuifubeifen"></i>恢复
|
||||
</div>
|
||||
<div class="bar-item">
|
||||
<el-upload
|
||||
class="el-upload"
|
||||
ref="upload"
|
||||
:action="uploadUrl"
|
||||
:headers="headers"
|
||||
accept=".zip"
|
||||
:on-success="handleUpload"
|
||||
:on-error="handleError"
|
||||
:show-file-list="false"
|
||||
:limit="1"
|
||||
>
|
||||
<i class="iconfont icondaoru"></i>
|
||||
</el-upload>
|
||||
导入
|
||||
</div>
|
||||
<div class="bar-item">
|
||||
<i class="iconfont icondaochu"></i>
|
||||
<el-dropdown @command="exportDashboard">
|
||||
<span class="el-dropdown-link">
|
||||
导出<i class="el-icon-arrow-down el-icon--right"></i>
|
||||
</span>
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="1">导出(包含数据集)</el-dropdown-item>
|
||||
<el-dropdown-item command="0">导出(不包含数据集)</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { insertDashboard, exportDashboard } from "@/api/bigscreen";
|
||||
import { Revoke } from "../util/revoke";
|
||||
import { getToken } from "@/utils/auth";
|
||||
export default {
|
||||
props: {
|
||||
dashboard: Object,
|
||||
widgets: Array
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
uploadUrl:
|
||||
process.env.BASE_API +
|
||||
"/reportDashboard/import/" +
|
||||
this.$route.query.reportCode,
|
||||
revoke: null
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
headers() {
|
||||
return {
|
||||
Authorization: getToken()
|
||||
};
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
widgets: {
|
||||
handler(val) {
|
||||
//以下部分是记录历史
|
||||
this.$nextTick(() => {
|
||||
this.revoke.push(this.widgets);
|
||||
});
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
/* 以下是记录历史的 */
|
||||
this.revoke = new Revoke();
|
||||
},
|
||||
methods: {
|
||||
// 保存
|
||||
async saveData() {
|
||||
if (!this.widgets || this.widgets.length == 0) {
|
||||
return this.$message.error("请添加组件");
|
||||
}
|
||||
const screenData = {
|
||||
reportCode: this.$route.query.reportCode,
|
||||
dashboard: {
|
||||
title: this.dashboard.title,
|
||||
width: this.dashboard.width,
|
||||
height: this.dashboard.height,
|
||||
backgroundColor: this.dashboard.backgroundColor,
|
||||
backgroundImage: this.dashboard.backgroundImage
|
||||
},
|
||||
widgets: this.widgets
|
||||
};
|
||||
const { code, data } = await insertDashboard(screenData);
|
||||
if (code == "200") {
|
||||
this.$message.success("保存成功!");
|
||||
}
|
||||
},
|
||||
// 预览
|
||||
viewScreen() {
|
||||
let routeUrl = this.$router.resolve({
|
||||
path: "/screen/preview",
|
||||
query: { reportCode: this.$route.query.reportCode }
|
||||
});
|
||||
window.open(routeUrl.href, "_blank");
|
||||
},
|
||||
// 撤销
|
||||
handleUndo() {
|
||||
const record = this.revoke.undo();
|
||||
if (!record) {
|
||||
return false;
|
||||
}
|
||||
this.widgets = record;
|
||||
},
|
||||
// 恢复
|
||||
handleRedo() {
|
||||
const record = this.revoke.redo();
|
||||
if (!record) {
|
||||
return false;
|
||||
}
|
||||
this.widgets = record;
|
||||
},
|
||||
// 导入失败
|
||||
handleError(err) {
|
||||
this.$message({
|
||||
message: "上传失败!",
|
||||
type: "error"
|
||||
});
|
||||
},
|
||||
// 导入 成功回调
|
||||
handleUpload(response, file, fileList) {
|
||||
//清除el-upload组件中的文件
|
||||
this.$refs.upload.clearFiles();
|
||||
//刷新大屏页面
|
||||
this.irefresh();
|
||||
if (response.code == "200") {
|
||||
this.$message({
|
||||
message: "导入成功!",
|
||||
type: "success"
|
||||
});
|
||||
} else {
|
||||
this.$message({
|
||||
message: response.message,
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
},
|
||||
// 导出
|
||||
async exportDashboard(val) {
|
||||
const fileName = this.$route.query.reportCode + ".zip";
|
||||
|
||||
const param = {
|
||||
reportCode: this.$route.query.reportCode,
|
||||
showDataSet: val
|
||||
};
|
||||
exportDashboard(param).then(res => {
|
||||
const that = this;
|
||||
const type = res.type;
|
||||
if (type == "application/json") {
|
||||
let reader = new FileReader();
|
||||
reader.readAsText(res, "utf-8");
|
||||
reader.onload = function() {
|
||||
const data = JSON.parse(reader.result);
|
||||
that.$message.error(data.message);
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = new Blob([res], {
|
||||
type: "application/octet-stream"
|
||||
});
|
||||
if (window.navigator.msSaveOrOpenBlob) {
|
||||
//msSaveOrOpenBlob方法返回bool值
|
||||
navigator.msSaveBlob(blob, fileName); //本地保存
|
||||
} else {
|
||||
const link = document.createElement("a"); //a标签下载
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = fileName;
|
||||
link.click();
|
||||
window.URL.revokeObjectURL(link.href);
|
||||
}
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.$emit("refresh");
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.layout-bar {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
font-size: 12px;
|
||||
padding: 0 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
.bar-item {
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
.iconfont {
|
||||
font-size: 12px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.el-dropdown-link {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue