sac/sf-ui/src/views/gateway/route/editTable.vue

277 lines
9.7 KiB
Vue
Raw Normal View History

2025-05-21 15:29:38 +08:00
<template>
<div>
<el-row type="flex" justify="end">
<el-button
v-if="editable"
type="primary"
plain
icon="el-icon-plus"
size="mini"
@click="handleAddRow"
>新增一行</el-button>
</el-row>
<el-form :model="formModel" ref="form" class="table-form" @validate="validateForm">
<el-table v-loading="loading" :data="formModel.tableData" style="margin-top: 10px;" max-height="400" border>
<template v-if="routeType === 'WEIGHT_ROUTE'">
<el-table-column prop="weight" width="240" key="weight">
<template slot="header">
<span class="required-asterisk">流量占比(%)</span>
</template>
<template slot-scope="{row, $index}">
<template v-if="!editable">{{ row.weight }}</template>
<template v-else>
<el-form-item
:prop="`tableData[${$index}].weight`"
:rules="[
{ required: true, message: '流量占比不能为空', trigger: 'blur' },
{ type: 'number', message: '流量占比必须为数字值', trigger: 'blur' }
]"
>
<el-input-number
v-model="tableData[$index].weight"
placeholder="请输入流量占比"
:min="0"
:max="100"
:controls="false"
/>
</el-form-item>
</template>
</template>
</el-table-column>
</template>
<template v-else>
<el-table-column prop="headerKey" key="headerKey">
<template slot="header">
<span class="required-asterisk">参数名</span>
</template>
<template slot-scope="{row, $index}">
<template v-if="!editable">{{ row.headerKey }}</template>
<template v-else>
<el-form-item
:prop="`tableData[${$index}].headerKey`"
:rules="[
{ required: true, message: '参数名不能为空', trigger: 'blur' },
{ pattern: /^[a-zA-Z0-9\_]+$/, message: '参数名只能是字母数字和下划线组合', trigger: 'blur' }
]"
>
<el-input v-model="tableData[$index].headerKey" clearable placeholder="请输入参数名"/>
</el-form-item>
</template>
</template>
</el-table-column>
<el-table-column prop="matchType" label="匹配方式" key="matchType">
<template slot="header">
<span class="required-asterisk">匹配方式</span>
</template>
<template slot-scope="{row, $index}">
<template v-if="!editable">{{ {'EQ': '完全匹配', 'IN': '模式匹配'}[row.matchType] }}</template>
<template v-else>
<el-form-item
:prop="`tableData[${$index}].matchType`"
:rules="{
required: true, message: '匹配方式不能为空', trigger: 'change'
}"
>
<el-select v-model="value[$index].matchType" @change="$refs.form.validateField(`tableData[${$index}].headerValues`)">
<el-option label="完全匹配" value="EQ" />
<el-option label="模式匹配" value="IN" />
</el-select>
</el-form-item>
</template>
</template>
</el-table-column>
<el-table-column prop="headerValues" label="参数值" key="headerValues">
<template slot="header">
<span class="required-asterisk">参数值</span>
<el-tooltip class="item" effect="dark" placement="top">
<div slot="content">完全匹配为精准匹配只能匹配一个参数值<br/>IN 模糊匹配支持输入多个值输入单个值后<br/>需使用分号分隔第二行信息</div>
<i class="el-icon-info ml10"></i>
</el-tooltip>
</template>
<template slot-scope="{row, $index}">
<template v-if="!editable">{{ row.headerValues.join(';') }}</template>
<template v-else>
<el-form-item
:prop="`tableData[${$index}].headerValues`"
:rules="{
validator: (rule, value, callback) => {
validatorHeaderValues($index, value, callback)
}, trigger: 'blur'
}"
>
<el-input
v-if="tableData[$index].headerValues"
:value="tableData[$index].headerValues.join(';')"
@input="tableData[$index].headerValues = $event.split(';')"
placeholder="请输入参数值"
clearable
/>
</el-form-item>
</template>
</template>
</el-table-column>
</template>
<el-table-column prop="serverAddress" label="服务地址" key="serverAddress">
<template slot="header">
<span class="required-asterisk">服务地址</span>
</template>
<template slot-scope="{row, $index}">
<template v-if="!editable">{{ row.serverAddress }}</template>
<template v-else>
<el-form-item
:prop="`tableData[${$index}].serverAddress`"
:rules="[
{ required: true, message: '服务地址不能为空', trigger: 'blur' },
{ pattern: /^(https?:\/\/)?((?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]|localhost|\d{1,3}(?:\.\d{1,3}){3})(?::\d+)?$/, message: '请输入正确的服务地址', trigger: 'blur' }
]"
>
<el-input
v-model="tableData[$index].serverAddress"
placeholder="请输入服务地址"
clearable
/>
</el-form-item>
</template>
</template>
</el-table-column>
<el-table-column v-if="editable" prop="address" label="操作" width="80">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDeleteRow(scope.$index)"
>删除</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
</div>
</template>
<script>
export default {
name: 'WeightTable',
props: {
editable: {
type: Boolean,
default: true
},
routeType: {
type: String,
default: 'WEIGHT_ROUTE'
},
value: {
type: Array,
default: () => {
return []
}
},
loading: {
type: Boolean,
default: false
}
},
data() {
return {
}
},
computed: {
tableData: {
get() {
return this.value
},
set(val) {
this.$emit('input', val)
}
},
formModel() {
return {
tableData: this.tableData
}
}
},
methods: {
// 校验表格数据完整性流量占比之和不为100、未填写完整、表格数据为空
validtorTable() {
return new Promise((resolve, reject) => {
if (this.tableData.length === 0) {
reject(new Error('请添加规则详情'))
}
const hasEmty = this.tableData.some(item => {
const values = this.routeType === 'WEIGHT_ROUTE' ? ['weight', 'serverAddress'] : ['headerKey', 'headerValues', 'matchType', 'serverAddress'];
return values.some(key => {
return item[key] === '' || item[key] === null || item[key] === void 0
})
})
if (hasEmty) {
reject(new Error('请填写完整'))
}
if (this.routeType === 'WEIGHT_ROUTE') {
const weightCount = this.tableData.reduce((acc, cur) => {
return acc + cur.weight;
}, 0);
if (weightCount !== 100) {
reject(new Error('流量占比之和必须为100'))
}
}
resolve()
})
},
validatorHeaderValues(index, value, callback) {
if (value.length === 0) {
callback(new Error('参数值不能为空'))
}
const row = this.tableData[index];
if (row.matchType === 'EQ' && value.length > 1) {
callback(new Error('完全匹配为精准匹配,只能匹配一个参数值'))
}
callback()
},
handleAddRow() {
const weightRow = { weight: 0, serverAddress: '' };
const headerRow = { headerKey: '', headerValues: [], matchType: '' };
const newRow = this.routeType === 'WEIGHT_ROUTE' ? weightRow : headerRow;
this.tableData.unshift(newRow)
},
handleDeleteRow(index) {
this.tableData.splice(index, 1)
this.$emit('validate')
},
// 校验数据准确性,在输入时即时校验,不暴露方法
// validtorFrom() {
// return new Promise(async(resolve, reject) => {
// try {
// await this.$refs.form.validate();
// resolve()
// } catch (error) {
// reject(new Error('请填写完整'))
// }
// })
// },
validateForm(key, res) {
this.$emit('validate')
}
}
}
</script>
<style lang="scss" scoped>
// ::v-deep.el-form-item {
// }
.table-form {
::v-deep.el-form-item {
margin-bottom: 22px;
&.is-error .el-input__inner {
border-color: #ff4949;
}
.el-input__inner {
border-color: #DCDFE6;
}
}
}
::v-deep.el-input-number .el-input__inner{
text-align: left;
}
</style>