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,29 +55,42 @@ export const formSchema: FormSchema[] = [ | ||
55 | placeholder: '请输入名称', | 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 | field: 'isolatedTbRuleEngine', | 83 | field: 'isolatedTbRuleEngine', |
60 | label: '', | 84 | label: '', |
61 | component: 'Checkbox', | 85 | component: 'Checkbox', |
62 | - ifShow: false, | 86 | + // ifShow: false, |
63 | renderComponentContent: () => { | 87 | renderComponentContent: () => { |
64 | return h('span', {}, [ | 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 | field: 'description', | 96 | field: 'description', |
@@ -19,7 +19,12 @@ | @@ -19,7 +19,12 @@ | ||
19 | 19 | ||
20 | const speedData = ref<{ value: string | number; second: string | number; uuid?: string }[]>([]); | 20 | const speedData = ref<{ value: string | number; second: string | number; uuid?: string }[]>([]); |
21 | const handleSuccess = (values) => { | 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 | const items = values.map((item) => `${item.value}:${item.second}`).join(','); | 28 | const items = values.map((item) => `${item.value}:${item.second}`).join(','); |
24 | emit('update:value', items); | 29 | emit('update:value', items); |
25 | }; | 30 | }; |
@@ -9,8 +9,50 @@ | @@ -9,8 +9,50 @@ | ||
9 | width="700px" | 9 | width="700px" |
10 | @ok="handleSubmit" | 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 | <!-- <CpnsTenantSet ref="getChildData" :parentData="parentSetData" /> --> | 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 | <CollapseContainer title="实体 (0-无限制)" :defaultExpand="false"> | 56 | <CollapseContainer title="实体 (0-无限制)" :defaultExpand="false"> |
15 | <Entity ref="getEntity" /> | 57 | <Entity ref="getEntity" /> |
16 | </CollapseContainer> | 58 | </CollapseContainer> |
@@ -36,7 +78,15 @@ | @@ -36,7 +78,15 @@ | ||
36 | </div> | 78 | </div> |
37 | </template> | 79 | </template> |
38 | <script lang="ts"> | 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 | import { BasicForm, useForm } from '/@/components/Form'; | 90 | import { BasicForm, useForm } from '/@/components/Form'; |
41 | import { formSchema } from './config'; | 91 | import { formSchema } from './config'; |
42 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | 92 | import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; |
@@ -51,6 +101,9 @@ | @@ -51,6 +101,9 @@ | ||
51 | import { saveTenantProfileApi } from '/@/api/tenant/tenantApi'; | 101 | import { saveTenantProfileApi } from '/@/api/tenant/tenantApi'; |
52 | import { useMessage } from '/@/hooks/web/useMessage'; | 102 | import { useMessage } from '/@/hooks/web/useMessage'; |
53 | import { CollapseContainer } from '/@/components/Container/index'; | 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 | export default defineComponent({ | 108 | export default defineComponent({ |
56 | name: 'ConfigDrawer', | 109 | name: 'ConfigDrawer', |
@@ -66,6 +119,10 @@ | @@ -66,6 +119,10 @@ | ||
66 | Ota, | 119 | Ota, |
67 | Speed, | 120 | Speed, |
68 | Entity, | 121 | Entity, |
122 | + Checkbox, | ||
123 | + Tooltip, | ||
124 | + Button, | ||
125 | + TenantConfig, | ||
69 | }, | 126 | }, |
70 | emits: ['success', 'register'], | 127 | emits: ['success', 'register'], |
71 | setup(_, { emit }) { | 128 | setup(_, { emit }) { |
@@ -84,15 +141,177 @@ | @@ -84,15 +141,177 @@ | ||
84 | const getOta = ref(null); | 141 | const getOta = ref(null); |
85 | const getWs = ref(null); | 142 | const getWs = ref(null); |
86 | const getSpeed = ref(null); | 143 | const getSpeed = ref(null); |
144 | + const getTenantConfig = ref(null); | ||
87 | 145 | ||
88 | const editGetId: any = ref(''); | 146 | const editGetId: any = ref(''); |
89 | const isDefault = ref(false); | 147 | const isDefault = ref(false); |
90 | const createTime = ref<string>(''); | 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 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ | 235 | const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({ |
92 | schemas: formSchema, | 236 | schemas: formSchema, |
93 | showActionButtonGroup: false, | 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 | const funcResetFields = () => { | 315 | const funcResetFields = () => { |
97 | proxy.$refs.getEntity.funcResetFields(); | 316 | proxy.$refs.getEntity.funcResetFields(); |
98 | proxy.$refs.getRuleEngine.funcResetFields(); | 317 | proxy.$refs.getRuleEngine.funcResetFields(); |
@@ -128,6 +347,28 @@ | @@ -128,6 +347,28 @@ | ||
128 | await setFieldsValue({ | 347 | await setFieldsValue({ |
129 | ...data.record, | 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 | createTime.value = data.record.createdTime; | 372 | createTime.value = data.record.createdTime; |
132 | updateStatusSchema(true); | 373 | updateStatusSchema(true); |
133 | } | 374 | } |
@@ -142,12 +383,12 @@ | @@ -142,12 +383,12 @@ | ||
142 | disabled: status, | 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,15 +446,52 @@ | ||
205 | try { | 446 | try { |
206 | if (!unref(isUpdate)) { | 447 | if (!unref(isUpdate)) { |
207 | await getAllFieldsFunc(); | 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 | createMessage.success('租户配置新增成功'); | 468 | createMessage.success('租户配置新增成功'); |
469 | + | ||
211 | closeDrawer(); | 470 | closeDrawer(); |
212 | emit('success'); | 471 | emit('success'); |
213 | resetFields(); | 472 | resetFields(); |
214 | } else { | 473 | } else { |
215 | await getAllFieldsFunc(true); | 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 | createMessage.success('租户配置编辑成功'); | 495 | createMessage.success('租户配置编辑成功'); |
218 | closeDrawer(); | 496 | closeDrawer(); |
219 | emit('success'); | 497 | emit('success'); |
@@ -239,6 +517,13 @@ | @@ -239,6 +517,13 @@ | ||
239 | getOta, | 517 | getOta, |
240 | getWs, | 518 | getWs, |
241 | getSpeed, | 519 | getSpeed, |
520 | + handleCheckbox, | ||
521 | + isolatedTbRuleEngine, | ||
522 | + handleDeleteTenant, | ||
523 | + queueConfiguration, | ||
524 | + getTenantConfig, | ||
525 | + handleNameChange, | ||
526 | + handleCreateQueue, | ||
242 | }; | 527 | }; |
243 | }, | 528 | }, |
244 | }); | 529 | }); |