Commit 594b8ae08c35ddd3c7a1a4396d8f84f5c74ccdf4
Merge branch 'fix/tenant-config-add-config' into 'main_dev'
fix: 租户配置添加独立规则链的配置 See merge request yunteng/thingskit-front!1450
Showing
5 changed files
with
684 additions
and
27 deletions
| 1 | +<template> | |
| 2 | + <BasicForm @register="registerForm"> | |
| 3 | + <template #nameSlot="{ model }"> | |
| 4 | + <Input | |
| 5 | + :disabled="model.disabled" | |
| 6 | + v-model:value="model.name" | |
| 7 | + @change="handleNameChange" | |
| 8 | + placeholder="请输入" | |
| 9 | + /> | |
| 10 | + </template> | |
| 11 | + </BasicForm> | |
| 12 | + | |
| 13 | + <CollapseContainer | |
| 14 | + title="提交设置" | |
| 15 | + style="box-shadow: 0 3px 1px -2px #0003, 0 2px 2px #00000024, 0 1px 5px #0000001f" | |
| 16 | + > | |
| 17 | + <BasicForm @register="registerSubmitStrategyForm" /> | |
| 18 | + </CollapseContainer> | |
| 19 | + | |
| 20 | + <CollapseContainer | |
| 21 | + title="重试处理设置" | |
| 22 | + class="my-2 retry" | |
| 23 | + style="box-shadow: 0 3px 1px -2px #0003, 0 2px 2px #00000024, 0 1px 5px #0000001f" | |
| 24 | + > | |
| 25 | + <BasicForm @register="registerProcessingStrategyForm" /> | |
| 26 | + </CollapseContainer> | |
| 27 | + <CollapseContainer | |
| 28 | + title="轮询设置" | |
| 29 | + style="box-shadow: 0 3px 1px -2px #0003, 0 2px 2px #00000024, 0 1px 5px #0000001f" | |
| 30 | + > | |
| 31 | + <BasicForm @register="registerPollingSettingsForm" /> | |
| 32 | + </CollapseContainer> | |
| 33 | +</template> | |
| 34 | + | |
| 35 | +<script lang="ts" setup> | |
| 36 | + import { BasicForm, useForm } from '/@/components/Form'; | |
| 37 | + import { Input } from 'ant-design-vue'; | |
| 38 | + import { | |
| 39 | + formSchema, | |
| 40 | + submitStrategySchema, | |
| 41 | + processingStrategySchema, | |
| 42 | + pollingSettingsSchema, | |
| 43 | + } from './config'; | |
| 44 | + import { CollapseContainer } from '/@/components/Container/index'; | |
| 45 | + | |
| 46 | + // const props = defineProps({ | |
| 47 | + // record: { type: Object }, | |
| 48 | + // }); | |
| 49 | + | |
| 50 | + const emit = defineEmits(['handleNameChange']); | |
| 51 | + | |
| 52 | + const [registerForm, { validate, getFieldsValue, setFieldsValue }] = useForm({ | |
| 53 | + schemas: formSchema, | |
| 54 | + showActionButtonGroup: false, | |
| 55 | + }); | |
| 56 | + | |
| 57 | + const [ | |
| 58 | + registerSubmitStrategyForm, | |
| 59 | + { | |
| 60 | + validate: validateSubmitStrategy, | |
| 61 | + getFieldsValue: getFieldsValueSubmitStrategy, | |
| 62 | + setFieldsValue: setFieldsValueSubmitStrategy, | |
| 63 | + }, | |
| 64 | + ] = useForm({ | |
| 65 | + schemas: submitStrategySchema, | |
| 66 | + showActionButtonGroup: false, | |
| 67 | + baseColProps: { span: 12 }, | |
| 68 | + wrapperCol: { span: 18 }, | |
| 69 | + }); | |
| 70 | + const [ | |
| 71 | + registerProcessingStrategyForm, | |
| 72 | + { | |
| 73 | + validate: validateProcessingStrategy, | |
| 74 | + setFieldsValue: setFieldsValueProcessingStrategy, | |
| 75 | + getFieldsValue: getFieldsValueProcessingStrategy, | |
| 76 | + }, | |
| 77 | + ] = useForm({ | |
| 78 | + schemas: processingStrategySchema, | |
| 79 | + showActionButtonGroup: false, | |
| 80 | + // baseColProps: { span: 12 }, | |
| 81 | + // wrapperCol: { span: 18 }, | |
| 82 | + }); | |
| 83 | + const [ | |
| 84 | + registerPollingSettingsForm, | |
| 85 | + { | |
| 86 | + validate: validatePollingSettings, | |
| 87 | + getFieldsValue: getFieldsValuePollingSettings, | |
| 88 | + setFieldsValue: setFieldsValuePollingSettings, | |
| 89 | + }, | |
| 90 | + ] = useForm({ | |
| 91 | + schemas: pollingSettingsSchema, | |
| 92 | + showActionButtonGroup: false, | |
| 93 | + // baseColProps: { span: 12 }, | |
| 94 | + // wrapperCol: { span: 18 }, | |
| 95 | + }); | |
| 96 | + | |
| 97 | + const validateAll = async () => { | |
| 98 | + await validate(); | |
| 99 | + await validateSubmitStrategy(); | |
| 100 | + await validateProcessingStrategy(); | |
| 101 | + await validatePollingSettings(); | |
| 102 | + }; | |
| 103 | + | |
| 104 | + const getAllFieldsValue = () => { | |
| 105 | + const { name, description, customProperties, nameOnly, topic } = getFieldsValue() || {}; | |
| 106 | + const additionalInfo = { description, customProperties }; | |
| 107 | + const processingStrategy = getFieldsValueProcessingStrategy(); | |
| 108 | + const submitStrategy = getFieldsValueSubmitStrategy(); | |
| 109 | + const values = getFieldsValuePollingSettings(); | |
| 110 | + const valuesInfo = { | |
| 111 | + name, | |
| 112 | + nameOnly, | |
| 113 | + additionalInfo, | |
| 114 | + processingStrategy, | |
| 115 | + submitStrategy, | |
| 116 | + topic, | |
| 117 | + ...values, | |
| 118 | + }; | |
| 119 | + return valuesInfo; | |
| 120 | + }; | |
| 121 | + | |
| 122 | + const setAllFieldsValue = (record: any) => { | |
| 123 | + // disabled 只是用来禁用名称输入 Main HighPriority SequentialByOriginator 默认是禁用 编辑的时候全部也是禁用 | |
| 124 | + const { name, additionalInfo, processingStrategy, disabled, submitStrategy, topic, ...values } = | |
| 125 | + record || {}; | |
| 126 | + setFieldsValue({ name, ...additionalInfo, disabled, topic }); | |
| 127 | + setFieldsValueSubmitStrategy(submitStrategy); | |
| 128 | + setFieldsValueProcessingStrategy(processingStrategy); | |
| 129 | + setFieldsValuePollingSettings({ ...values }); | |
| 130 | + }; | |
| 131 | + | |
| 132 | + const handleNameChange = ({ target }) => { | |
| 133 | + emit('handleNameChange', target?.value); | |
| 134 | + }; | |
| 135 | + | |
| 136 | + defineExpose({ getAllFieldsValue, setAllFieldsValue, setFieldsValue, validateAll }); | |
| 137 | +</script> | |
| 138 | + | |
| 139 | +<style lang="less" scoped> | |
| 140 | + :deep(.ant-input-number) { | |
| 141 | + width: 95% !important; | |
| 142 | + } | |
| 143 | + | |
| 144 | + :deep(.ant-select) { | |
| 145 | + width: 95% !important; | |
| 146 | + } | |
| 147 | + | |
| 148 | + .retry { | |
| 149 | + :deep(.ant-select) { | |
| 150 | + width: 97.5% !important; | |
| 151 | + } | |
| 152 | + } | |
| 153 | +</style> | ... | ... |
src/views/tenant/config/components/config.ts
0 → 100644
| 1 | +import { FormSchema } from '/@/components/Form'; | |
| 2 | + | |
| 3 | +const PolicyTypeEnum = { | |
| 4 | + SEQUENTIAL_BY_ORIGINATOR: 'SEQUENTIAL_BY_ORIGINATOR', | |
| 5 | + SEQUENTIAL_BY_TENANT: 'SEQUENTIAL_BY_TENANT', | |
| 6 | + SEQUENTIAL: 'SEQUENTIAL', | |
| 7 | + BURST: 'BURST', | |
| 8 | + BATCH: 'BATCH', | |
| 9 | +}; | |
| 10 | +const PolicyTypeLabelEnum = { | |
| 11 | + SEQUENTIAL_BY_ORIGINATOR: '按发起者顺序处理', | |
| 12 | + SEQUENTIAL_BY_TENANT: '按租户顺序处理', | |
| 13 | + SEQUENTIAL: '顺序处理', | |
| 14 | + BURST: '突发处理', | |
| 15 | + BATCH: '批量处理', | |
| 16 | +}; | |
| 17 | + | |
| 18 | +const ProcessTypeEnum = { | |
| 19 | + RETRY_FAILED_AND_TIMED_OUT: 'RETRY_FAILED_AND_TIMED_OUT', | |
| 20 | + SKIP_ALL_FAILURES: 'SKIP_ALL_FAILURES', | |
| 21 | + SKIP_ALL_FAILURES_AND_TIMED_OUT: 'SKIP_ALL_FAILURES_AND_TIMED_OUT', | |
| 22 | + RETRY_ALL: 'RETRY_ALL', | |
| 23 | + RETRY_FAILED: 'RETRY_FAILED', | |
| 24 | + RETRY_TIMED_OUT: 'RETRY_TIMED_OUT', | |
| 25 | +}; | |
| 26 | + | |
| 27 | +const ProcessTypeLabelEnum = { | |
| 28 | + RETRY_FAILED_AND_TIMED_OUT: '失败与超时重试', | |
| 29 | + SKIP_ALL_FAILURES: '跳过所有失败', | |
| 30 | + SKIP_ALL_FAILURES_AND_TIMED_OUT: '跳过所有失败和超时', | |
| 31 | + RETRY_ALL: '全部重试', | |
| 32 | + RETRY_FAILED: '失败重试', | |
| 33 | + RETRY_TIMED_OUT: '超时重试', | |
| 34 | +}; | |
| 35 | + | |
| 36 | +export const formSchema: FormSchema[] = [ | |
| 37 | + { | |
| 38 | + field: 'name', | |
| 39 | + label: '名称', | |
| 40 | + component: 'Input', | |
| 41 | + required: true, | |
| 42 | + rules: [ | |
| 43 | + { | |
| 44 | + pattern: /^[A-Za-z0-9._-]*$/, | |
| 45 | + message: "不能包含ASCII字母数字以外的字符, '.', '_' 和 '-'等", | |
| 46 | + }, | |
| 47 | + { | |
| 48 | + required: true, | |
| 49 | + }, | |
| 50 | + ], | |
| 51 | + slot: 'nameSlot', | |
| 52 | + }, | |
| 53 | + { | |
| 54 | + field: 'disabled', | |
| 55 | + label: '', | |
| 56 | + component: 'Checkbox', | |
| 57 | + ifShow: false, | |
| 58 | + }, | |
| 59 | + { | |
| 60 | + // 用于判断名称是否是唯一的 | |
| 61 | + field: 'nameOnly', | |
| 62 | + label: '', | |
| 63 | + defaultValue: true, | |
| 64 | + component: 'Checkbox', | |
| 65 | + ifShow: false, | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + field: 'topic', | |
| 69 | + label: '', | |
| 70 | + component: 'Input', | |
| 71 | + ifShow: false, | |
| 72 | + }, | |
| 73 | + { | |
| 74 | + field: 'customProperties', | |
| 75 | + label: '自定义属性', | |
| 76 | + component: 'Input', | |
| 77 | + helpMessage: [ | |
| 78 | + '自定义队列(主题)创建属性,例如:retention.ms:604800000;retention.bytes:1048576000', | |
| 79 | + ], | |
| 80 | + }, | |
| 81 | + { | |
| 82 | + field: 'description', | |
| 83 | + label: '说明', | |
| 84 | + component: 'InputTextArea', | |
| 85 | + helpMessage: ['此文本将显示在队列说明中,而不是所选策略中'], | |
| 86 | + }, | |
| 87 | +]; | |
| 88 | + | |
| 89 | +export const submitStrategySchema: FormSchema[] = [ | |
| 90 | + { | |
| 91 | + field: 'type', | |
| 92 | + label: '策略类型', | |
| 93 | + component: 'Select', | |
| 94 | + helpMessage: [ | |
| 95 | + '按发起者顺序处理:在确认设备A的前一条消息之前,不会提交设备A的新消息', | |
| 96 | + '按租户顺序处理:在确认租户A的前一条消息之前,不会提交租户A的新消息', | |
| 97 | + '顺序处理:在确认前一条消息之前,不会提交新消息', | |
| 98 | + '突发处理:所有消息都按到达顺序提交到规则链', | |
| 99 | + '批量处理:在确认前一批消息之前,不会提交新批', | |
| 100 | + ], | |
| 101 | + defaultValue: PolicyTypeEnum.BURST, | |
| 102 | + componentProps: { | |
| 103 | + options: Object.keys(PolicyTypeLabelEnum).map((item) => ({ | |
| 104 | + label: PolicyTypeLabelEnum[item], | |
| 105 | + value: PolicyTypeEnum[item], | |
| 106 | + })), | |
| 107 | + }, | |
| 108 | + }, | |
| 109 | + { | |
| 110 | + field: 'batchSize', | |
| 111 | + label: '批量处理大小', | |
| 112 | + required: true, | |
| 113 | + component: 'InputNumber', | |
| 114 | + ifShow: ({ model }) => model.type === PolicyTypeEnum.BATCH, | |
| 115 | + }, | |
| 116 | +]; | |
| 117 | + | |
| 118 | +export const processingStrategySchema: FormSchema[] = [ | |
| 119 | + { | |
| 120 | + field: 'type', | |
| 121 | + label: '处理类型', | |
| 122 | + component: 'Select', | |
| 123 | + colProps: { span: 24 }, | |
| 124 | + required: true, | |
| 125 | + componentProps: { | |
| 126 | + options: Object.keys(ProcessTypeLabelEnum).map((item) => ({ | |
| 127 | + label: ProcessTypeLabelEnum[item], | |
| 128 | + value: ProcessTypeEnum[item], | |
| 129 | + })), | |
| 130 | + }, | |
| 131 | + helpMessage: [ | |
| 132 | + '失败与超时重试:重试处理包重所有失败和超时的消息', | |
| 133 | + '跳过所有失败:忽略所有失败', | |
| 134 | + '跳过所有失败和超时:忽略所有失败和超时', | |
| 135 | + '全部重试:重试处理包中的所有消息', | |
| 136 | + '失败重试:重试处理包重的所有失败消息', | |
| 137 | + '超时重试:重试处理包中的所有超时消息', | |
| 138 | + ], | |
| 139 | + defaultValue: ProcessTypeEnum.SKIP_ALL_FAILURES, | |
| 140 | + }, | |
| 141 | + { | |
| 142 | + field: 'retries', | |
| 143 | + label: '重试次数(0-无限制)', | |
| 144 | + required: true, | |
| 145 | + component: 'InputNumber', | |
| 146 | + colProps: { span: 12 }, | |
| 147 | + }, | |
| 148 | + | |
| 149 | + { | |
| 150 | + field: 'failurePercentage', | |
| 151 | + label: '跳过重试的失败消息百分比', | |
| 152 | + required: true, | |
| 153 | + component: 'InputNumber', | |
| 154 | + colProps: { span: 12 }, | |
| 155 | + }, | |
| 156 | + { | |
| 157 | + field: 'pauseBetweenRetries', | |
| 158 | + label: '重试间隔(秒)', | |
| 159 | + required: true, | |
| 160 | + component: 'InputNumber', | |
| 161 | + colProps: { span: 12 }, | |
| 162 | + }, | |
| 163 | + { | |
| 164 | + field: 'maxPauseBetweenRetries', | |
| 165 | + label: '最大重试间隔(秒)', | |
| 166 | + required: true, | |
| 167 | + component: 'InputNumber', | |
| 168 | + colProps: { span: 12 }, | |
| 169 | + }, | |
| 170 | +]; | |
| 171 | + | |
| 172 | +export const pollingSettingsSchema: FormSchema[] = [ | |
| 173 | + { | |
| 174 | + field: 'pollInterval', | |
| 175 | + label: '轮询间隔', | |
| 176 | + required: true, | |
| 177 | + colProps: { span: 12 }, | |
| 178 | + component: 'InputNumber', | |
| 179 | + }, | |
| 180 | + { | |
| 181 | + field: 'partitions', | |
| 182 | + label: '分区', | |
| 183 | + required: true, | |
| 184 | + colProps: { span: 12 }, | |
| 185 | + component: 'InputNumber', | |
| 186 | + }, | |
| 187 | + { | |
| 188 | + field: 'consumerPerPartition', | |
| 189 | + label: '每个分区消费者单独轮询消息', | |
| 190 | + required: true, | |
| 191 | + colProps: { span: 12 }, | |
| 192 | + component: 'Checkbox', | |
| 193 | + }, | |
| 194 | + { | |
| 195 | + field: 'packProcessingTimeout', | |
| 196 | + label: '处理超时(毫秒)', | |
| 197 | + required: true, | |
| 198 | + colProps: { span: 12 }, | |
| 199 | + component: 'InputNumber', | |
| 200 | + }, | |
| 201 | +]; | ... | ... |
| ... | ... | @@ -55,29 +55,42 @@ export const formSchema: FormSchema[] = [ |
| 55 | 55 | placeholder: '请输入名称', |
| 56 | 56 | }, |
| 57 | 57 | }, |
| 58 | + // { | |
| 59 | + // field: 'isolatedTbRuleEngine', | |
| 60 | + // label: '', | |
| 61 | + // component: 'Checkbox', | |
| 62 | + // ifShow: false, | |
| 63 | + // renderComponentContent: () => { | |
| 64 | + // return h('span', {}, [ | |
| 65 | + // h('span', {}, '隔离板芯容器中的加工'), | |
| 66 | + // h('span', { style: { color: 'grey' } }, '(每个独立租户需要单独的微服务)'), | |
| 67 | + // ]); | |
| 68 | + // }, | |
| 69 | + // }, | |
| 70 | + // { | |
| 71 | + // field: 'isolatedTbCore', | |
| 72 | + // label: '', | |
| 73 | + // component: 'Checkbox', | |
| 74 | + // ifShow: false, | |
| 75 | + // renderComponentContent: () => { | |
| 76 | + // return h('span', {}, [ | |
| 77 | + // h('span', {}, '在独立的规则引擎中处理'), | |
| 78 | + // h('span', { style: { color: 'grey' } }, '(每个独立租户需要单独的微服务)'), | |
| 79 | + // ]); | |
| 80 | + // }, | |
| 81 | + // }, | |
| 58 | 82 | { |
| 59 | 83 | field: 'isolatedTbRuleEngine', |
| 60 | 84 | label: '', |
| 61 | 85 | component: 'Checkbox', |
| 62 | - ifShow: false, | |
| 86 | + // ifShow: false, | |
| 63 | 87 | renderComponentContent: () => { |
| 64 | 88 | return h('span', {}, [ |
| 65 | - h('span', {}, '隔离板芯容器中的加工'), | |
| 66 | - h('span', { style: { color: 'grey' } }, '(每个独立租户需要单独的微服务)'), | |
| 67 | - ]); | |
| 68 | - }, | |
| 69 | - }, | |
| 70 | - { | |
| 71 | - field: 'isolatedTbCore', | |
| 72 | - label: '', | |
| 73 | - component: 'Checkbox', | |
| 74 | - ifShow: false, | |
| 75 | - renderComponentContent: () => { | |
| 76 | - return h('span', {}, [ | |
| 77 | - h('span', {}, '在独立的规则引擎中处理'), | |
| 78 | - h('span', { style: { color: 'grey' } }, '(每个独立租户需要单独的微服务)'), | |
| 89 | + h('span', {}, '使用独立的规则引擎服务'), | |
| 90 | + h('span', { style: { color: 'grey' } }, '每个独立租户需要单独的规则引擎微服务'), | |
| 79 | 91 | ]); |
| 80 | 92 | }, |
| 93 | + slot: 'isolatedTbRuleEngine', | |
| 81 | 94 | }, |
| 82 | 95 | { |
| 83 | 96 | field: 'description', | ... | ... |
| ... | ... | @@ -19,7 +19,12 @@ |
| 19 | 19 | |
| 20 | 20 | const speedData = ref<{ value: string | number; second: string | number; uuid?: string }[]>([]); |
| 21 | 21 | const handleSuccess = (values) => { |
| 22 | - if (values.length) speedData.value = values; | |
| 22 | + if (!values?.length) { | |
| 23 | + speedData.value = []; | |
| 24 | + emit('update:value', []); | |
| 25 | + return; | |
| 26 | + } | |
| 27 | + speedData.value = values; | |
| 23 | 28 | const items = values.map((item) => `${item.value}:${item.second}`).join(','); |
| 24 | 29 | emit('update:value', items); |
| 25 | 30 | }; | ... | ... |
| ... | ... | @@ -9,8 +9,50 @@ |
| 9 | 9 | width="700px" |
| 10 | 10 | @ok="handleSubmit" |
| 11 | 11 | > |
| 12 | - <BasicForm @register="registerForm" /> | |
| 12 | + <BasicForm @register="registerForm"> | |
| 13 | + <template #isolatedTbRuleEngine="{ model }"> | |
| 14 | + <div class="flex items-center"> | |
| 15 | + <Checkbox v-model:checked="model.isolatedTbRuleEngine" @change="handleCheckbox" /> | |
| 16 | + <span>使用独立的规则引擎服务</span> | |
| 17 | + <span style="color: grey">(每个独立租户需要单独的规则引擎微服务)</span> | |
| 18 | + </div> | |
| 19 | + </template> | |
| 20 | + </BasicForm> | |
| 13 | 21 | <!-- <CpnsTenantSet ref="getChildData" :parentData="parentSetData" /> --> |
| 22 | + | |
| 23 | + <CollapseContainer | |
| 24 | + title="队列" | |
| 25 | + :defaultExpand="true" | |
| 26 | + v-if="isolatedTbRuleEngine" | |
| 27 | + class="mb-2" | |
| 28 | + > | |
| 29 | + <CollapseContainer | |
| 30 | + v-for="(item, index) in queueConfiguration" | |
| 31 | + :key="item.id" | |
| 32 | + :title="item.name" | |
| 33 | + :defaultExpand="true" | |
| 34 | + class="my-4" | |
| 35 | + style="box-shadow: 0 3px 1px -2px #0003, 0 2px 2px #00000024, 0 1px 5px #0000001f" | |
| 36 | + > | |
| 37 | + <template #action v-if="item.name !== 'Main'"> | |
| 38 | + <Tooltip title="删除"> | |
| 39 | + <Icon | |
| 40 | + class="ml-2 cursor-pointer" | |
| 41 | + icon="fluent:delete-off-20-regular" | |
| 42 | + size="20" | |
| 43 | + @click="handleDeleteTenant(index)" | |
| 44 | + /> | |
| 45 | + </Tooltip> | |
| 46 | + </template> | |
| 47 | + <TenantConfig | |
| 48 | + ref="getTenantConfig" | |
| 49 | + :record="item" | |
| 50 | + @handleNameChange="(name) => handleNameChange(index, name)" | |
| 51 | + /> | |
| 52 | + </CollapseContainer> | |
| 53 | + | |
| 54 | + <Button @click="handleCreateQueue" type="primary" class="my-3">添加队列</Button> | |
| 55 | + </CollapseContainer> | |
| 14 | 56 | <CollapseContainer title="实体 (0-无限制)" :defaultExpand="false"> |
| 15 | 57 | <Entity ref="getEntity" /> |
| 16 | 58 | </CollapseContainer> |
| ... | ... | @@ -36,7 +78,15 @@ |
| 36 | 78 | </div> |
| 37 | 79 | </template> |
| 38 | 80 | <script lang="ts"> |
| 39 | - import { defineComponent, ref, computed, unref, getCurrentInstance, reactive } from 'vue'; | |
| 81 | + import { | |
| 82 | + defineComponent, | |
| 83 | + ref, | |
| 84 | + computed, | |
| 85 | + unref, | |
| 86 | + getCurrentInstance, | |
| 87 | + reactive, | |
| 88 | + nextTick, | |
| 89 | + } from 'vue'; | |
| 40 | 90 | import { BasicForm, useForm } from '/@/components/Form'; |
| 41 | 91 | import { formSchema } from './config'; |
| 42 | 92 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
| ... | ... | @@ -51,6 +101,9 @@ |
| 51 | 101 | import { saveTenantProfileApi } from '/@/api/tenant/tenantApi'; |
| 52 | 102 | import { useMessage } from '/@/hooks/web/useMessage'; |
| 53 | 103 | import { CollapseContainer } from '/@/components/Container/index'; |
| 104 | + import { Checkbox, Tooltip, Button } from 'ant-design-vue'; | |
| 105 | + import TenantConfig from './components/TenantConfig.vue'; | |
| 106 | + import { buildUUID } from '/@/utils/uuid'; | |
| 54 | 107 | |
| 55 | 108 | export default defineComponent({ |
| 56 | 109 | name: 'ConfigDrawer', |
| ... | ... | @@ -66,6 +119,10 @@ |
| 66 | 119 | Ota, |
| 67 | 120 | Speed, |
| 68 | 121 | Entity, |
| 122 | + Checkbox, | |
| 123 | + Tooltip, | |
| 124 | + Button, | |
| 125 | + TenantConfig, | |
| 69 | 126 | }, |
| 70 | 127 | emits: ['success', 'register'], |
| 71 | 128 | setup(_, { emit }) { |
| ... | ... | @@ -84,15 +141,177 @@ |
| 84 | 141 | const getOta = ref(null); |
| 85 | 142 | const getWs = ref(null); |
| 86 | 143 | const getSpeed = ref(null); |
| 144 | + const getTenantConfig = ref(null); | |
| 87 | 145 | |
| 88 | 146 | const editGetId: any = ref(''); |
| 89 | 147 | const isDefault = ref(false); |
| 90 | 148 | const createTime = ref<string>(''); |
| 149 | + | |
| 150 | + // 独立规则引擎默认的三项Main不能删除其他能删除 | |
| 151 | + const defaultQueueConfiguration = () => { | |
| 152 | + return [ | |
| 153 | + { | |
| 154 | + name: 'Main', | |
| 155 | + topic: 'tb_rule_engine.main', | |
| 156 | + pollInterval: 2000, | |
| 157 | + partitions: 1, | |
| 158 | + consumerPerPartition: false, | |
| 159 | + packProcessingTimeout: 10000, | |
| 160 | + submitStrategy: { | |
| 161 | + type: 'BURST', | |
| 162 | + batchSize: 1000, | |
| 163 | + }, | |
| 164 | + processingStrategy: { | |
| 165 | + type: 'SKIP_ALL_FAILURES', | |
| 166 | + retries: 3, | |
| 167 | + failurePercentage: 0, | |
| 168 | + pauseBetweenRetries: 3, | |
| 169 | + maxPauseBetweenRetries: 3, | |
| 170 | + }, | |
| 171 | + id: buildUUID(), | |
| 172 | + disabled: true, | |
| 173 | + nameOnly: true, | |
| 174 | + additionalInfo: { | |
| 175 | + description: '', | |
| 176 | + customProperties: '', | |
| 177 | + }, | |
| 178 | + }, | |
| 179 | + { | |
| 180 | + name: 'HighPriority', | |
| 181 | + topic: 'tb_rule_engine.hp', | |
| 182 | + pollInterval: 2000, | |
| 183 | + partitions: 1, | |
| 184 | + consumerPerPartition: false, | |
| 185 | + packProcessingTimeout: 10000, | |
| 186 | + submitStrategy: { | |
| 187 | + type: 'BURST', | |
| 188 | + batchSize: 100, | |
| 189 | + }, | |
| 190 | + processingStrategy: { | |
| 191 | + type: 'RETRY_FAILED_AND_TIMED_OUT', | |
| 192 | + retries: 0, | |
| 193 | + failurePercentage: 0, | |
| 194 | + pauseBetweenRetries: 5, | |
| 195 | + maxPauseBetweenRetries: 5, | |
| 196 | + }, | |
| 197 | + id: buildUUID(), | |
| 198 | + disabled: true, | |
| 199 | + nameOnly: true, | |
| 200 | + additionalInfo: { | |
| 201 | + description: '', | |
| 202 | + customProperties: '', | |
| 203 | + }, | |
| 204 | + }, | |
| 205 | + { | |
| 206 | + name: 'SequentialByOriginator', | |
| 207 | + topic: 'tb_rule_engine.sq', | |
| 208 | + pollInterval: 2000, | |
| 209 | + partitions: 1, | |
| 210 | + consumerPerPartition: false, | |
| 211 | + packProcessingTimeout: 10000, | |
| 212 | + submitStrategy: { | |
| 213 | + type: 'SEQUENTIAL_BY_ORIGINATOR', | |
| 214 | + batchSize: 100, | |
| 215 | + }, | |
| 216 | + processingStrategy: { | |
| 217 | + type: 'RETRY_FAILED_AND_TIMED_OUT', | |
| 218 | + retries: 3, | |
| 219 | + failurePercentage: 0, | |
| 220 | + pauseBetweenRetries: 5, | |
| 221 | + maxPauseBetweenRetries: 5, | |
| 222 | + }, | |
| 223 | + id: buildUUID(), | |
| 224 | + disabled: true, | |
| 225 | + nameOnly: true, | |
| 226 | + additionalInfo: { | |
| 227 | + description: '', | |
| 228 | + customProperties: '', | |
| 229 | + }, | |
| 230 | + }, | |
| 231 | + ]; | |
| 232 | + }; | |
| 233 | + const queueConfiguration = ref<any>([]); | |
| 234 | + | |
| 91 | 235 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ |
| 92 | 236 | schemas: formSchema, |
| 93 | 237 | showActionButtonGroup: false, |
| 94 | 238 | }); |
| 95 | 239 | |
| 240 | + // 判断是否启用独立规则引擎 | |
| 241 | + const isolatedTbRuleEngine = ref<boolean>(false); | |
| 242 | + const handleCheckbox = (checkedValue) => { | |
| 243 | + const { | |
| 244 | + target: { checked }, | |
| 245 | + } = checkedValue || {}; | |
| 246 | + isolatedTbRuleEngine.value = checked; | |
| 247 | + if (checked && !unref(isUpdate)) { | |
| 248 | + queueConfiguration.value = defaultQueueConfiguration(); | |
| 249 | + nextTick(() => { | |
| 250 | + unref(queueConfiguration).forEach((item, index) => { | |
| 251 | + proxy.$refs.getTenantConfig[index]?.setAllFieldsValue(item); | |
| 252 | + }); | |
| 253 | + }); | |
| 254 | + } | |
| 255 | + }; | |
| 256 | + | |
| 257 | + // 删除队列 | |
| 258 | + const handleDeleteTenant = (index: number) => { | |
| 259 | + queueConfiguration.value.splice(index, 1); | |
| 260 | + }; | |
| 261 | + | |
| 262 | + const handleNameChange = async (index: number, name: string) => { | |
| 263 | + const isRepeat = unref(queueConfiguration).every((item) => item.name !== name); | |
| 264 | + nextTick(() => { | |
| 265 | + queueConfiguration.value[index].name = name; | |
| 266 | + }); | |
| 267 | + if (!isRepeat) { | |
| 268 | + createMessage.warning('队列名称必须唯一。'); | |
| 269 | + proxy.$refs.getTenantConfig[index]?.setFieldsValue({ | |
| 270 | + nameOnly: false, | |
| 271 | + topic: 'tb_rule_engine.' + name, | |
| 272 | + }); | |
| 273 | + return; | |
| 274 | + } | |
| 275 | + proxy.$refs.getTenantConfig[index]?.setFieldsValue({ | |
| 276 | + nameOnly: true, | |
| 277 | + topic: 'tb_rule_engine.' + name, | |
| 278 | + }); | |
| 279 | + }; | |
| 280 | + | |
| 281 | + const handleCreateQueue = () => { | |
| 282 | + const values = { | |
| 283 | + name: '', | |
| 284 | + pollInterval: 2000, | |
| 285 | + partitions: 1, | |
| 286 | + consumerPerPartition: false, | |
| 287 | + packProcessingTimeout: 10000, | |
| 288 | + submitStrategy: { | |
| 289 | + type: 'BURST', | |
| 290 | + batchSize: 1000, | |
| 291 | + }, | |
| 292 | + processingStrategy: { | |
| 293 | + type: 'SKIP_ALL_FAILURES', | |
| 294 | + retries: 3, | |
| 295 | + failurePercentage: 0, | |
| 296 | + pauseBetweenRetries: 3, | |
| 297 | + maxPauseBetweenRetries: 3, | |
| 298 | + }, | |
| 299 | + disabled: false, | |
| 300 | + id: buildUUID(), | |
| 301 | + nameOnly: true, | |
| 302 | + additionalInfo: { | |
| 303 | + description: '', | |
| 304 | + customProperties: '', | |
| 305 | + }, | |
| 306 | + }; | |
| 307 | + queueConfiguration.value.push(values); | |
| 308 | + nextTick(() => { | |
| 309 | + proxy.$refs.getTenantConfig[unref(queueConfiguration).length - 1]?.setAllFieldsValue( | |
| 310 | + values | |
| 311 | + ); | |
| 312 | + }); | |
| 313 | + }; | |
| 314 | + | |
| 96 | 315 | const funcResetFields = () => { |
| 97 | 316 | proxy.$refs.getEntity.funcResetFields(); |
| 98 | 317 | proxy.$refs.getRuleEngine.funcResetFields(); |
| ... | ... | @@ -128,6 +347,28 @@ |
| 128 | 347 | await setFieldsValue({ |
| 129 | 348 | ...data.record, |
| 130 | 349 | }); |
| 350 | + const { isolatedTbRuleEngine: dataIsolatedTbRuleEngine } = data.record || {}; | |
| 351 | + isolatedTbRuleEngine.value = dataIsolatedTbRuleEngine; | |
| 352 | + | |
| 353 | + const oldQueueConfiguration = data.record.profileData.queueConfiguration; | |
| 354 | + //独立规则引擎服务赋值 | |
| 355 | + if (dataIsolatedTbRuleEngine && oldQueueConfiguration?.length) { | |
| 356 | + queueConfiguration.value = | |
| 357 | + oldQueueConfiguration.map((item) => { | |
| 358 | + return { | |
| 359 | + ...item, | |
| 360 | + id: buildUUID(), | |
| 361 | + disabled: true, | |
| 362 | + nameOnly: true, | |
| 363 | + }; | |
| 364 | + }) || defaultQueueConfiguration(); | |
| 365 | + nextTick(() => { | |
| 366 | + unref(queueConfiguration).forEach((item, index) => { | |
| 367 | + proxy.$refs.getTenantConfig[index]?.setAllFieldsValue(item); | |
| 368 | + }); | |
| 369 | + }); | |
| 370 | + } | |
| 371 | + | |
| 131 | 372 | createTime.value = data.record.createdTime; |
| 132 | 373 | updateStatusSchema(true); |
| 133 | 374 | } |
| ... | ... | @@ -142,12 +383,12 @@ |
| 142 | 383 | disabled: status, |
| 143 | 384 | }, |
| 144 | 385 | }, |
| 145 | - { | |
| 146 | - field: 'isolatedTbCore', | |
| 147 | - componentProps: { | |
| 148 | - disabled: status, | |
| 149 | - }, | |
| 150 | - }, | |
| 386 | + // { | |
| 387 | + // field: 'isolatedTbRuleEngine', | |
| 388 | + // componentProps: { | |
| 389 | + // disabled: status, | |
| 390 | + // }, | |
| 391 | + // }, | |
| 151 | 392 | ]); |
| 152 | 393 | }; |
| 153 | 394 | |
| ... | ... | @@ -205,15 +446,52 @@ |
| 205 | 446 | try { |
| 206 | 447 | if (!unref(isUpdate)) { |
| 207 | 448 | await getAllFieldsFunc(); |
| 208 | - // return; | |
| 209 | - await saveTenantProfileApi({ ...postAllData, isolatedTbRuleEngine: null }); | |
| 449 | + const getTenantConfigRefs = proxy.$refs.getTenantConfig; | |
| 450 | + const queueConfigValues: any = []; | |
| 451 | + for (let i = 0; i < getTenantConfigRefs?.length; i++) { | |
| 452 | + await proxy.$refs.getTenantConfig[i].validateAll(); | |
| 453 | + const values = proxy.$refs.getTenantConfig[i].getAllFieldsValue(); | |
| 454 | + queueConfigValues.push({ ...values, nameOnly: undefined }); | |
| 455 | + const { nameOnly } = values || {}; | |
| 456 | + if (!nameOnly) { | |
| 457 | + createMessage.success('队列名称必须唯一。'); | |
| 458 | + return false; | |
| 459 | + } | |
| 460 | + } | |
| 461 | + const { | |
| 462 | + profileData: { configuration }, | |
| 463 | + } = postAllData || {}; | |
| 464 | + await saveTenantProfileApi({ | |
| 465 | + ...postAllData, | |
| 466 | + profileData: { configuration, queueConfiguration: queueConfigValues }, | |
| 467 | + }); | |
| 210 | 468 | createMessage.success('租户配置新增成功'); |
| 469 | + | |
| 211 | 470 | closeDrawer(); |
| 212 | 471 | emit('success'); |
| 213 | 472 | resetFields(); |
| 214 | 473 | } else { |
| 215 | 474 | await getAllFieldsFunc(true); |
| 216 | - await saveTenantProfileApi({ ...postAllData, isolatedTbRuleEngine: null }); | |
| 475 | + const getTenantConfigRefs = proxy.$refs.getTenantConfig; | |
| 476 | + // proxy.$refs.getTenantConfig[index].getAllFieldsValue(); | |
| 477 | + const queueConfigValues: any = []; | |
| 478 | + for (let i = 0; i < getTenantConfigRefs?.length; i++) { | |
| 479 | + await proxy.$refs.getTenantConfig[i].validateAll(); | |
| 480 | + const values = proxy.$refs.getTenantConfig[i].getAllFieldsValue(); | |
| 481 | + queueConfigValues.push({ ...values, nameOnly: undefined }); | |
| 482 | + const { nameOnly } = values || {}; | |
| 483 | + if (!nameOnly) { | |
| 484 | + createMessage.warning('队列名称必须唯一。'); | |
| 485 | + return false; | |
| 486 | + } | |
| 487 | + } | |
| 488 | + const { | |
| 489 | + profileData: { configuration }, | |
| 490 | + } = postAllData || {}; | |
| 491 | + await saveTenantProfileApi({ | |
| 492 | + ...postAllData, | |
| 493 | + profileData: { configuration, queueConfiguration: queueConfigValues }, | |
| 494 | + }); | |
| 217 | 495 | createMessage.success('租户配置编辑成功'); |
| 218 | 496 | closeDrawer(); |
| 219 | 497 | emit('success'); |
| ... | ... | @@ -239,6 +517,13 @@ |
| 239 | 517 | getOta, |
| 240 | 518 | getWs, |
| 241 | 519 | getSpeed, |
| 520 | + handleCheckbox, | |
| 521 | + isolatedTbRuleEngine, | |
| 522 | + handleDeleteTenant, | |
| 523 | + queueConfiguration, | |
| 524 | + getTenantConfig, | |
| 525 | + handleNameChange, | |
| 526 | + handleCreateQueue, | |
| 242 | 527 | }; |
| 243 | 528 | }, |
| 244 | 529 | }); | ... | ... |