sac/sf-ui/src/views/gateway/route/editTable.vue
2025-05-21 15:29:38 +08:00

277 lines
9.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>