iview-admin的行编辑官方并没有给出代码demo,
希望做到如同easyi-ui可编辑行组件类似
最终效果图如下
先定义编辑文本
- 可编辑文本组件
<template>
<div class="input-edit-outer">
<div v-if="!isEditting" class="input-edit-con">
<span class="value-con">{{ newValue ? newValue : '-' }}</span></div>
<div v-else class="input-editting-con">
<Input :value="newValue" @input="handleInput" class="input-edit-input"/>
</div>
</div>
</template>
<script>
export default {
name: 'EditTable',
data(){
return {
newValue:''
}
},
props: {
edittingCellId: [String, Number],
id: [String, Number],
params: Object,
value:[String, Number]
},
computed: {
isEditting () {
return this.edittingCellId === `editting-${this.params.index}-${this.id}`
}
},
methods: {
handleInput (val) {
this.$emit('input', val)
}
},
mounted(){
this.newValue = this.value
}
}
</script>
<style lang="less" scoped>
.input-edit-outer{
height: 100%;
.input-edit-con{
height: 100%;
.value-con{
vertical-align: middle;
}
}
.input-editting-con{
.input-edit-input{
width: ~"calc(100% - 60px)";
}
}
}
</style>
- 可编辑下拉组件
<template>
<div class="select-edit-outer">
<div v-if="!isEditting" class="select-edit-con">
<span class="value-con">{{ displayText ? displayText : '-' }}</span>
</div>
<div v-else class="select-editting-con">
<Select :value="displayValue" class="select-edit-input" @on-change="onChange">
<Option v-for="item in options" :value="item.value" :key="item.value">{{ item.label }}</Option>
</Select>
</div>
</div>
</template>
<script>
export default {
name: 'SelectTable',
data(){
return{
displayText : '',
displayValue : '',
selectOptions:[]
}
},
props: {
edittingCellId: [String, Number],
params: Object,
value:[String, Number],
id:[String, Number],
options:Array
},
computed: {
isEditting () {
return this.edittingCellId === `editting-${this.params.index}-${this.id}`
}
},
methods: {
onChange (val) {
this.$emit('on-change', val)
}
},
mounted(){
this.displayValue = this.value
this.displayText = this.options.find(ele => ele.value == this.value).label//根据value值获取options的对应的值
},
watch:{
}
}
</script>
<style lang="less" scoped>
.select-edit-outer{
height: 100%;
.select-edit-con{
height: 100%;
.value-con{
vertical-align: middle;
}
}
.select-editting-con{
.select-edit-input{
width: ~"calc(100% - 60px)";
}
}
}
</style>
3.父组件
<style lang="less">
@import './dynamicLogLevel.less';
</style>
<template>
<div class="dynamicLogLevel">
<Row>
<tables ref="tables" editable :border="true" size="small"
v-model="tableData" :columns="columns"
:simple="simple" />
</Row>
<Modal ref="createModal" :closable="false" draggable v-model="createModal" width="300">
<div slot="header">
<span>{{ createTitle }}</span>
</div>
<Form ref="createForm" :model="createForm" :rules="ruleValidate" >
<Row>
<FormItem prop="logger">
<Input type="text" v-model="createForm.logger" :maxlength="50" placeholder="logger名"></Input>
</FormItem>
</Col>
</Row>
<Row>
<FormItem prop="loggerLevel">
<Select v-model="createForm.loggerLevel" filterable placeholder="请选择日志级别">
<Option value="DEBUG">DEBUG</Option>
<Option value="INFO">INFO</Option>
<Option value="ERROR">ERROR</Option>
</Select>
</FormItem>
</Row>
<Row>
<FormItem prop="loggerState">
<Select v-model="createForm.loggerState" filterable placeholder="请选择有效状态">
<Option value="TRUE">TRUE</Option>
<Option value="FALSE">FALSE</Option>
</Select>
</FormItem>
</Row>
</Form>
<div slot="footer" align="center">
<Button type="default" size="large" @click="cancle('createForm')">取消</Button>
<Button type="primary" size="large" @click="query('createForm')">新建配置</Button>
</div>
</Modal>
</div>
</template>
<script>
import Tables from '_c/tables'
import EditTable from '_c/editTable'
import SelectTable from '_c/selectTable'
import InputTable from '_c/inputTable'
import { getHostsData, getRecordData } from '@/api/data'
import config from '@/config'
export default{
name: 'hosts',
components: {
Tables
},
data () {
return {
simple:false,
columns: [
{
title: ' ',
width:120,
align: 'left',
render: (h, params) => {
let isExpand = params.row.isExpand
let isDown = params.row.isDown
let level = params.row.level
let marginLeft = '0'
let iconType = !isDown ? 'ios-arrow-forward' : 'ios-arrow-down'
//根据level是第几层去判断样式以及调用的方法
switch (level){
case 1:
marginLeft = '0'
break;
case 2:
marginLeft = '15px'
break;
case 3:
marginLeft = '30px'
iconType = 'md-create'
default:
break;
}
if(!isExpand && level != 3){
return h('div',{style:{cursor: 'pointer'}},[
h('Icon',{props:{type:iconType},style:{marginLeft:marginLeft},on:{click: (e) => {e.stopPropagation();this.doWhich(level, params)}}})
])
}else if(level === 3){
//当level 为3时,返回的是操作按钮
return h(EditTable, {
props: {
edittingCellId: this.edittingCellId,
params:params,
id:params.row.id
},
style:{
marginLeft:'30px'
},
on: {
'on-start-edit-table': (newParams) => {
this.editedParams = params
this.edittingCellId = `editting-${newParams.index}-${params.row.id}`//此值要确保是唯一值
},
'on-cancel-edit-table': (newParams) => {
this.edittingCellId = ''
},
'on-save-edit-table': (newParams) => {
this.edittingCellId = ''
this.onSaveEditRow()
}
}
})
}else{
return ''
}
}
},
{title: '项目名', key: 'jobName', sortable:true, align: 'center'},
{
title: '级别',
key: 'levelState',
sortable:true,
align: 'center',
render:(h, params) =>{
return h(SelectTable, {
props: {
edittingCellId: this.edittingCellId,
params:params,
value:params.row.levelState,
options: [{
value: 'DEBUG',
label: 'DEBUG'
}, {
value: 'INFO',
label: 'INFO'
}, {
value: 'ERROR',
label: 'ERROR'
}]
},
on: {
'on-select-change': (val) => {
//监听返回的select事件,将select值返回到修改后的editedParams
this.editedParams.row.levelState = val
}
}
})
}
},
{
title: '生效状态',
key: 'disableState',
sortable:true,
align: 'center',
render:(h, params) =>{
return h(SelectTable, {
props: {
edittingCellId: this.edittingCellId,
params:params,
value:params.row.disableState,
options: [{
value: 'TRUE',
label: 'TRUE'
}, {
value: 'FALSE',
label: 'FALSE'
}]
},
on: {
'on-select-change': (val) => {
//监听返回的select事件,将select值返回到修改后的editedParams
this.editedParams.row.disableState = val
}
}
})
}
},
{
title:'操作',
width:150,
render:(h, params) =>{
let level = params.row.level
let iconType = 'md-copy'
//根据level是第几层去判断样式以及调用的方法
switch (level){
case 1:
iconType = 'ios-copy'
break;
case 2:
iconType = 'ios-document'
break;
default:
break;
}
if(level === 3){
return h('div', [
h('div',{style:{display:'inline-block'},on:{click : (e)=>{e.stopPropagation();}}},[
h('Poptip', {props: {confirm: true,title: '你确定要删除吗?'},on: {'on-ok': (e) => {this.handleDelete (params)}}}, [
h('Icon',{props:{type: 'md-trash',size:'20',color:'#2399E5'},style:{cursor:'pointer'}})
])
])
])
}else{
return h('div',{style:{cursor: 'pointer'}},[
h('Icon',{props:{type:iconType,size:20},style:{color:'#2399E5'},on:{click: (e) => {e.stopPropagation();this.doCopy(level, params)}}})
])
}
}
}
],
tableData: [],
edittingCellId:'',
editedParams:{},//编辑中的行对象
createModal:false,
createTitle:'新增动态日志配置',
createForm:{
logger:'',
loggerLevel:'',
loggerState:''
},
ruleValidate:{
logger: [
{ required: true, message: 'logger名不能为空', trigger: 'blur' }
],
loggerLevel: [
{ required: true, message: '日志级别不能为空', trigger: 'blur' }
],
loggerState: [
{ required: true, message: '有效状态不能为空', trigger: 'blur' }
]
},
createLevel:'',
createParams:{}
}
},
mounted () {
this.getHostsDatas();
},
methods: {
// 删除当前行
handleDelete(param){
console.log("param=删除当前行操作")
},
getHostsDatas(){
getHostsData().then(res => {
let tableDatas = res.data.data
tableDatas.map( item =>{
item.isExpand = false//默认数据中加上是否展开属性,默认不展开
item.level = 1 //默认第一次加载的数据为第一层数据,总共三层,第一层第二层可以展开,第三层是修改
item.isDown = false//默认行数据向下展开图标不向下
})
this.tableData = tableDatas
this.dataCount = res.data.total
})
},
expandRow1(params){
//判断当前行是否展开,如果未展开,执行以下方法,先展开再请求接口加载到tabledata中当前data index 后
if(!this.tableData[params.index].isDown){
getRecordData().then(res => {
return res.data
}).then( data => {
this.tableData[params.index].isDown = true
let newArrayData = data
this.tableData[params.index].totals = newArrayData.length //将展开操作查询到的数据总条数加到当前行数据的totals上
newArrayData.map( item =>{
item.isExpand = false
item.level = 2 //默认第一次加载的数据为第一层数据,总共三层,第一层第二层可以展开,第三层是修改
item.upLevelIndex = params.index
})
newArrayData.map( (value, key) =>{
this.tableData.splice(params.index + key + 1, 0, value)
})
})
}else{//如果当前行已展开,则隐藏
this.tableData[params.index].isDown = false
this.tableData.splice(params.index + 1, params.row.totals)
}
},
expandRow2(params){
//判断当前行是否展开,如果未展开,执行以下方法,先展开再请求接口加载到tabledata中当前data index 后
if(!this.tableData[params.index].isDown){
getRecordData().then(res => {
return res.data
}).then( data => {
this.tableData[params.index].isDown = true
let newArrayData = data
//将展开操作查询到的数据总条数加到当前行数据的上一级(level 1)的totals上
this.tableData[params.row.upLevelIndex].totals += parseInt(newArrayData.length)
//将展开操作查询到的数据总条数加到当前行数据的totals上
this.tableData[params.index].totals = newArrayData.length
newArrayData.map( item =>{
item.isExpand = false
//默认第一次加载的数据为第一层数据,总共三层,第一层第二层可以展开,第三层是修改
item.level = 3
item.upLevelIndex = params.index
})
newArrayData.map( (value, key) =>{
this.tableData.splice(params.index + key + 1, 0, value)
})
})
}else{//如果当前行已展开,则隐藏
//将展开操作查询到的数据总条数加到当前行数据的上一级(level 1)的totals上
this.tableData[params.row.upLevelIndex].totals -= parseInt(params.row.totals)
this.tableData[params.index].isDown = false
this.tableData.splice(params.index + 1, params.row.totals)
}
},
doWhich(level, params){
switch (level){
//调用1级的展开方法
case 1:
console.log("expandRow1")
this.expandRow1(params)
break;
//调用2级的展开方法
case 2:
console.log("expandRow2")
this.expandRow2(params)
break;
//调用3级的修改方法
case 3:
console.log("update")
break;
//不调用任何方法并页面提示报错
default:
this.$Modal.error({
title: "方法错误",
content: "方法调用错误,请刷新重试!"
});
break;
}
},
onSaveEditRow(){
console.log("editedParams="+JSON.stringify(this.editedParams))
},
//给当前行添加下级日志文件,如果level为1级则给下面所有的项目名IP都新增,如果是2级则只给自己当前下面IP新增
doCopy(level, params){
this.createModal = true
this.createLevel = level
this.createParams = params
},
cancle(name){
this.createModal = false
this.$refs[name].resetFields()
},
query(name){
this.$refs[name].validate((valid) => {
if (valid) {
this.createModal = false
this.$refs[name].resetFields()
} else {
this.$Message.error('请填写正确信息!');
}
})
}
},
watch:{
}
}
</script>