<template>
|
<div ref="container">
|
<el-container class="designer-container">
|
<el-aside width="300px">
|
<left-aside ref="left-aside" :basic-components="basicComponents" :module-node.sync="moduleNode" :detail-fields.sync="detailFields" :widget-form-data.sync="widgetFormData" :reset-do-list="resetDoList"></left-aside>
|
</el-aside>
|
|
<el-container class="designer-center-container" direction="vertical">
|
<div class="content">
|
<div class="right-tools" @mousedown.stop>
|
<el-button type="text" size="medium" icon="el-icon-yrt-baocun" @click="handleGenerateJson">保存</el-button>
|
<el-button type="text" size="medium" icon="el-icon-yrt-reset" @click="handleReset">重置</el-button>
|
<el-button type="text" size="medium" icon="el-icon-view" @click="handlePreview">预览</el-button>
|
<i class="el-icon-yrt-vertical_line"></i>
|
<el-button type="text" size="medium" icon="el-icon-yrt-undo" @click.native="toolActionUndo()">撤销</el-button>
|
<el-button type="text" size="medium" icon="el-icon-yrt-redo" @click.native="toolActionRedo()">恢复</el-button>
|
<i class="el-icon-yrt-vertical_line"></i>
|
<el-button type="text" size="medium" icon="el-icon-yrt-zuoduiqi" @click.native="toolAction('left')">左对齐</el-button>
|
<el-button type="text" size="medium" icon="el-icon-yrt-youduiqi" @click.native="toolAction('right')">右对齐</el-button>
|
<el-button type="text" size="medium" icon="el-icon-yrt-shangduiqi" @click.native="toolAction('top')">上对齐</el-button>
|
<el-button type="text" size="medium" icon="el-icon-yrt-xiaduiqi" @click.native="toolAction('bottom')">下对齐</el-button>
|
<i class="el-icon-yrt-vertical_line"></i>
|
<el-button type="text" size="medium" icon="el-icon-yrt-settings2" @click.native="toolActionSetting">设置</el-button>
|
</div>
|
|
<widget-form ref="widgetForm" :data="widgetFormData" :select.sync="widgetFormSelect" :config-type.sync="configType" :detail-fields.sync="detailFields" :add-do-list="addDoList"></widget-form>
|
</div>
|
</el-container>
|
|
<!--属性窗口-->
|
<el-dialog v-dialogDrag :modal="false" :visible.sync="settingVisible" :append-to-body="true" :modal-append-to-body="true" width="300px" top="5vh" title="属性设置" class="attribute-config-container">
|
<el-tabs value="widget" @tab-click="(tab, event)=>{handleConfigSelect(tab, event)}">
|
<el-tab-pane label="字段属性" name="widget">
|
<el-scrollbar :noresize="false" :native="false" wrap-class="config scrollbar-wrap">
|
<component v-show="configTab=='widget'" :is="configType" :data="widgetFormSelect" :basic-components="basicComponents"></component>
|
</el-scrollbar>
|
</el-tab-pane>
|
<el-tab-pane label="表单属性" name="form">
|
<el-scrollbar :noresize="false" :native="false" wrap-class="config scrollbar-wrap">
|
<form-config v-show="configTab=='form'" :data-options="widgetFormData.dataOptions"></form-config>
|
</el-scrollbar>
|
</el-tab-pane>
|
</el-tabs>
|
</el-dialog>
|
|
<cus-dialog ref="widgetPreview" :visible="previewVisible" title="UI预览" width="1000px" form @on-close="previewVisible = false" @on-submit="handlePagePreview">
|
</cus-dialog>
|
|
<cus-dialog ref="jsonPreview" :visible="jsonVisible" width="800px" form title="生成JSON并保存Vue文件" @on-close="jsonVisible = false">
|
<div id="jsoneditor" style="height: 400px;width: 100%;">{{ vueData }}</div>
|
<template slot="action">
|
<el-button data-clipboard-target=".ace_text-input" @dblclick.native="$message.success('复制成功');">双击复制</el-button>
|
<el-button :loading="createLoading" type="primary" data-clipboard-target=".ace_text-input" @click.native="createBaseVue">保存</el-button>
|
</template>
|
</cus-dialog>
|
</el-container>
|
</div>
|
</template>
|
|
<script>
|
import Draggable from "vuedraggable";
|
import WidgetConfig from "./WidgetConfig";
|
import FormConfig from "./FormConfig";
|
import WidgetForm from "./WidgetForm";
|
import CusDialog from "./CusDialog";
|
import { basicComponents } from "./componentsConfig.js";
|
import { loadJs } from "./util/index.js";
|
import { generateMixinCode, generateMainCode } from "./generateMixinCode.js";
|
import LeftAside from "./components/leftAside";
|
|
export default {
|
name: "sys-dev-tools-print-designer",
|
components: {
|
Draggable,
|
WidgetConfig,
|
FormConfig,
|
WidgetForm,
|
CusDialog,
|
LeftAside
|
},
|
data() {
|
return {
|
basicComponents,
|
|
// 明细字段
|
detailFields: [],
|
|
// 当前配置参数设置组件
|
configType: "WidgetConfig",
|
|
// 模块字段信息
|
moduleNode: {
|
projectName: null,
|
cnName: "【请选择模块】",
|
table_Id: 0,
|
tableName: null,
|
tableView: null,
|
dBServer: null,
|
dBServerReadOnly: null,
|
parentId: null,
|
detailName: null,
|
idField: null,
|
codeRegular: null,
|
linkColumn: null,
|
sortName: null
|
},
|
|
// 设计器数据结构
|
widgetFormData: {
|
// 数据加载及保存参数
|
dataOptions: {
|
menu_Id: null,
|
projectName: "BasicInfo",
|
tableView: "",
|
idField: "",
|
router: "/sys/table",
|
title: "",
|
paddingTop: 5,
|
paddingBottom: 5,
|
paddingLeft: 5,
|
paddingRight: 5,
|
width: 210,
|
height: 148,
|
templateType: "常规模板"
|
},
|
// 字段集合
|
fields: []
|
},
|
// 撤销、恢复
|
undoList: [],
|
redoList: [],
|
// undo、redo操作,不在记录历史
|
isDoAction: false,
|
// 时间戳
|
currentTimeStamp: 0,
|
|
// 设计器默认数据结构
|
widgetFormDataDefault: {
|
// 数据加载及保存参数
|
dataOptions: {
|
projectName: "BasicInfo",
|
tableView: "",
|
idField: "",
|
router: "",
|
title: "",
|
paddingTop: 30,
|
paddingRight: 30,
|
paddingBottom: 30,
|
paddingLeft: 30,
|
templateType: "常规模板"
|
},
|
// 字段集合
|
fields: []
|
},
|
// 设计器类型:管理页面、编辑页面
|
editRegionTab: "WidgetConfig",
|
configTab: "widget",
|
widgetFormSelect: null, // 选中项
|
previewVisible: false,
|
jsonVisible: false,
|
codeVisible: false,
|
blank: "",
|
vueData: "", // 创建混入文件内容
|
mainCode: "", // 创建主文件内容
|
createLoading: false, // 创建页面loading
|
// 参数设置窗口显示
|
settingVisible: true
|
};
|
},
|
watch: {
|
widgetFormData: {
|
deep: true,
|
handler: function(val) {
|
this.addDoList();
|
}
|
},
|
configType: function(val) {},
|
widgetFormSelect: {
|
handler(val) {},
|
deep: true
|
}
|
},
|
mounted() {
|
loadJs("lib/ace/src/ace.js");
|
},
|
deactivated() {
|
this.settingVisible = false;
|
},
|
activated() {
|
this.settingVisible = true;
|
// SaaS模块权限
|
this.common.hasSaaSAuth("打印模板设置", this.$refs.container);
|
},
|
methods: {
|
handleConfigSelect(tab, event) {
|
this.configTab = tab.name;
|
},
|
// 预览设计
|
handlePreview() {
|
this.previewVisible = true;
|
},
|
// 重置,重新开始设计
|
handleReset() {
|
if (!this.moduleNode.tableView) {
|
this.$message.error("请选择需要设计的模块!");
|
return;
|
}
|
this.$confirm("确定要重置设计,将重新开始设计, 是否继续?", "重置提示", {
|
confirmButtonText: "确定",
|
cancelButtonText: "取消",
|
type: "warning"
|
})
|
.then(() => {
|
this.reset();
|
this.$message({
|
type: "success",
|
message: "重置成功!"
|
});
|
})
|
.catch(() => {
|
this.$message({
|
type: "info",
|
message: "已取消重置"
|
});
|
});
|
},
|
// 重置
|
reset() {
|
var data = this.moduleNode;
|
this.widgetFormData = Object.assign({}, this.widgetFormDataDefault, {
|
dataOptions: {
|
projectName: data.projectName,
|
tableView: data.tableView,
|
idField: data.idField,
|
router: "/api/common/loadEditData",
|
idValue: 0,
|
codeRegular: data.codeRegular, // 自动编码字段
|
linkColumn: data.linkColumn, // 链接到弹出编辑窗口的字段
|
menu_Id: null,
|
pageIndex: 1,
|
pageSize: 15,
|
total: 0,
|
sortName: data.sortName
|
}
|
});
|
this.widgetFormSelect = null; // 编辑页面选中项
|
},
|
// 预览页面
|
handlePagePreview() {},
|
// 生成JSON
|
handleGenerateJson() {
|
var title = this.widgetFormData.dataOptions.title;
|
var router = this.widgetFormData.dataOptions.router;
|
var tableView = this.widgetFormData.dataOptions.tableView;
|
if (!title || !router || !tableView) {
|
this.$message.error("请在表单属性里面填写必填属性");
|
return;
|
}
|
|
this.jsonVisible = true;
|
var last = router.lastIndexOf("/");
|
if (last === router.length - 1) {
|
router = router.substring(0, router.length - 1);
|
this.widgetFormData.dataOptions.router = router;
|
}
|
|
this.mainCode = generateMainCode(router);
|
this.vueData = generateMixinCode(this.widgetFormData);
|
|
this.$nextTick(() => {
|
// eslint-disable-next-line
|
const editor = ace.edit("jsoneditor");
|
// eslint-disable-next-line
|
editor.session.setMode("ace/mode/jsx");
|
});
|
},
|
|
// 生成文件
|
createBaseVue() {
|
var the = this;
|
if (this.widgetFormData.dataOptions.menu_Id === "") {
|
this.$message.error("关联模块ID不能为空!");
|
return;
|
}
|
if (!this.widgetFormData.dataOptions.title) {
|
this.$message.error("模板名称不能为空!");
|
return;
|
}
|
if (!this.widgetFormData.dataOptions.router) {
|
this.$message.error("API地址不能为空!");
|
return;
|
}
|
if (!this.widgetFormData.dataOptions.tableView) {
|
this.$message.error("关联表名不能为空!");
|
return;
|
}
|
// eslint-disable-next-line
|
const editor = ace.edit("jsoneditor");
|
var selectText = editor.getSelectedText();
|
|
// UI布局参数
|
var vueData = selectText;
|
if (!vueData) {
|
vueData = JSON.stringify(this.widgetFormData, null, 2);
|
} else {
|
this.widgetFormData = JSON.parse(vueData);
|
}
|
if (!this.vueData) {
|
this.$message.error("没有可保存的数据!");
|
return;
|
}
|
var node = this.$refs["left-aside"].getCurrentNode();
|
var printTemplate_Id = node.printTemplate_Id;
|
// 更新节点数据
|
node.vueData = vueData;
|
|
the.createLoading = true;
|
var url = "/api/sys/printTemplate/savePrintTemplate";
|
var params = {
|
menu_Id: this.widgetFormData.dataOptions.menu_Id,
|
printTemplate_Id: printTemplate_Id,
|
templateName: this.widgetFormData.dataOptions.title,
|
templateType: this.widgetFormData.dataOptions.templateType,
|
vueData: vueData,
|
noDataSign: true // 数据不参与加密
|
};
|
|
the.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res);
|
if (res.result) {
|
this.moduleNode.vueData = vueData; // 保存数下拉框中的VueData
|
this.jsonVisible = false;
|
this.resetDoList();
|
}
|
the.createLoading = false;
|
},
|
true
|
);
|
},
|
|
// 工具栏事件操作
|
toolAction(action) {
|
var topItem = null;
|
var fields = this.widgetFormData.fields;
|
document.querySelectorAll(".resable-item.selected").forEach(item => {
|
if (!topItem || topItem.offsetY > item.offsetY) {
|
topItem = item;
|
}
|
});
|
if (!topItem) return;
|
|
document.querySelectorAll(".resable-item.selected").forEach(item => {
|
const key = item.attributes["data-key"].value;
|
const field = fields.find(item => {
|
return item.key === key;
|
});
|
|
let bottom, y, right, x;
|
switch (action) {
|
case "top":
|
field.options.y = topItem.offsetTop;
|
break;
|
case "bottom":
|
bottom = topItem.offsetTop + topItem.offsetHeight;
|
y = bottom - item.offsetHeight;
|
field.options.y = y;
|
break;
|
case "left":
|
field.options.x = topItem.offsetLeft;
|
break;
|
case "right": {
|
right = topItem.offsetLeft + topItem.offsetWidth;
|
x = right - item.offsetWidth;
|
field.options.x = x;
|
break;
|
}
|
}
|
});
|
},
|
// 设计动作记录add do list
|
addDoList() {
|
if (this.isDoAction) {
|
this.isDoAction = false;
|
return;
|
}
|
var currStamp = new Date().valueOf();
|
var span = currStamp - this.currentTimeStamp;
|
var newItem = JSON.parse(JSON.stringify(this.widgetFormData));
|
if (this.undoList.length) {
|
var lastItem = this.undoList[this.undoList.length - 1];
|
var newItemJson = JSON.stringify(this.widgetFormData);
|
|
if (newItemJson !== lastItem) {
|
if (span < 150) {
|
this.undoList[this.undoList.length - 1] = newItem;
|
} else {
|
this.undoList.push(newItem);
|
}
|
}
|
} else {
|
this.undoList.push(newItem);
|
}
|
this.redoList = [];
|
this.currentTimeStamp = currStamp;
|
},
|
// undo
|
toolActionUndo() {
|
this.isDoAction = true;
|
if (this.undoList.length >= 1) {
|
var item = this.undoList.pop();
|
var newItem = JSON.parse(JSON.stringify(item));
|
this.redoList.push(newItem);
|
var lastItem = this.undoList[this.undoList.length - 1];
|
newItem = JSON.parse(JSON.stringify(lastItem));
|
this.widgetFormData = newItem;
|
} else {
|
this.$message.error("没有可撤销的步骤了!");
|
}
|
},
|
// redo
|
toolActionRedo() {
|
this.isDoAction = true;
|
if (this.redoList.length) {
|
var item = this.redoList.pop();
|
var newItem = JSON.parse(JSON.stringify(item));
|
this.undoList.push(newItem);
|
newItem = JSON.parse(JSON.stringify(item));
|
this.widgetFormData = newItem;
|
} else {
|
this.$message.error("没有可恢复的步骤了!");
|
}
|
},
|
// todo、redo reset
|
resetDoList() {
|
this.redoList = [];
|
this.undoList = [];
|
},
|
toolActionSetting() {
|
this.settingVisible = !this.settingVisible;
|
}
|
}
|
};
|
</script>
|
|
<style lang="scss" scoped>
|
@import "./styles/index.scss";
|
|
.el-container {
|
height: 100% !important;
|
}
|
|
.el-radio + .el-radio {
|
margin-left: 0 !important;
|
}
|
.el-radio {
|
margin-right: 30px;
|
line-height: 32px;
|
}
|
.el-checkbox + .el-checkbox {
|
margin-left: 0 !important;
|
}
|
.el-checkbox {
|
margin-right: 30px;
|
}
|
|
.attribute-config-container {
|
.el-tabs__header {
|
margin: 0;
|
}
|
}
|
</style>
|