<template>
|
<el-tabs value="field-tab" class="components-list">
|
<el-tab-pane label="字段选择器" name="field-tab">
|
<el-collapse accordion>
|
<el-collapse-item ref="master-table-item" title="主表字段">
|
<template slot="title">
|
<span class="left title">{{ currentModuleNode.cnName }}</span>
|
<el-popover ref="tree-popover" class="right" width="400" trigger="manual">
|
<el-button slot="reference" type="text" @click.stop="()=>{$refs['tree-popover'].doShow();}">选择模块</el-button>
|
<el-scrollbar :noresize="false" :native="false" wrap-class="tree scrollbar-wrap">
|
<el-tree ref="module-tree" :load="loadModuleNode" :props="moduleProps" lazy @node-click="moduleclick">
|
<span slot-scope="{ node, data }" class="custom-tree-node">
|
<template v-if="!node.isLeaf">
|
<span v-if="node.expanded">
|
<i class="el-icon-yrt-wenjianjiazhankai"></i> {{ node.label }}
|
</span>
|
<span v-else>
|
<i class="el-icon-yrt-wenjianjia"></i> {{ node.label }}
|
</span>
|
</template>
|
<template v-else>
|
<span>
|
<i class="el-icon-yrt-wenjian1"></i> {{ node.label }}
|
</span>
|
</template>
|
</span>
|
</el-tree>
|
</el-scrollbar>
|
<el-footer style="padding-top:10px;border-top:1px solid #f3f3f3;text-align:right;">
|
<el-button type="primary" @click="()=>{$refs['tree-popover'].doClose();}">关闭</el-button>
|
</el-footer>
|
</el-popover>
|
</template>
|
<el-scrollbar :noresize="false" :native="false" wrap-class="fields scrollbar-wrap">
|
<draggable :list="fieldComponents" :options="{group:{ name:'people', pull:'clone',put:false},sort:false, ghostClass: 'ghost'}" :move="handleMove" tag="ul" @end="handleMoveEnd" @start="handleMoveStart">
|
<li v-for="(item, index) in fieldComponents" :key="index" class="form-edit-widget-label">
|
<a>
|
<i :class="item.icon"></i>
|
<span>{{ item.label.title }}</span>
|
</a>
|
</li>
|
</draggable>
|
</el-scrollbar>
|
</el-collapse-item>
|
<el-collapse-item title="明细字段">
|
<template v-if="currentDetailFields.length">
|
<el-scrollbar :noresize="false" :native="false" wrap-class="fields scrollbar-wrap">
|
<draggable :list="currentDetailFields" :options="{group:{ name:'people', pull:'clone',put:false},sort:false, ghostClass: 'ghost'}" :move="handleMove" tag="ul" @end="handleMoveEnd" @start="handleMoveStart">
|
<li v-for="(item, index) in currentDetailFields" :key="index" class="form-edit-widget-label">
|
<a>
|
<i :class="item.icon"></i>
|
<span>{{ item.label }}</span>
|
</a>
|
</li>
|
</draggable>
|
</el-scrollbar>
|
</template>
|
<template v-else>
|
<div class="margin-top-no margin-bottom-20 padding-0-10 color-gray">这里是表单明细字段列表,请在编辑页面中关联子表名</div>
|
</template>
|
</el-collapse-item>
|
<el-collapse-item title="基础字段">
|
<draggable :list="basicComponents" :options="{group:{ name:'people', pull:'clone',put:false},sort:false, ghostClass: 'ghost'}" :move="handleMove" tag="ul" @end="handleMoveEnd" @start="handleMoveStart">
|
|
<li v-for="(item, index) in basicComponents" :key="index" class="form-edit-widget-label">
|
<a>
|
<i :class="item.icon"></i>
|
<span>{{ item.label.title }}</span>
|
</a>
|
</li>
|
</draggable>
|
</el-collapse-item>
|
</el-collapse>
|
</el-tab-pane>
|
<el-tab-pane label="模板选择" name="template-tab" class="template-tab">
|
<el-form class="form-tool">
|
<el-form-item>
|
<el-input v-model="filterText" placeholder="搜索名称" prefix-icon="el-icon-search" class="search-input">
|
</el-input>
|
<el-button title="刷新" class="btn-refresh" icon="el-icon-yrt-shuaxin" @click.native="treeRefresh"></el-button>
|
</el-form-item>
|
<el-form-item>
|
<!--数据tree-->
|
<el-tree ref="template-tree" :data="dataTree" :props="templateProps" :load="(node, resolve)=>{loadTemplateNode(node, resolve)}" :filter-node-method="filterTreeNode" :draggable="treeDraggable" highlight-currentlazy lazy node-key="printTemplate_Id" @node-click="templateNodeclick" @node-drag-start="treeNodeDragStart" @node-drag-end="treeNodeDragEnd">
|
<span slot-scope="{ node, data }" class="custom-tree-node" @mouseover="() => treeNodeOver(node, data)" @mouseout="() => treeNodeOut(node, data)">
|
<span>
|
<i v-if="data.hasChild" class="el-icon-menu"></i>
|
<i v-else class="el-icon-tickets"></i>
|
<template v-if="data.isEdit">
|
<el-input v-model="data.label" size="mini" class="w-150" @blur="treeNodeEditBlur(node, data)" @click.native.stop></el-input>
|
</template>
|
<template v-else>
|
{{ node.label }}
|
</template>
|
</span>
|
<span v-show="data==treeNodeOverItem">
|
<el-button type="text" size="mini" title="复制" @click="() => treeNodeCopy(node, data)">
|
<i class="el-icon-yrt-fuzhi" />
|
</el-button>
|
<el-button type="text" size="mini" title="添加子级" @click="() => treeNodeAppend(node, data)">
|
<i class="el-icon-circle-plus-outline" />
|
</el-button>
|
<el-button type="text" size="mini" title="编辑" @click.stop="() => treeNodeEdit(node, data)">
|
<i class="el-icon-edit-outline" />
|
</el-button>
|
<el-button type="text" size="mini" title="删除" @click="() => treeNodeRemove(node, data)">
|
<i class="el-icon-delete"></i>
|
</el-button>
|
</span>
|
</span>
|
</el-tree>
|
|
</el-form-item>
|
</el-form>
|
</el-tab-pane>
|
</el-tabs>
|
</template>
|
|
<script>
|
import Draggable from 'vuedraggable'
|
import { fieldComponents } from '../componentsConfig.js'
|
|
export default {
|
name: 'left-aside',
|
components: {
|
Draggable
|
},
|
props: {
|
basicComponents: {
|
type: Array,
|
default: () => []
|
},
|
detailFields: {
|
type: Array,
|
default: () => []
|
},
|
moduleNode: {
|
type: Object,
|
default: () => {}
|
},
|
widgetFormData: {
|
type: Object,
|
default: () => {}
|
},
|
resetDoList: {
|
type: Function,
|
default: () => {
|
return () => {}
|
}
|
}
|
},
|
data() {
|
return {
|
fieldComponents,
|
// 搜索关键词
|
filterText: '',
|
// tree数据集合
|
dataTree: [],
|
// 鼠标滑过Item
|
treeNodeOverItem: {},
|
// 鼠标选中Item
|
currentTreeNode: {},
|
// 记录修改前当前行名称
|
currentOldLabel: null,
|
|
// 模块tree prop参数配置
|
moduleProps: {
|
label: 'cnName',
|
// children: "zones",
|
isLeaf: function(data, node) {
|
return data.hasChild !== 1
|
}
|
},
|
|
// 模板tree prop参数配置
|
templateProps: {
|
label: 'templateName',
|
// children: "zones",
|
isLeaf: function(data, node) {
|
return data.hasChild !== 1
|
}
|
},
|
// 模板节点选中项
|
currentNodeKey: null,
|
// 树模板可以拖拽
|
treeDraggable: true
|
}
|
},
|
computed: {
|
currentModuleNode: {
|
get: function() {
|
return this.moduleNode
|
},
|
set: function(newVal) {
|
this.$emit('update:moduleNode', newVal) // 双向绑定,通知父级组件变量值同步更新
|
}
|
},
|
currentDetailFields: {
|
get: function() {
|
return this.detailFields
|
},
|
set: function(newVal) {
|
this.$emit('update:detailFields', newVal) // 双向绑定,通知父级组件变量值同步更新
|
}
|
},
|
currentWidgetFormData: {
|
get: function() {
|
return this.widgetFormData
|
},
|
set: function(newVal) {
|
this.$emit('update:widgetFormData', newVal) // 双向绑定,通知父级组件变量值同步更新
|
}
|
}
|
},
|
watch: {
|
filterText(val) {
|
this.$refs['template-tree'].filter(val)
|
}
|
},
|
methods: {
|
handleMoveEnd(evt) {
|
// console.log("end", evt);
|
},
|
handleMoveStart({ oldIndex }) {
|
// console.log("start", oldIndex, this.basicComponents);
|
},
|
handleMove() {
|
return true
|
},
|
// 加载模块节点树
|
loadModuleNode(node, resolve) {
|
var the = this
|
let loading = null
|
|
the.$nextTick(() => {
|
var where = ''
|
if (node.level === 0) {
|
where = { parentId: 0 }
|
|
var treeEl = the.$refs['module-tree']
|
loading = this.$loading({
|
target: treeEl.$el,
|
lock: true,
|
text: 'Loading',
|
spinner: 'el-icon-loading',
|
customClass: 'tree-loading'
|
})
|
} else {
|
where = { parentId: node.data.table_Id }
|
}
|
|
var url = '/api/common/loadTreeNode'
|
var params = {
|
folder: 'sys/core',
|
DBServer: 'Sys',
|
tableName: 'Sys_MvcTableInfo',
|
tableView: 'Sys_MvcTableInfo',
|
keyName: 'table_Id',
|
nodeName: 'cnName',
|
fixHasChild: false,
|
isBreakWay: false,
|
displayBreakWay: false,
|
parentName: 'parentId',
|
orderBy: 'orderNo desc, table_Id',
|
where: where,
|
extendColumns: 'vueData, namespace as projectName, tableView, keyIDs, codeRegular, linkColumn, sortName'
|
}
|
the.common.ajax(
|
url,
|
params,
|
res => {
|
if (res.result) {
|
resolve(res.data)
|
} else {
|
the.$message.error(res.msg)
|
}
|
if (loading) loading.close()
|
},
|
true
|
)
|
})
|
},
|
// 选择模块单击事件
|
moduleclick(data, node, element) {
|
if (!node.isLeaf) return
|
|
this.currentModuleNode = {
|
projectName: data.ProjectName,
|
cnName: data.cnName,
|
table_Id: data.table_Id,
|
tableName: data.tableName,
|
tableView: data.tableView,
|
dBServer: data.DBServer,
|
dBServerReadOnly: data.DBServerReadOnly,
|
parentId: data.parentId,
|
detailName: data.DetailName,
|
idField: data.keyIDs,
|
codeRegular: data.codeRegular,
|
linkColumn: data.linkColumn,
|
sortName: data.sortName,
|
vueData: data.vueData
|
}
|
this.loadModuleFields(data, node, element)
|
this.$refs['tree-popover'].doClose()
|
var cItem = this.$refs['master-table-item']
|
if (!cItem.isActive) {
|
cItem.handleHeaderClick()
|
}
|
},
|
// 加载模块字段
|
loadModuleFields(data, node, element) {
|
var the = this
|
var where = {
|
table_Id: data.table_Id,
|
columnComment: {
|
operator: '!=',
|
value: '分割行'
|
}
|
// isManagerDataSet: 1
|
}
|
debugger
|
var url = '/api/common/loadDataList'
|
var params = {
|
folder: 'sys/core',
|
projectName: 'Rattan.Sys',
|
tableView: 'Sys_MvcTableColumn',
|
idField: 'columnID',
|
idValue: 0,
|
menu_Id: 6,
|
pageIndex: 1,
|
pageSize: 1000,
|
total: 0,
|
where: where,
|
sortName: 'orderNo DESC, columnID'
|
}
|
|
the.common.ajax(
|
url,
|
params,
|
res => {
|
if (res.result) {
|
the.fieldComponents = res.data.rows.map((item, index, arr) => {
|
var field = {
|
type: 'field',
|
label: {
|
title: item.columnComment,
|
showColon: true,
|
styles: {
|
width: '100px',
|
'font-size': '14px',
|
'text-align': 'right',
|
'line-height': '30px'
|
}
|
},
|
text: {
|
prop: this.common.caseStyle(item.columnName),
|
styles: {
|
width: '170px',
|
'font-size': '14px',
|
'text-align': 'left',
|
'line-height': '30px'
|
}
|
},
|
icon: 'el-icon-yrt-danhangshurukuang',
|
options: {
|
x: 50,
|
y: 5,
|
z: 0,
|
w: 280,
|
h: 30,
|
minw: 30,
|
minh: 30,
|
parent: true,
|
snap: false,
|
snapTolerance: 20
|
},
|
styles: {
|
'font-size': '16px',
|
'font-weight': 'normal',
|
'font-style': 'normal',
|
'white-space': 'nowrap',
|
'text-decoration': 'none'
|
}
|
}
|
|
return field
|
})
|
} else {
|
the.$message({
|
showClose: true,
|
duration: 6000,
|
message: res.msg,
|
type: 'error'
|
})
|
}
|
},
|
true
|
)
|
},
|
|
// 加载模板节点树
|
loadTemplateNode(node, resolve) {
|
var the = this
|
|
the.$nextTick(() => {
|
var where = ''
|
if (node.level === 0) {
|
where = {
|
parentId: 0,
|
userProduct_Id: this.common.getUserInfo().userProduct_Id
|
}
|
} else {
|
where = {
|
parentId: node.data.printTemplate_Id,
|
userProduct_Id: this.common.getUserInfo().userProduct_Id
|
}
|
}
|
|
var url = '/api/common/loadTreeNode'
|
var params = {
|
folder: 'sys/print',
|
dbServer: 'Sys',
|
tableName: 'Base_PrintTemplate',
|
tableView: 'Base_PrintTemplate',
|
keyName: 'printTemplate_Id',
|
nodeName: 'templateName',
|
fixHasChild: false,
|
isBreakWay: false,
|
displayBreakWay: false,
|
parentName: 'parentId',
|
orderBy: 'orderNo desc, printTemplate_Id',
|
where: where,
|
extendColumns: 'vueData'
|
}
|
the.common.ajax(
|
url,
|
params,
|
res => {
|
if (res.result) {
|
res.data.forEach(item => {
|
item.isEdit = false
|
})
|
resolve(res.data)
|
this.$nextTick(() => {
|
if (this.currentNodeKey) {
|
this.$refs['template-tree'].setCurrentKey(this.currentNodeKey)
|
}
|
})
|
} else {
|
the.$message.error(res.msg)
|
}
|
},
|
this.$refs['template-tree']
|
)
|
})
|
},
|
// 搜索导航
|
filterTreeNode(value, data) {
|
if (!value) return true
|
return data.label.indexOf(value) !== -1
|
},
|
// 选择模块单击事件
|
templateNodeclick(data, node, element) {
|
if (this.currentTreeNode) this.currentTreeNode.isEdit = false
|
this.currentTreeNode = data
|
this.currentOldLabel = this.currentTreeNode.label
|
this.currentNodeKey = this.$refs['template-tree'].getCurrentKey()
|
|
if (data.vueData) {
|
this.resetDoList()
|
const vueData = JSON.parse(data.vueData)
|
this.currentWidgetFormData = this.common.objectToCase(vueData)
|
}
|
},
|
// 获得当前节点
|
getCurrentNode() {
|
var node = this.$refs['template-tree'].getCurrentNode()
|
return node
|
},
|
// tree鼠标进入
|
treeNodeOver(node, data) {
|
this.treeNodeOverItem = data
|
},
|
// tree鼠标移出
|
treeNodeOut(node, data) {
|
this.treeNodeOverItem = {}
|
},
|
// 刷新tree
|
treeRefresh() {
|
this.filterText = ''
|
var root = this.$refs['template-tree'].store.root
|
while (root.childNodes.length) {
|
this.$refs['template-tree'].remove(root.childNodes[0])
|
}
|
this.loadTemplateNode(root, data => {
|
root.doCreateChildren(data)
|
})
|
},
|
// 复制节点
|
treeNodeCopy(node, data) {
|
this.$prompt('请输入复制新模板名称', '复制模板', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消'
|
})
|
.then(({ value }) => {
|
if (!value) {
|
this.$message.error('名称不能为空')
|
return
|
}
|
|
var url = '/api/sys/printTemplate/copyItem'
|
var params = {
|
id: data.value, // 当前ID
|
value: value
|
}
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res)
|
this.treeRefresh()
|
},
|
this.$refs['template-tree']
|
)
|
})
|
.catch(() => {
|
this.$message({
|
type: 'info',
|
message: '取消输入'
|
})
|
})
|
},
|
// 新建节点
|
treeNodeAppend(node, data) {
|
this.$prompt('请输入模板名称', '添加子级模板', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消'
|
})
|
.then(({ value }) => {
|
if (!value) {
|
this.$message.error('名称不能为空')
|
return
|
}
|
|
var url = '/api/sys/printTemplate/addItem'
|
var params = {
|
id: data.value, // 父级ID
|
value: value
|
}
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res)
|
this.treeRefresh()
|
},
|
this.$refs['template-tree']
|
)
|
})
|
.catch(() => {
|
this.$message({
|
type: 'info',
|
message: '取消输入'
|
})
|
})
|
},
|
// 编辑节点
|
treeNodeEdit(node, data) {
|
data.isEdit = true
|
this.treeDraggable = false
|
},
|
// 删除
|
treeNodeRemove(node, data) {
|
this.$confirm('此操作将永久删除该模板, 是否继续?', '提示', {
|
confirmButtonText: '确定',
|
cancelButtonText: '取消',
|
type: 'warning'
|
})
|
.then(() => {
|
var url = '/api/sys/printTemplate/deleteItem'
|
var params = {
|
id: data.value
|
}
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res)
|
this.treeRefresh()
|
},
|
this.$refs['template-tree']
|
)
|
})
|
.catch(() => {
|
this.$message({
|
type: 'info',
|
message: '已取消删除'
|
})
|
})
|
},
|
// 失去焦点后修改数据
|
treeNodeEditBlur(node, data) {
|
data.isEdit = false
|
this.treeDraggable = true
|
if (this.currentOldLabel === data.label) {
|
return
|
}
|
|
var url = '/api/sys/printTemplate/updateTitle'
|
var params = {
|
id: data.value,
|
value: data.label
|
}
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res)
|
this.treeRefresh()
|
},
|
this.$refs['template-tree']
|
)
|
},
|
// 开始拖拽
|
treeNodeDragStart(draggingNode, evt) {},
|
// 拖拽操作
|
treeNodeDragEnd(draggingNode, dropNode, dropType, evt) {
|
if (!this.treeDraggable) {
|
this.treeDraggable = true
|
return
|
}
|
// 不允许拖入到子集的下面
|
var stopChildren = draggingNode.childNodes.find(item => {
|
return item.data.value === dropNode.data.value
|
})
|
if (stopChildren) {
|
return
|
}
|
// 拖拽到自己身上不响应
|
if (draggingNode.data.value === dropNode.data.value) {
|
return
|
}
|
|
var url = '/api/sys/printTemplate/moveItem'
|
var params = {
|
id: draggingNode.data.value, // 当前ID
|
value: dropNode.data.value // 父级ID
|
}
|
this.common.ajax(
|
url,
|
params,
|
res => {
|
this.common.showMsg(res)
|
this.treeRefresh()
|
},
|
this.$refs['template-tree']
|
)
|
}
|
}
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
$primary-color: #409eff;
|
$primary-background-color: #ecf5ff;
|
|
.components-list {
|
padding: 0;
|
width: 100%;
|
height: 100%;
|
overflow-x: hidden;
|
|
.widget-cate {
|
padding: 8px 12px;
|
font-size: 13px;
|
}
|
|
ul {
|
position: relative;
|
overflow: hidden;
|
padding: 0 10px 10px;
|
margin: 0;
|
}
|
|
.form-edit-widget-label {
|
font-size: 12px;
|
display: block;
|
width: 48%;
|
line-height: 26px;
|
position: relative;
|
float: left;
|
left: 0;
|
overflow: hidden;
|
text-overflow: ellipsis;
|
white-space: nowrap;
|
margin: 1%;
|
color: #333;
|
border: 1px solid #f4f6fc;
|
|
&:hover {
|
color: $primary-color;
|
border: 1px dashed $primary-color;
|
}
|
|
& > a {
|
display: block;
|
cursor: move;
|
background: #f4f6fc;
|
border: 1px solid #f4f6fc;
|
|
i {
|
margin-right: 6px;
|
margin-left: 8px;
|
font-size: 16px;
|
display: inline-block;
|
vertical-align: middle;
|
|
&.el-icon-yrt-danhangshurukuang {
|
font-size: 20px;
|
margin-top: -5px;
|
margin-right: 3px;
|
}
|
|
&.el-icon-yrt-fuhao-shuzishurukuang {
|
font-size: 20px;
|
margin-right: 3px;
|
margin-top: -5px;
|
}
|
|
&.el-icon-yrt-kaiguanclose {
|
font-size: 20px;
|
margin-right: 3px;
|
margin-top: -5px;
|
}
|
}
|
|
span {
|
display: inline-block;
|
vertical-align: middle;
|
}
|
}
|
}
|
|
.el-collapse-item__header {
|
padding-left: 10px;
|
}
|
|
.el-collapse-item__content {
|
padding-bottom: 0px;
|
}
|
}
|
|
.scrollbar-wrap {
|
ul {
|
margin-bottom: 10px;
|
}
|
}
|
|
/deep/ .tree.scrollbar-wrap {
|
max-height: 410px;
|
overflow-x: hidden;
|
padding: 10px;
|
|
.el-tree {
|
margin-bottom: 10px;
|
}
|
}
|
|
/deep/ .fields.scrollbar-wrap {
|
max-height: 410px;
|
overflow-x: hidden;
|
padding: 0px;
|
}
|
|
.template-tab {
|
width: 100%;
|
height: 100%;
|
background-color: white;
|
border-radius: 4px;
|
.form-tool {
|
padding-top: 10px;
|
.el-form-item {
|
padding: 0 10px;
|
}
|
.search-input {
|
width: calc(100% - 40px);
|
}
|
.btn-search,
|
.btn-refresh {
|
padding: 10px;
|
}
|
.btn-refresh {
|
margin-left: 0px;
|
}
|
}
|
/deep/ .el-tree-node.is-current > .el-tree-node__content {
|
background-color: #a7ccf7;
|
color: white;
|
.el-button--text {
|
color: white;
|
}
|
height: 30px;
|
}
|
.custom-tree-node {
|
flex: 1;
|
display: flex;
|
align-items: center;
|
justify-content: space-between;
|
font-size: 14px;
|
padding-right: 8px;
|
}
|
.el-button + .el-button {
|
margin-left: 3px;
|
}
|
}
|
</style>
|