限流,支持客户端ID查询.

This commit is contained in:
许晓东
2023-02-04 21:28:51 +08:00
parent 56621e0b8c
commit ee6defe5d2
10 changed files with 549 additions and 137 deletions

View File

@@ -0,0 +1,169 @@
<template>
<a-modal
title="新增配置"
:visible="show"
:width="800"
:mask="false"
:destroyOnClose="true"
:footer="null"
:maskClosable="false"
@cancel="handleCancel"
>
<div>
<a-spin :spinning="loading">
<a-form
:form="form"
:label-col="{ span: 5 }"
:wrapper-col="{ span: 12 }"
@submit="handleSubmit"
>
<a-form-item label="用户">
<a-input
v-decorator="[
'user',
]"
placeholder="输入用户主体标识,比如:用户名!"
/>
</a-form-item>
<a-form-item label="客户端ID">
<a-input
v-decorator="[
'client-id',
]"
placeholder="输入用户客户端ID!"
/>
</a-form-item>
<a-form-item label="IP">
<a-input
v-decorator="[
'ip',
]"
placeholder="输入客户端IP!"
/>
</a-form-item>
<a-form-item label="生产速率">
<a-input-number
:min="1"
:max="102400000"
v-decorator="[
'producerRate',
]"
/>
<a-select default-value="MB" v-model="producerRateUnit" style="width: 100px">
<a-select-option value="MB"> MB/s</a-select-option>
<a-select-option value="KB"> KB/s</a-select-option>
<a-select-option value="Byte"> Byte/s</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="消费速率">
<a-input-number
:min="1"
:max="102400000"
v-decorator="[
'consumerRate',
]"
/>
<a-select default-value="MB" v-model="consumerRateUnit" style="width: 100px">
<a-select-option value="MB"> MB/s</a-select-option>
<a-select-option value="KB"> KB/s</a-select-option>
<a-select-option value="Byte"> Byte/s</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="吞吐量">
<a-input-number
:min="1"
:max="102400000"
v-decorator="[
'requestPercentage',
]"
/>
</a-form-item>
<a-form-item :wrapper-col="{ span: 12, offset: 5 }">
<a-button type="primary" html-type="submit"> 提交</a-button>
</a-form-item>
</a-form>
</a-spin>
</div>
</a-modal>
</template>
<script>
import request from "@/utils/request";
import {KafkaTopicApi} from "@/utils/api";
import notification from "ant-design-vue/es/notification";
export default {
name: "AddQuotaConfig",
props: {
topic: {
type: String,
default: "",
},
visible: {
type: Boolean,
default: false,
},
},
data() {
return {
show: this.visible,
data: [],
loading: false,
form: this.$form.createForm(this, {name: "coordinated"}),
producerRateUnit: "MB",
consumerRateUnit: "MB",
};
},
watch: {
visible(v) {
this.show = v;
},
},
methods: {
handleSubmit(e) {
e.preventDefault();
this.form.validateFields((err, values) => {
if (!err) {
if (values.configs) {
const config = {};
values.configs.split("\n").forEach((e) => {
const c = e.split("=");
if (c.length > 1) {
let k = c[0].trim(),
v = c[1].trim();
if (k && v) {
config[k] = v;
}
}
});
values.configs = config;
}
this.loading = true;
request({
url: KafkaTopicApi.creatTopic.url,
method: KafkaTopicApi.creatTopic.method,
data: values,
}).then((res) => {
this.loading = false;
if (res.code == 0) {
this.$message.success(res.msg);
this.$emit("closeAddQuotaDialog", {refresh: true});
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
}
});
},
handleCancel() {
this.data = [];
this.$emit("closeAddQuotaDialog", {refresh: false});
},
},
};
</script>
<style scoped></style>

View File

@@ -0,0 +1,175 @@
<template>
<div class="tab-content">
<a-spin :spinning="loading">
<div id="search-offset-form-advanced-search">
<a-form
class="ant-advanced-search-form"
:form="form"
@submit="handleSearch"
>
<a-row :gutter="24">
<a-col :span="16">
<a-form-item label="客户端ID">
<a-input
v-decorator="[
'id',
]"
placeholder="请输入生产者/消费者客户端ID!"
/>
</a-form-item>
</a-col>
<a-col :span="2" :style="{ textAlign: 'right' }">
<a-form-item>
<a-button type="primary" html-type="submit"> 搜索</a-button>
</a-form-item>
</a-col>
</a-row>
</a-form>
</div>
<div class="operation-row-button">
<a-button type="primary" @click="openAddQuotaDialog"
>新增配置
</a-button>
</div>
<QuotaList :columns="columns" :data="data"></QuotaList>
<AddQuotaConfig :visible="showAddQuotaDialog" @closeAddQuotaDialog="closeAddQuotaDialog"></AddQuotaConfig>
</a-spin>
</div>
</template>
<script>
import request from "@/utils/request";
import {KafkaClientQuotaApi} from "@/utils/api";
import notification from "ant-design-vue/lib/notification";
import QuotaList from "@/views/quota/QuotaList.vue";
import AddQuotaConfig from "@/views/quota/AddQuotaConfig.vue";
export default {
name: "ClientIDQuota",
components: {QuotaList, AddQuotaConfig},
props: {
topicList: {
type: Array,
},
},
data() {
return {
loading: false,
form: this.$form.createForm(this, {name: "client_id_search_offset"}),
data: [],
showAlterQuotaDialog: false,
showAddQuotaDialog: false,
columns: [
{
title: "客户端ID",
dataIndex: "client",
key: "client",
width: 300,
slots: {title: "client"},
scopedSlots: {customRender: "client"},
},
{
title: "生产速率(带宽/秒)",
dataIndex: "producerRate",
key: "producerRate",
},
{
title: "消费速率(带宽/秒)",
dataIndex: "consumerRate",
key: "consumerRate",
},
{
title: "吞吐量(请求占比*100)",
dataIndex: "requestPercentage",
key: "requestPercentage",
},
],
};
},
methods: {
handleSearch() {
this.form.validateFields((err, values) => {
if (!err) {
this.loading = true;
const params = {types: ["client-id"]};
if (values.id) {
params.names = [values.id.trim()];
}
request({
url: KafkaClientQuotaApi.getClientQuotaConfigs.url,
method: KafkaClientQuotaApi.getClientQuotaConfigs.method,
data: params,
}).then((res) => {
this.loading = false;
if (res.code == 0) {
this.data = res.data;
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
}
});
},
openAddQuotaDialog() {
this.showAddQuotaDialog = true;
},
closeAddQuotaDialog() {
this.showAddQuotaDialog = false;
},
},
created() {
this.handleSearch();
},
};
</script>
<style scoped>
.tab-content {
width: 100%;
height: 100%;
}
.ant-advanced-search-form {
padding: 24px;
background: #fbfbfb;
border: 1px solid #d9d9d9;
border-radius: 6px;
}
.ant-advanced-search-form .ant-form-item {
display: flex;
}
.ant-advanced-search-form input {
width: 400px;
}
.ant-advanced-search-form .ant-form-item-control-wrapper {
flex: 1;
}
#components-form-topic-advanced-search .ant-form {
max-width: none;
margin-bottom: 1%;
}
#search-offset-form-advanced-search .search-result-list {
margin-top: 16px;
border: 1px dashed #e9e9e9;
border-radius: 6px;
background-color: #fafafa;
min-height: 200px;
text-align: center;
padding-top: 80px;
}
.operation-row-button {
height: 4%;
text-align: left;
margin-bottom: 5px;
margin-top: 5px;
}
</style>

View File

@@ -3,6 +3,7 @@
<a-spin :spinning="loading">
<a-tabs default-active-key="1" size="large" tabPosition="top">
<a-tab-pane key="1" tab="客户端ID">
<ClientIDQuota></ClientIDQuota>
</a-tab-pane>
<a-tab-pane key="2" tab="用户">
</a-tab-pane>
@@ -18,39 +19,16 @@
</template>
<script>
import request from "@/utils/request";
import {KafkaTopicApi} from "@/utils/api";
import notification from "ant-design-vue/lib/notification";
import ClientIDQuota from "@/views/quota/ClientIDQuota.vue";
export default {
name: "ClientQuota",
components: {},
components: {ClientIDQuota},
data() {
return {
loading: false,
topicList: [],
};
},
methods: {
getTopicNameList() {
request({
url: KafkaTopicApi.getTopicNameList.url,
method: KafkaTopicApi.getTopicNameList.method,
}).then((res) => {
if (res.code == 0) {
this.topicList = res.data;
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
},
},
created() {
this.getTopicNameList();
},
};
</script>

View File

@@ -0,0 +1,56 @@
<template>
<div>
<a-table
:columns="columns"
:data-source="data"
bordered
:row-key="
(record, index) => {
return index;
}
"
@change="handleChange"
>
<div slot="client" slot-scope="text">
<span v-if="text" >{{text}}</span><span v-else style="color: red">默认配置</span>
</div>
</a-table>
</div>
</template>
<script>
export default {
name: "QuotaList",
components: {},
props: {
columns: {
type: Array,
},
data: {
type: Array,
},
},
data() {
return {
showDetailDialog: false,
record: {},
sortedInfo: null,
};
},
methods: {
openDetailDialog(record) {
this.record = record;
this.showDetailDialog = true;
},
closeDetailDialog() {
this.showDetailDialog = false;
},
handleChange() {
this.sortedInfo = arguments[2];
},
},
};
</script>
<style scoped></style>