- 需求说明:
后端一个接口返回所有表格(具体几个表格需要根据select框选择框选择定,具体就是几列,也就是返回了几个表格都是动态的,根据接口确定)的数据,返回的表格list是静态表格的json数据,前端需要将其整合为一个对比表格。拿汽车之家的页面做一个说明:
把实现好的页面做一个说明:
后端返回数据:返回的数据是类似于一个静态表格的数据,需要前端来整合数据
- 功能说明:
- 根据select框下的选项查出对应的源端对应的值
- 全表查询模糊匹配
- 隐藏参数值相同
- 隐藏参数值为空
- 主要实现:
<vxe-grid v-bind="gridOptions" :cell-style="cellStyle" :row-style="rowStyle" :column-config="{ resizable: true, minWidth: 160 }" :tooltip-config="{theme: 'light', enterable: true}" show-overflow @cell-dblclick="celldblclick"> </vxe-grid>
const getTable = () => {
gridOptions.columns = [
{
field: 'Variable_name',
title: 'Variable_name',
width: 260,
},
]
gridOptions.data = [];
mysql_variables({
servers: source.value.join(',')
// servers: '10.9.21.54:10000,10.9.21.12:3306'
}).then(res => {
if (res.code == 200) {
var tableList = res.data;
var tableAll = [];
tableList.forEach((value, i) => { //数组循环
// console.log(value, 'valuevaluevalue');
for (var pl in value) { //数组对象遍历,获取到列名数据
// console.log(pl); //获取key
gridOptions.columns.push({
field: pl,
title: pl,
})
//获取到表格内的数据
const tableRow = value[pl].map((item, index) => {
return {
Variable_name: item.Variable_name,
[pl]: item.Value,
}
})
tableAll.push(tableRow)
}
})
// 数据集合,剥离出表格数据
let _arr = tableAll.reduce((prev, next) => {
return prev.length > next.length ? prev : next
})
_arr.forEach((itm) => {
for (let i = 0; i < tableAll.length; i++) {
tableAll[i].forEach(item => {
if (item.Variable_name == itm.Variable_name) {
for (var pl in item) {
itm[pl] = item[pl]
}
}
});
}
});
tableData.value = _arr
//筛选出参数值一致的数组
sameTable.value = [];
//筛选出参数值为空的数组
nullTable.value = [];
var nullData = []
_arr.forEach(ele => {
let itemArr = []
let itemRow = JSON.parse(JSON.stringify(ele));
delete itemRow.Variable_name;
delete itemRow._X_ROW_KEY;
for (let key in itemRow) {
itemArr.push(itemRow[key])
}
let newList = Array.from(new Set(itemArr))
if (newList.length > 1) {
sameTable.value.push(ele)
} else if (newList.length == 1 && newList[0] == '') {
nullData.push(ele)
}
})
nullTable.value = _arr.filter(item => nullData.indexOf(item) === -1);
// 处理数据选项板块
if (sameVal.value == true) {
gridOptions.data = sameTable.value;
} else if (nullVal.value == true && sameVal.value == false) {
gridOptions.data = nullTable.value;
} else {
gridOptions.data = _arr;
}
}
})
}
- 具体实现
<template>
<div class="container">
<div class="header_search">
<div class="search_son">
<div>
<span>选择源端:</span>
<el-select v-model="source" multiple filterable collapse-tags collapse-tags-tooltip placeholder="请选择"
style="width:380px;" @visible-change="sourceChange" @remove-tag="removeSource" @blur="sourceBlur">
<el-option v-for="item in sourceOptions" :key="item.ftype"
:label="`${item.fserver_host}:${item.fserver_port}:${item.frole}:${item.fstate}`"
:value="`${item.fserver_host}:${item.fserver_port}`" />
</el-select>
</div>
<div style="margin-left:20px">
<span> 全表搜索:</span>
<vxe-input v-model="filterName" type="search" clearable placeholder="试试全表搜索" @keyup="searchEvent"
style="width:340px;" @clear="searchEvent"></vxe-input>
</div>
<div style="margin-left:20px">
<el-checkbox :disabled="source.length<2" v-model="sameVal" size="large"
@change="getTable">隐藏参数值相同</el-checkbox>
<el-checkbox :disabled="source.length==0" v-model="nullVal" size="large"
@change="getTable">隐藏参数值为空</el-checkbox>
</div>
</div>
</div>
<div class="header_search">
<div class="search_son">
<el-icon style="margin-right:10px;font-weight: bold;">
<InfoFilled color="#f56c6c" size="16" />
</el-icon>
<span style="color: #f56c6c;font-weight: bold;">双击参数的值可进行修改噢!(双击
Variable_name值可复制值至粘贴板)</span>
</div>
</div>
<!-- 展示表格,先展示一个表格 -->
<div style="margin-top: 5px;height:74vh">
<vxe-grid v-bind="gridOptions" :cell-style="cellStyle" :row-style="rowStyle"
:column-config="{ resizable: true, minWidth: 160 }" :tooltip-config="{theme: 'light', enterable: true}"
show-overflow @cell-dblclick="celldblclick">
</vxe-grid>
</div>
</div>
</template>
<script setup>
import { ref, computed, reactive, toRefs, onMounted, defineProps } from 'vue'
import { mysql_detail, mysql_variables, modify_cnf } from '@/api/mysql';
import { useStore } from 'vuex';
import { useRoute } from 'vue-router';
import XEUtils from 'xe-utils'
const props = defineProps({
// 父组件 v-model 没有指定参数名,则默认是 modelValue
activeName: {
type: String,
default: 'basicInform'
}
})
onMounted(() => {
setTimeout(() => {
if (localStorage.getItem('mysql_activeName') == 'paramManage') {
// getTable();
getSorceIpPort();
}
}, 20)
});
watch(
() => props.activeName, (newVal, oldVal) => {
if (newVal == 'paramManage') {
// getTable();
getSorceIpPort();
}
}
)
// 参数定义
const route = useRoute();
const source = ref([])
const sourceOptions = ref([])
const filterName = ref('')
const sameVal = ref(false)
const nullVal = ref(false)
const tableData = ref([])
const sameTable = ref([])
const nullTable = ref([])
const slotLable = ref([])
const gridOptions = reactive({
border: true,
// 'max-height': 700,
height: 'auto',
align: 'left',
columnConfig: {
resizable: true
},
columns: [],
data: []
})
// 方法区
const rowStyle = ({
row, rowIndex, $rowIndex, column, columnIndex, $columnIndex
}) => {
var rowValue = [];
if (row.Variable_name) {
let comRow = JSON.parse(JSON.stringify(row));
delete comRow.Variable_name;
delete comRow._X_ROW_KEY;
for (let key in comRow) {
rowValue.push(comRow[key])
}
if (rowValue.length + 1 < gridOptions.columns.length) {
return {
backgroundColor: '#f56c6c1a'
}
// return 'warning-row'
}
let newList = Array.from(new Set(rowValue))
if (newList.length > 1) {
// return 'warning-row'
return {
backgroundColor: '#f56c6c1a'
}
}
// if (newList[0] == '') {
// return {
// backgroundColor: '#f56c6c1a'
// }
// }
}
return {}
}
const cellStyle = ({
row, rowIndex, $rowIndex, column, columnIndex, $columnIndex
}) => {
if (columnIndex == 0) {
// console.log(column.field);
return {
fontWeight: 'bolder',
}
}
}
const removeSource = (e) => {
if (source.value.length == 0) {
gridOptions.columns = [];
gridOptions.data = [];
}
}
const sourceBlur = (e) => {
if (source.value.length == 0) {
gridOptions.columns = [];
gridOptions.data = [];
}
}
const sourceChange = (e) => {
// console.log(source.value, '选择的内容项=====');
if (!e && source.value.length != 0) {
getTable()
}
}
const getSorceIpPort = () => {
mysql_detail({
InstanceName: route.name,
Line: '',
}).then(res => {
if (res.code == 200) {
//获取ip_port
sourceOptions.value = res.data
}
})
}
const getTable = () => {
gridOptions.columns = [
{
field: 'Variable_name',
title: 'Variable_name',
width: 260,
},
]
gridOptions.data = [];
mysql_variables({
servers: source.value.join(',')
// servers: '10.9.21.54:10000,10.9.21.12:3306'
}).then(res => {
if (res.code == 200) {
var tableList = res.data;
var tableAll = [];
tableList.forEach((value, i) => { //数组循环
// console.log(value, 'valuevaluevalue');
for (var pl in value) { //数组对象遍历,获取到列名数据
// console.log(pl); //获取key
gridOptions.columns.push({
field: pl,
title: pl,
})
//获取到表格内的数据
const tableRow = value[pl].map((item, index) => {
return {
Variable_name: item.Variable_name,
[pl]: item.Value,
}
})
tableAll.push(tableRow)
}
})
// 数据集合,剥离出表格数据
let _arr = tableAll.reduce((prev, next) => {
return prev.length > next.length ? prev : next
})
_arr.forEach((itm) => {
for (let i = 0; i < tableAll.length; i++) {
tableAll[i].forEach(item => {
if (item.Variable_name == itm.Variable_name) {
for (var pl in item) {
itm[pl] = item[pl]
}
}
});
}
});
tableData.value = _arr
//筛选出参数值一致的数组
sameTable.value = [];
//筛选出参数值为空的数组
nullTable.value = [];
var nullData = []
_arr.forEach(ele => {
let itemArr = []
let itemRow = JSON.parse(JSON.stringify(ele));
delete itemRow.Variable_name;
delete itemRow._X_ROW_KEY;
for (let key in itemRow) {
itemArr.push(itemRow[key])
}
let newList = Array.from(new Set(itemArr))
if (newList.length > 1) {
sameTable.value.push(ele)
} else if (newList.length == 1 && newList[0] == '') {
nullData.push(ele)
}
// for (let k = 0; k < newList.length; k++) {
// if (newList[k] == '') {
// nullData.push(ele)
// }
// }
})
nullTable.value = _arr.filter(item => nullData.indexOf(item) === -1);
// 处理数据选项板块
if (sameVal.value == true) {
gridOptions.data = sameTable.value;
} else if (nullVal.value == true && sameVal.value == false) {
gridOptions.data = nullTable.value;
} else {
gridOptions.data = _arr;
}
}
})
}
const searchEvent = () => {
sameVal.value = false;
nullVal.value = false;
const filterVal = String(filterName.value).trim().toLowerCase()
if (filterVal) {
const filterRE = new RegExp(filterVal, 'gi')
const searchProps = gridOptions.columns.map(item => {
return item.field
})
const rest = tableData.value.filter(item => searchProps.some(key => String(item[key]).toLowerCase().indexOf(filterVal) > -1))
gridOptions.data = rest.map(row => {
const item = Object.assign({}, row)
searchProps.forEach(key => {
item[key] = String(item[key]).replace(filterRE, match => match)
})
return item
})
} else {
gridOptions.data = tableData.value
}
}
//双击复制单元格内容
const celldblclick = ({ row, rowIndex, $rowIndex, column, columnIndex, $columnIndex, $event }) => {
if (columnIndex == 0) {
var save = function (e) {
e.clipboardData.setData('text/plain', row[column.property]);
e.preventDefault();//阻止默认行为
}
document.addEventListener('copy', save);
document.execCommand("copy");
document.removeEventListener('copy', save);
// this.$message({message: '复制成功', type:'success'}) //加提示
ElMessage({
type: 'success',
message: 'Variable_name值已复制至剪切板'
})
} else {
ElMessageBox.prompt(`修改【${column.property}】下的${row.Variable_name}值:`, `提示`, {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputValue: row[column.property],
})
.then(({ value }) => {
console.log(value, '输入的值=====');
modify_cnf({
ServerPort: column.property.split(':')[1],
ParamName: row.Variable_name,
Value: value,
ServerHost: column.property.split(':')[0],
}).then(res => {
if (res.code == 200) {
ElMessage({
type: 'success',
message: `修改成功`,
})
getTable();
} else {
ElMessage({
type: 'error',
message: `修改失败`,
})
}
})
})
.catch(() => {
// ElMessage({
// type: 'info',
// message: 'Input canceled',
// })
})
}
}
</script>
<style lang="scss" scoped>
.container {
width: 100%;
}
.header_search {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between;
}
.search_son {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
</style>