7 changed files with 771 additions and 64 deletions
@ -0,0 +1,78 @@ |
|||||
|
<template> |
||||
|
<div> |
||||
|
<el-checkbox |
||||
|
:indeterminate="isIndeterminate" |
||||
|
v-model="checkAll" |
||||
|
@change="handleCheckAllChange">全选</el-checkbox> |
||||
|
<div style="margin: 15px 0;"></div> |
||||
|
<el-checkbox-group v-model="checkedList" @change="handleChange"> |
||||
|
<div v-for="n in boxList" :key="n.itemId" class="mb10"> |
||||
|
<el-checkbox :label="n.itemId">{{n.label}}</el-checkbox> |
||||
|
</div> |
||||
|
</el-checkbox-group> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
export default { |
||||
|
name: 'checkBox', |
||||
|
model: { |
||||
|
prop: 'value', |
||||
|
event: 'change' |
||||
|
}, |
||||
|
props: { |
||||
|
value: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
list: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
boxList: [], |
||||
|
checkAll: false, |
||||
|
checkedList: [], |
||||
|
isIndeterminate: false, |
||||
|
pid: '', |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.boxList = this.list.filter(item => item.itemType != 'inputRange') |
||||
|
console.log('cehck-bo----', this.list) |
||||
|
this.pid = this.list[0].itemGroupId |
||||
|
}, |
||||
|
methods: { |
||||
|
handleCheckAllChange(val) { |
||||
|
|
||||
|
this.checkedList = val ? this.boxList.map(item => item.itemId) : []; |
||||
|
this.isIndeterminate = false; |
||||
|
|
||||
|
this.$emit('change', { list: this.filterArr(this.checkedList), pid: this.pid }) |
||||
|
}, |
||||
|
handleChange(value) { |
||||
|
let checkedCount = value.length; |
||||
|
this.checkAll = checkedCount === this.list.length; |
||||
|
this.isIndeterminate = checkedCount > 0 && checkedCount < this.boxList.length; |
||||
|
this.$emit('change', { list: this.filterArr(this.checkedList), pid: this.pid }) |
||||
|
}, |
||||
|
filterArr(arr) { |
||||
|
let list = [] |
||||
|
arr.forEach(item => { |
||||
|
this.boxList.forEach(n => { |
||||
|
if (item === n.itemId) list.push(n) |
||||
|
}) |
||||
|
}) |
||||
|
return list |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.mb10 { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,94 @@ |
|||||
|
<template> |
||||
|
<div class="right-wr scroll-h" :id="'wrItems' + id"> |
||||
|
<div v-for="(n, i) in list" :key="n.itemId" class="right-item"> |
||||
|
<div class="item-label">{{ n.label }}</div> |
||||
|
<div class="item-btn"> |
||||
|
<el-tag type="danger" class="mr10" @click="handleDelItem(n, i)"> |
||||
|
<i class="el-icon-delete"></i> |
||||
|
</el-tag> |
||||
|
<el-tag type="primary"> |
||||
|
<i class="el-icon-rank"></i> |
||||
|
</el-tag> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import Sortable from 'sortablejs' |
||||
|
export default { |
||||
|
name: 'DragItems', |
||||
|
props: { |
||||
|
list: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
id: { |
||||
|
type: String, |
||||
|
default: '' |
||||
|
} |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
dragList: [] |
||||
|
} |
||||
|
}, |
||||
|
mounted() { |
||||
|
|
||||
|
// this.dragSort() |
||||
|
}, |
||||
|
watch: { |
||||
|
list: { |
||||
|
handler(val) { |
||||
|
this.dragList = val.filter(item => item.itemType != 'inputRange') |
||||
|
}, |
||||
|
deep: true |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
handleDelItem(item, i) { |
||||
|
this.$emit('del', { item, index: i}) |
||||
|
}, |
||||
|
dragSort () { |
||||
|
const el = document.getElementById(`wrItems${this.id}`) |
||||
|
this.sortTable = Sortable.create(el, { |
||||
|
group: 'right-item', |
||||
|
ghostClass: 'sortable-ghost', // Class name for the drop placeholder, |
||||
|
chosenClass: 'sortable-choose', |
||||
|
animation: 500, |
||||
|
delay: 0, |
||||
|
onEnd: evt => { |
||||
|
console.log('evt----', evt) |
||||
|
const targetRow = this.list.splice(evt.oldIndex, 1)[0] |
||||
|
this.list.splice(evt.newIndex, 0, targetRow) |
||||
|
this.$emit('drag', this.list) |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.right-wr { |
||||
|
max-height: calc(80vh - 270px); |
||||
|
overflow: auto; |
||||
|
.right-item { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
cursor: pointer; |
||||
|
padding: 10px 30px; |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
.sortable-choose { |
||||
|
background: #eee; |
||||
|
} |
||||
|
.mr10 { |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
.mb10 { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
</style> |
@ -0,0 +1,463 @@ |
|||||
|
<template> |
||||
|
<div v-if="list.length > 0" class="diy-container"> |
||||
|
<el-tabs v-model="activeName"> |
||||
|
<el-tab-pane label="自定义模板" name="first"> |
||||
|
<div class="diy-wr"> |
||||
|
<div class="left"> |
||||
|
<el-tabs tab-position="left" class="left-h"> |
||||
|
<el-tab-pane v-for="item in list" :key="item.id" :label="item.label"> |
||||
|
<div class="pd10 dialog-h-content scroll-h"> |
||||
|
<checkBox v-if="item.queryItemList" :ref="'checkbox' + item.id" |
||||
|
:list="item.queryItemList" @change="handleChangeBox" /> |
||||
|
</div> |
||||
|
</el-tab-pane> |
||||
|
|
||||
|
</el-tabs> |
||||
|
</div> |
||||
|
<div class="right"> |
||||
|
<div class="right-header"> |
||||
|
<div class="title">导出信息</div> |
||||
|
<el-button plain @click="handlePreview('')">预览</el-button> |
||||
|
</div> |
||||
|
<div> |
||||
|
<el-collapse v-model="activeCollapse" id="collapsWr"> |
||||
|
<el-collapse-item v-for="item in rightList" :key="item.id" |
||||
|
:title="item.label" :name="item.id" class="col-h"> |
||||
|
<dragItem :ref="'drag' + item.id" :list="item.queryItemList" :id="item.id" |
||||
|
@del="handleDelItem" |
||||
|
@drag="handleDrag($event, item)"></dragItem> |
||||
|
</el-collapse-item> |
||||
|
</el-collapse> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-tab-pane> |
||||
|
<el-tab-pane label="模板列表" name="second"> |
||||
|
<el-table |
||||
|
:data="tableData" |
||||
|
height="calc(80vh - 140px)" |
||||
|
style="width: 100%"> |
||||
|
<el-table-column |
||||
|
type="index" |
||||
|
label="序号" |
||||
|
align="center" |
||||
|
width="50"> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="name" |
||||
|
label="模板名称" |
||||
|
align="center" |
||||
|
min-width="180"> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
prop="createdBy" |
||||
|
align="center" |
||||
|
label="创建者" |
||||
|
width="180"> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
align="center" |
||||
|
prop="createdTime" |
||||
|
label="创建时间" |
||||
|
width="180"> |
||||
|
</el-table-column> |
||||
|
<el-table-column |
||||
|
align="center" |
||||
|
label="操作" |
||||
|
width="160"> |
||||
|
<template slot-scope="scope"> |
||||
|
<el-button v-if="scope.row.isSelf" type="text" size="small" class="div-table-button--delete" |
||||
|
@click="handleDeltemplate(scope.row.id)">删除</el-button> |
||||
|
<el-button type="text" size="small" class="div-table-button--detail" |
||||
|
@click="handlePreview(scope.row.id)">预览</el-button> |
||||
|
<el-button |
||||
|
type="text" |
||||
|
size="small" |
||||
|
class="div-table-button--edit" @click="handleExportTemplate(scope.row.id)">导出</el-button> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</el-tab-pane> |
||||
|
</el-tabs> |
||||
|
<div v-if="activeName == 'first'" class="diy-footer"> |
||||
|
<div class="left"> |
||||
|
<div class="flex-div"> |
||||
|
<div>模板名称:</div> |
||||
|
<el-input v-model="form.name" class="wd200 mr10" /> |
||||
|
<el-checkbox v-model="form.isSaveTemp">保存为常用模板</el-checkbox> |
||||
|
</div> |
||||
|
</div> |
||||
|
<el-button class="diy-button--delete" :loading="exportLoading" @click="handleExport">导出</el-button> |
||||
|
</div> |
||||
|
<el-dialog :visible.sync="diyDialog" |
||||
|
:close-on-click-modal="false" |
||||
|
:close-on-press-escape="false" |
||||
|
width="1150px" |
||||
|
append-to-body |
||||
|
top="5vh" |
||||
|
class="dialog-h" |
||||
|
@close="handleClose" |
||||
|
> |
||||
|
<div style="padding: 20px;"> |
||||
|
<el-table |
||||
|
:data="tableData" |
||||
|
height="calc(80vh - 140px)" |
||||
|
style="width: 100%"> |
||||
|
<el-table-column |
||||
|
v-for="(item, index) in previewList" |
||||
|
:label="item.label" |
||||
|
:key="index" |
||||
|
align="center" |
||||
|
min-width="120"> |
||||
|
<el-table-column |
||||
|
v-for="(n, i) in item.children" |
||||
|
:label="n.label" |
||||
|
:key="i" |
||||
|
align="center" |
||||
|
min-width="120"> |
||||
|
|
||||
|
</el-table-column> |
||||
|
</el-table-column> |
||||
|
|
||||
|
</el-table> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script> |
||||
|
import checkBox from '../../components/checkBox.vue' |
||||
|
import dragItem from '../../components/dragItem.vue' |
||||
|
import Sortable from 'sortablejs' |
||||
|
export default { |
||||
|
props: { |
||||
|
list: { |
||||
|
type: Array, |
||||
|
default: () => [] |
||||
|
}, |
||||
|
search: { |
||||
|
type: Object, |
||||
|
default: () => {} |
||||
|
} |
||||
|
}, |
||||
|
components: { |
||||
|
checkBox, |
||||
|
dragItem |
||||
|
}, |
||||
|
data() { |
||||
|
return { |
||||
|
exportLoading: false, |
||||
|
activeCollapse: ['1'], |
||||
|
activeName: 'first', |
||||
|
info: {}, |
||||
|
rightList: [], |
||||
|
form: { |
||||
|
isSaveTemp: false, |
||||
|
name: '', |
||||
|
itemList: [] |
||||
|
}, |
||||
|
tableData: [], |
||||
|
previewList: [], |
||||
|
diyDialog: false, |
||||
|
} |
||||
|
}, |
||||
|
created() { |
||||
|
this.list.forEach(item => { |
||||
|
this.$set(this.info, item.id, []) |
||||
|
}) |
||||
|
console.log('infodiy----', this.list) |
||||
|
this.getTemplateList() |
||||
|
}, |
||||
|
watch: { |
||||
|
rightList: { |
||||
|
handler(val) { |
||||
|
if (val.length > 0) this.dragSort() |
||||
|
|
||||
|
}, |
||||
|
deep: true |
||||
|
} |
||||
|
}, |
||||
|
methods: { |
||||
|
handleChangeBox({list, pid}) { |
||||
|
console.log('ccccc----', list) |
||||
|
// if (list.length == 0) return |
||||
|
let obj = {} |
||||
|
this.list.forEach(item =>{ |
||||
|
if (item.id == pid) obj = { ...item, queryItemList: [...list] } |
||||
|
}) |
||||
|
const groups = this.rightList.map(item => item.id) |
||||
|
if (groups.includes(pid)) { |
||||
|
this.rightList.forEach((item, i) => { |
||||
|
if (item.id == pid ) { |
||||
|
item.queryItemList = [...list] |
||||
|
if (list.length == 0) this.rightList.splice(i, 1) |
||||
|
} |
||||
|
}) |
||||
|
} else { |
||||
|
this.rightList.push(obj) |
||||
|
|
||||
|
this.$nextTick(() => { |
||||
|
console.log('itemttt------', this.$refs[`drag${pid}`]) |
||||
|
this.$refs[`drag${pid}`][0].dragSort() |
||||
|
}) |
||||
|
} |
||||
|
this.activeCollapse = [...this.activeCollapse, pid] |
||||
|
}, |
||||
|
handleDelItem(val) { |
||||
|
const { item, index } = val |
||||
|
console.log('item------', item, this.$refs[`checkbox${item.itemGroupId}`]) |
||||
|
const checkList = this.$refs[`checkbox${item.itemGroupId}`][0].checkedList |
||||
|
checkList.forEach((n, i) => { |
||||
|
if (n == item.itemId) this.$refs[`checkbox${item.itemGroupId}`][0].checkedList.splice(i, 1) |
||||
|
}) |
||||
|
this.rightList.forEach((n, i) => { |
||||
|
if (n.id === item.itemGroupId) { |
||||
|
n.queryItemList.splice(index, 1) |
||||
|
if (n.queryItemList.length === 0) this.rightList.splice(i, 1) |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
}, |
||||
|
dragSort() { |
||||
|
const el = document.getElementById('collapsWr') |
||||
|
this.sortTable = Sortable.create(el, { |
||||
|
group: 'el-collapse-item', |
||||
|
ghostClass: 'sortable-ghost', // Class name for the drop placeholder, |
||||
|
animation: 500, |
||||
|
delay: 0, |
||||
|
onEnd: evt => { |
||||
|
console.log('evt----', evt) |
||||
|
const targetRow = this.rightList.splice(evt.oldIndex, 1)[0] |
||||
|
this.rightList.splice(evt.newIndex, 0, targetRow) |
||||
|
} |
||||
|
}) |
||||
|
}, |
||||
|
handleDrag(val, item) { |
||||
|
console.log('drag-----', val) |
||||
|
console.log('drag-----', item) |
||||
|
this.rightList.forEach((n, i) => { |
||||
|
if (item.id == n.id) n.queryItemList = [...val] |
||||
|
}) |
||||
|
}, |
||||
|
handleClose() { |
||||
|
this.previewList = [] |
||||
|
this.diyDialog = false |
||||
|
}, |
||||
|
handleDeltemplate(id) { |
||||
|
this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', { |
||||
|
confirmButtonText: '确定', |
||||
|
cancelButtonText: '取消', |
||||
|
type: 'warning' |
||||
|
}).then(() => { |
||||
|
this.delTemplate(id) |
||||
|
}).catch(() => { |
||||
|
this.$message({ |
||||
|
type: 'info', |
||||
|
message: '已取消删除' |
||||
|
}); |
||||
|
}) |
||||
|
}, |
||||
|
handlePreview(id) { |
||||
|
if (id) this.getPreview(id) |
||||
|
else { |
||||
|
if (this.rightList.length == 0) return this.$message.error('请选择导出信息') |
||||
|
this.previewList = this.rightList.map(item => { |
||||
|
return { |
||||
|
label: item.label, |
||||
|
children: item.queryItemList |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
this.diyDialog = true |
||||
|
}, |
||||
|
handleExport() { |
||||
|
if (this.rightList.length === 0) return this.$message.error('请选择导出信息') |
||||
|
if (this.form.isSaveTemp && !this.form.name) return this.$message.error('请输入模板名称') |
||||
|
this.exportLoading = true |
||||
|
this.exportTemplate() |
||||
|
|
||||
|
}, |
||||
|
handleExportTemplate(id) { |
||||
|
this.exportTemplate(id) |
||||
|
}, |
||||
|
async exportTemplate(id) { |
||||
|
let url = "/epmetuser/icresiuser/exportExcelCustom" |
||||
|
|
||||
|
let params = { |
||||
|
templateId: id || '', |
||||
|
searchForm: {...this.search}, |
||||
|
exportConfig: { |
||||
|
...this.form, |
||||
|
formCode: 'resi_base_info', |
||||
|
itemList: this.rightList.map(item => { |
||||
|
return { |
||||
|
itemId: item.id, |
||||
|
label: item.label, |
||||
|
tableName: item.queryItemList[0].tableName, |
||||
|
children: item.queryItemList, |
||||
|
supportAdd: item.supportAdd |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
} |
||||
|
await this.$http({ |
||||
|
method: 'POST', |
||||
|
url, |
||||
|
responseType: 'blob', |
||||
|
data: params |
||||
|
}) |
||||
|
.then(res => { |
||||
|
console.log('res----dddd', res) |
||||
|
// this.download(res.data, title + '.xls') |
||||
|
this.getTemplateList() |
||||
|
if (res.headers["content-disposition"]) { |
||||
|
let fileName = window.decodeURI(res.headers["content-disposition"].split(";")[1].split("=")[1]) |
||||
|
console.log('filename', fileName) |
||||
|
let blob = new Blob([res.data], { type: 'application/vnd.ms-excel' }) |
||||
|
var url = window.URL.createObjectURL(blob) |
||||
|
var aLink = document.createElement('a') |
||||
|
aLink.style.display = 'none' |
||||
|
aLink.href = url |
||||
|
aLink.setAttribute('download', fileName) |
||||
|
document.body.appendChild(aLink) |
||||
|
aLink.click() |
||||
|
document.body.removeChild(aLink) //下载完成移除元素 |
||||
|
window.URL.revokeObjectURL(url) //释放掉blob对象 |
||||
|
this.$message.success('导出成功') |
||||
|
this.$emit('close') |
||||
|
} else this.$message.error('下载失败') |
||||
|
this.exportLoading = false |
||||
|
}) |
||||
|
.catch(err => { |
||||
|
console.log('err', err) |
||||
|
this.exportLoading = false |
||||
|
return this.$message.error('网络错误') |
||||
|
}) |
||||
|
}, |
||||
|
async getTemplateList () { |
||||
|
let params = { |
||||
|
formCode: 'resi_base_info' |
||||
|
} |
||||
|
await this.$http |
||||
|
.post('/oper/customize/icExportTemplate/templateList', params) |
||||
|
.then(({ data: res }) => { |
||||
|
if (res.code !== 0) { |
||||
|
return this.$message.error(res.msg) |
||||
|
} else { |
||||
|
this.tableData = res.data |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
return this.$message.error('网络错误') |
||||
|
}) |
||||
|
}, |
||||
|
async getPreview (id) { |
||||
|
let params = { |
||||
|
id: id || '' |
||||
|
} |
||||
|
await this.$http |
||||
|
.post('/oper/customize/icExportTemplate/templateDetail', params) |
||||
|
.then(({ data: res }) => { |
||||
|
if (res.code !== 0) { |
||||
|
return this.$message.error(res.msg) |
||||
|
} else { |
||||
|
this.previewList = res.data |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
return this.$message.error('网络错误') |
||||
|
}) |
||||
|
}, |
||||
|
async delTemplate(id) { |
||||
|
let params = [id] |
||||
|
await this.$http |
||||
|
.post('/oper/customize/icExportTemplate/delete', params) |
||||
|
.then(({ data: res }) => { |
||||
|
if (res.code !== 0) { |
||||
|
return this.$message.error(res.msg) |
||||
|
} else { |
||||
|
this.$message({ |
||||
|
type: 'success', |
||||
|
message: '删除成功!' |
||||
|
}); |
||||
|
this.getTemplateList() |
||||
|
} |
||||
|
}) |
||||
|
.catch(() => { |
||||
|
return this.$message.error('网络错误') |
||||
|
}) |
||||
|
}, |
||||
|
} |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style lang="scss" scoped> |
||||
|
.diy-container { |
||||
|
padding: 20px 20px 0 20px; |
||||
|
} |
||||
|
.diy-wr { |
||||
|
display: flex; |
||||
|
width: 100%; |
||||
|
height: calc(80vh - 120px); |
||||
|
.left { |
||||
|
width: 49%; |
||||
|
} |
||||
|
.right { |
||||
|
flex-shrink: 0; |
||||
|
width: 50%; |
||||
|
height: 100%; |
||||
|
box-sizing: border-box; |
||||
|
margin-left: 20px; |
||||
|
padding: 0 20px; |
||||
|
border-left: 1px solid #eee; |
||||
|
.right-header { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding-bottom: 10px; |
||||
|
// border-bottom: 1px solid #eee; |
||||
|
.title { |
||||
|
font-weight: 500; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
.diy-footer { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
margin-top: 10px; |
||||
|
} |
||||
|
.left-h { |
||||
|
|
||||
|
::v-deep .el-tabs__header.is-left, |
||||
|
::v-deep .el-tabs__nav-wrap.is-left::after { |
||||
|
height: calc(80vh - 120px); |
||||
|
} |
||||
|
} |
||||
|
.flex-div { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
} |
||||
|
// #collapsWr { |
||||
|
// .col-h { |
||||
|
// ::v-deep .el-collapse-item__wrap { |
||||
|
// max-height: calc(80vh - 220px); |
||||
|
// // overflow: auto; |
||||
|
// } |
||||
|
|
||||
|
// } |
||||
|
// } |
||||
|
.mb10 { |
||||
|
margin-bottom: 10px; |
||||
|
} |
||||
|
.pd10 { |
||||
|
padding: 10px; |
||||
|
} |
||||
|
.mr10 { |
||||
|
margin-right: 10px; |
||||
|
} |
||||
|
.wd200 { |
||||
|
width: 200px; |
||||
|
} |
||||
|
</style> |
Loading…
Reference in new issue