Commit 219ef54bbbef0bf547c6d3eb6d154337ac92de81

Authored by xp.Huang
2 parents 8f97aab1 89ea2adf

Merge branch 'ft' into 'main_dev'

refactor: 重构数据流转

See merge request yunteng/thingskit-front!641
Showing 30 changed files with 2046 additions and 2758 deletions

Too many changes to show.

To preserve performance only 30 of 36 files are displayed.

1 -<template>  
2 - <div>  
3 - <BasicModal  
4 - :showOkBtn="false"  
5 - :showCancelBtn="false"  
6 - v-bind="$attrs"  
7 - @register="registerDrawer"  
8 - :title="getTitle"  
9 - width="1000px"  
10 - @cancel="handleCancel"  
11 - destroy-on-close  
12 - >  
13 - <div class="step-form-form">  
14 - <a-steps :current="current">  
15 - <a-step title="选择流转方式" />  
16 - <a-step title="完善配置参数" />  
17 - </a-steps>  
18 - </div>  
19 - <div>  
20 - <div v-show="current === 0">  
21 - <TransferConfigMode  
22 - :save-content="handleSubmit"  
23 - ref="refTransferConfigMode"  
24 - @next="handleNext"  
25 - />  
26 - </div>  
27 - <div v-show="current === 1">  
28 - <TransferConfigParams  
29 - ref="refTransferConfigParams"  
30 - :getModeSelect="getModeSelectVal"  
31 - @prevSon="handlePrev"  
32 - />  
33 - </div>  
34 - </div>  
35 - <div style="float: right" v-if="isViewStatus">  
36 - <Button type="primary" @click="handleSubmit" v-show="current === 1" class="mr-2"  
37 - >确认</Button  
38 - >  
39 - <Button type="default" @click="handleCancel" class="mr-2">取消</Button>  
40 - </div>  
41 - </BasicModal>  
42 - </div>  
43 -</template>  
44 -<script lang="ts">  
45 - import { defineComponent, reactive, ref, unref, getCurrentInstance } from 'vue';  
46 - import { BasicModal, useModalInner } from '/@/components/Modal';  
47 - import { Steps } from 'ant-design-vue';  
48 - import TransferConfigMode from './cpns/transferConfigMode.vue';  
49 - import TransferConfigParams from './cpns/transferConfigParams.vue';  
50 - import { postAddConvertApi } from '/@/api/datamanager/dataManagerApi';  
51 - import { useMessage } from '/@/hooks/web/useMessage';  
52 - import { Button } from '/@/components/Button';  
53 - import { add } from '/@/components/Form/src/componentMap';  
54 - import TransferModal from '/@/components/Form/src/components/TransferModal.vue';  
55 - import TransferTableModal from '/@/components/Form/src/components/TransferTableModal.vue';  
56 -  
57 - add('TransferModal', TransferModal);  
58 - add('TransferTableModal', TransferTableModal);  
59 -  
60 - export default defineComponent({  
61 - name: 'ConfigDrawer',  
62 - components: {  
63 - BasicModal,  
64 - [Steps.name]: Steps,  
65 - [Steps.Step.name]: Steps.Step,  
66 - TransferConfigMode,  
67 - TransferConfigParams,  
68 - Button,  
69 - },  
70 - emits: ['success', 'register'],  
71 - setup(_, { emit }) {  
72 - const isViewStatus = ref(false);  
73 - const { createMessage } = useMessage();  
74 - const { proxy } = getCurrentInstance() as any;  
75 - let allPostForm: any = reactive({});  
76 - const getNameObj = reactive({  
77 - name: '',  
78 - });  
79 - const getTypeObj = reactive({  
80 - type: '',  
81 - remark: '',  
82 - });  
83 - const additionalInfoV = {  
84 - additionalInfo: {  
85 - description: '',  
86 - },  
87 - };  
88 - const getSonFormValue: any = ref({});  
89 - const getModeSonFormValue: any = ref({});  
90 - const refTransferConfigParams = ref(null);  
91 - const refTransferConfigMode = ref(null);  
92 - const getModeSelectVal = ref({});  
93 - const isUpdate: any = ref(true);  
94 - const getTitle = ref('');  
95 - const current = ref(0);  
96 - const editPostId = ref('');  
97 - let isEdit = ref(true);  
98 - let noEditObj: any = reactive({});  
99 - const editType = reactive({  
100 - type: '',  
101 - configuration: {},  
102 - name: '',  
103 - additionalInfo: {},  
104 - });  
105 - const editNextType = reactive({  
106 - type: '',  
107 - configuration: {},  
108 - name: '',  
109 - remark: '',  
110 - datasourceType: '',  
111 - datasourceContent: {},  
112 - });  
113 - const editTypeFunc = (d) => {  
114 - editType.type = d.type;  
115 - editType.configuration = d.configuration;  
116 - editType.name = d.name;  
117 - editType.additionalInfo = d.additionalInfo;  
118 - };  
119 -  
120 - const [registerDrawer, { setModalProps, closeModal }] = useModalInner(async (data) => {  
121 - isUpdate.value = data?.isUpdate;  
122 - current.value = 0;  
123 - setModalProps({ confirmLoading: false });  
124 - function commonViewOrEditFunc() {  
125 - editPostId.value = data.record.id;  
126 - editNextType.type = data.record.type;  
127 - editNextType.configuration = data.record;  
128 - editNextType.name = data.record.name;  
129 - editNextType.remark = data.record.remark;  
130 - editNextType.datasourceType = data.record.datasourceType;  
131 - editNextType.datasourceContent = data.record.datasourceContent;  
132 - editNextType.convertConfigId = data.record.id;  
133 -  
134 - proxy.$refs.refTransferConfigMode.setStepOneFieldsValueFunc(editNextType);  
135 - }  
136 - if (!unref(isUpdate)) {  
137 - isEdit.value = false;  
138 - } else {  
139 - isEdit.value = true;  
140 - }  
141 - if (isEdit.value) {  
142 - noEditObj = {  
143 - name: data.record?.name,  
144 - remark: data.record?.remark,  
145 - type: data.record?.type,  
146 - id: data.record.id,  
147 - configuration: data.record?.configuration,  
148 - };  
149 - }  
150 - switch (unref(isUpdate)) {  
151 - case 'view':  
152 - commonViewOrEditFunc();  
153 - isViewStatus.value = false;  
154 - getTitle.value = '查看流转配置';  
155 - break;  
156 - case true:  
157 - commonViewOrEditFunc();  
158 - isViewStatus.value = true;  
159 - getTitle.value = '编辑流转配置';  
160 - break;  
161 - case false:  
162 - proxy.$refs.refTransferConfigMode?.customResetStepOneFunc();  
163 - isViewStatus.value = true;  
164 - getTitle.value = '新增流转配置';  
165 - break;  
166 - }  
167 - });  
168 - const handleCancel = () => {  
169 - defineClearFunc();  
170 - closeModal();  
171 - };  
172 - const defineClearFunc = () => {  
173 - proxy.$refs.refTransferConfigMode?.customResetStepOneFunc();  
174 - proxy.$refs.refTransferConfigParams?.clearSonValueDataFunc();  
175 - };  
176 - const handleNext = (args) => {  
177 - current.value++;  
178 - getModeSelectVal.value = args;  
179 - if (unref(isUpdate)) {  
180 - isEdit.value = false;  
181 - try {  
182 - if (editNextType.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {  
183 - editTypeFunc(editNextType.configuration);  
184 - } else if (editNextType.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode') {  
185 - editTypeFunc(editNextType.configuration);  
186 - } else if (editNextType.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') {  
187 - editTypeFunc(editNextType.configuration);  
188 - } else if (editNextType.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode') {  
189 - editTypeFunc(editNextType.configuration);  
190 - }  
191 - proxy.$refs.refTransferConfigParams.editSonValueDataFunc(editType);  
192 - } catch (e) {  
193 - return e;  
194 - }  
195 - } else {  
196 - proxy.$refs.refTransferConfigParams.editSonValueDataFunc({});  
197 - }  
198 - };  
199 - const handlePrev = () => {  
200 - current.value--;  
201 - if (unref(isUpdate)) {  
202 - isEdit.value = true;  
203 - noEditObj = {  
204 - name: editNextType?.name,  
205 - remark: editNextType?.remark,  
206 - type: editNextType?.type,  
207 - id: editPostId?.value,  
208 - configuration: editNextType?.configuration?.configuration,  
209 - };  
210 - }  
211 - };  
212 -  
213 - const commonFunc = () => {  
214 - try {  
215 - additionalInfoV.additionalInfo.description =  
216 - getSonFormValue.value.configuration.description;  
217 - delete getSonFormValue.value.configuration.description;  
218 - delete getSonFormValue.value.configuration.type;  
219 - delete getSonFormValue.value?.configuration?.name;  
220 - } catch (e) {  
221 - return e;  
222 - }  
223 - };  
224 - const addOrEditFunc = async () => {  
225 - if (!unref(isUpdate)) {  
226 - proxy.$refs.refTransferConfigParams.clearSonValueValidateFunc();  
227 - }  
228 - getModeSonFormValue.value = await proxy.$refs.refTransferConfigMode.getSonValueFunc();  
229 - getSonFormValue.value = await proxy.$refs.refTransferConfigParams.getSonValueDataFunc();  
230 -  
231 - if (getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {  
232 - getTypeObj.type = 'org.thingsboard.rule.engine.kafka.TbKafkaNode';  
233 - } else if (  
234 - getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.mqtt.TbMqttNode'  
235 - ) {  
236 - getTypeObj.type = 'org.thingsboard.rule.engine.mqtt.TbMqttNode';  
237 - } else if (  
238 - getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'  
239 - ) {  
240 - getTypeObj.type = 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode';  
241 - } else if (  
242 - getModeSonFormValue.value?.type == 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'  
243 - ) {  
244 - getTypeObj.type = 'org.thingsboard.rule.engine.rest.TbRestApiCallNode';  
245 - }  
246 - getTypeObj.remark = getModeSonFormValue.value.remark;  
247 - getNameObj.name = getSonFormValue.value?.configuration?.name;  
248 - commonFunc();  
249 - const id: any = {  
250 - id: unref(isUpdate) ? editPostId.value : '',  
251 - };  
252 - Object.assign(  
253 - allPostForm,  
254 - getTypeObj,  
255 - getSonFormValue.value,  
256 - getNameObj,  
257 - id,  
258 - additionalInfoV.additionalInfo.description ? additionalInfoV : {},  
259 - {  
260 - datasourceType: getModeSonFormValue.value.datasourceType,  
261 - datasourceContent: getModeSonFormValue.value.datasourceContent,  
262 - }  
263 - );  
264 - if (!unref(isUpdate)) {  
265 - delete allPostForm.id;  
266 - }  
267 - };  
268 - const setConfiguration = (record: Recordable) => {  
269 - const type = Reflect.get(record, 'type');  
270 - const configuration = Reflect.get(record, 'configuration');  
271 - const clientProperties = Reflect.get(configuration, 'clientProperties');  
272 - !clientProperties && (record.configuration.clientProperties = {});  
273 -  
274 - if (  
275 - type === 'org.thingsboard.rule.engine.mqtt.TbMqttNode' ||  
276 - type === 'org.thingsboard.rule.engine.kafka.TbKafkaNode' ||  
277 - type === 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'  
278 - ) {  
279 - Reflect.deleteProperty(configuration, 'clientProperties');  
280 - }  
281 -  
282 - if (type === 'org.thingsboard.rule.engine.kafka.TbKafkaNode') {  
283 - const otherProperties = Reflect.get(configuration, 'otherProperties');  
284 - configuration.kafkaHeadersCharset = 'UTF-8';  
285 - !otherProperties && (record.configuration.otherProperties = {});  
286 - }  
287 -  
288 - if (type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode') {  
289 - configuration.exchangeNamePattern = configuration.exchangeNamePattern || '';  
290 - configuration.routingKeyPattern = configuration.routingKeyPattern || '';  
291 - }  
292 - };  
293 -  
294 - const handleSubmit = async (closeModalAfterSuccess = true) => {  
295 - try {  
296 - closeModalAfterSuccess && setModalProps({ confirmLoading: true });  
297 - if (!unref(isUpdate)) {  
298 - await addOrEditFunc();  
299 - if (allPostForm.name == undefined) {  
300 - return createMessage.error('请填写配置参数名称');  
301 - }  
302 - //验证属性新增了必填  
303 - const isApiHeaders =  
304 - allPostForm?.configuration?.headers ||  
305 - allPostForm?.configuration?.otherProperties ||  
306 - allPostForm?.configuration?.clientProperties;  
307 - if (isApiHeaders && Object.keys(isApiHeaders).includes('')) {  
308 - return createMessage.error('请填写属性');  
309 - }  
310 - if (isApiHeaders && Object.values(isApiHeaders).includes('')) {  
311 - return createMessage.error('请填写属性');  
312 - }  
313 - setConfiguration(allPostForm);  
314 - const res = await postAddConvertApi(allPostForm);  
315 - if (res) {  
316 - closeModalAfterSuccess && closeModal();  
317 - closeModalAfterSuccess && createMessage.success('数据流转新增成功');  
318 - setTimeout(() => {  
319 - emit('success');  
320 - }, 500);  
321 - closeModalAfterSuccess && defineClearFunc();  
322 - }  
323 - } else {  
324 - await addOrEditFunc();  
325 - if (!isEdit.value) {  
326 - //验证属性新增了必填  
327 - const isApiHeaders =  
328 - allPostForm?.configuration?.headers ||  
329 - allPostForm?.configuration?.otherProperties ||  
330 - allPostForm?.configuration?.clientProperties;  
331 - if (isApiHeaders && Object.keys(isApiHeaders).includes('')) {  
332 - return createMessage.error('请填写属性');  
333 - }  
334 - if (isApiHeaders && Object.values(isApiHeaders).includes('')) {  
335 - return createMessage.error('请填写属性');  
336 - }  
337 - }  
338 - Object.assign(noEditObj, getTypeObj, {  
339 - datasourceType: allPostForm.datasourceType,  
340 - datasourceContent: allPostForm.datasourceContent,  
341 - });  
342 - setConfiguration(allPostForm);  
343 - setConfiguration(noEditObj);  
344 - const res = await postAddConvertApi(isEdit.value ? noEditObj : allPostForm);  
345 - if (res) {  
346 - closeModalAfterSuccess && closeModal();  
347 - closeModalAfterSuccess && createMessage.success('数据流转编辑成功');  
348 - setTimeout(() => {  
349 - emit('success');  
350 - }, 500);  
351 - closeModalAfterSuccess && defineClearFunc();  
352 - }  
353 - }  
354 - } catch {  
355 - } finally {  
356 - setModalProps({ confirmLoading: false });  
357 - }  
358 - };  
359 - return {  
360 - handleCancel,  
361 - registerDrawer,  
362 - handleSubmit,  
363 - getTitle,  
364 - current,  
365 - handleNext,  
366 - handlePrev,  
367 - getModeSelectVal,  
368 - refTransferConfigParams,  
369 - refTransferConfigMode,  
370 - isViewStatus,  
371 - };  
372 - },  
373 - });  
374 -</script>  
  1 +<template>
  2 + <div>
  3 + <BasicForm @register="register">
  4 + <template #uploadFilesSlot="{ model }">
  5 + <UploadFile
  6 + :url="credentialsFile.caCertFileName"
  7 + @fileUrlEmit="handleFileUrlEmitH"
  8 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  9 + />
  10 + <div class="h-4"></div>
  11 + <UploadFile
  12 + :url="credentialsFile.certFileName"
  13 + @fileUrlEmit="handleFileUrlEmitC"
  14 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  15 + />
  16 + <div class="h-4"></div>
  17 + <UploadFile
  18 + :url="credentialsFile.privateKeyFileName"
  19 + @fileUrlEmit="handleFileUrlEmitB"
  20 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  21 + /> </template
  22 + ></BasicForm>
  23 + </div>
  24 +</template>
  25 +<script lang="ts" setup name="DataFlowMethodIsApi">
  26 + import { reactive } from 'vue';
  27 + import { BasicForm, useForm } from '/@/components/Form';
  28 + import { modeApiForm } from './config';
  29 + import { modelFormPublicConfig } from '../../../dataflowmodal/config';
  30 + import { UploadFile } from '../../../uploadfile';
  31 + import { CredentialsEnum } from '../mqtt/enum';
  32 +
  33 + const credentialsFile = reactive({
  34 + caCertFileName: '',
  35 + certFileName: '',
  36 + privateKeyFileName: '',
  37 + });
  38 +
  39 + const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
  40 + schemas: modeApiForm,
  41 + ...modelFormPublicConfig,
  42 + });
  43 +
  44 + const handleFileUrlEmitH = (fileUrl) => (credentialsFile.caCertFileName = fileUrl);
  45 +
  46 + const handleFileUrlEmitC = (fileUrl) => (credentialsFile.certFileName = fileUrl);
  47 +
  48 + const handleFileUrlEmitB = (fileUrl) => (credentialsFile.privateKeyFileName = fileUrl);
  49 +
  50 + const getValue = async () => {
  51 + const values = await validateFields();
  52 + if (!values) return;
  53 + const credentials = {
  54 + type: values['type'],
  55 + ...credentialsFile,
  56 + };
  57 + const mergeValues = {
  58 + ...values,
  59 + ...{ credentials },
  60 + };
  61 + return mergeValues;
  62 + };
  63 +
  64 + const setValue = (value) => {
  65 + const { credentials } = value;
  66 + if (credentials) {
  67 + for (let i in credentials) Reflect.set(credentialsFile, i, credentials[i]);
  68 + }
  69 + setFieldsValue(value);
  70 + };
  71 +
  72 + const resetValue = () => resetFields();
  73 + defineExpose({
  74 + getValue,
  75 + setValue,
  76 + resetValue,
  77 + });
  78 +</script>
  79 +
  80 +<style lang="less" scoped></style>
  1 +import { FormSchema } from '/@/components/Form';
  2 +import { isBasic, isPem } from '../../mqtt/enum';
  3 +
  4 +/**
  5 + * RestApi表单相关默认值配置
  6 + */
  7 +class ApiFormPartialConfig {
  8 + static restEndpointUrlPattern = 'http://localhost/api'; //端点URL模式
  9 + static requestMethod = 'POST'; //请求方式
  10 + static proxyHost = true; //代理主机
  11 + static proxyPort = 0; //代理端口
  12 + static maxParallelRequestsCount = 0; //最大并行请求数
  13 + static readTimeoutMs = 0; //读取超时(毫秒)
  14 + static maxQueueSize = 0; //Redis队列最大数
  15 + static type = 'anonymous'; //凭据类型
  16 +
  17 + //requestMethod Select options配置
  18 + static getRequestMethod() {
  19 + return [
  20 + { label: 'GET', value: 'GET' },
  21 + { label: 'POST', value: 'POST' },
  22 + { label: 'PUT', value: 'PUT' },
  23 + { label: 'DELETE', value: 'DELETE' },
  24 + ];
  25 + }
  26 +
  27 + //凭据类型Select options配置
  28 + static getType() {
  29 + return [
  30 + { label: 'Anonymous', value: 'anonymous' },
  31 + { label: 'Basic', value: 'basic' },
  32 + { label: 'PEM', value: 'pem' },
  33 + ];
  34 + }
  35 +}
  36 +
  37 +export const modeApiForm: FormSchema[] = [
  38 + {
  39 + field: 'name',
  40 + label: '名称',
  41 + colProps: { span: 12 },
  42 + required: true,
  43 + component: 'Input',
  44 + componentProps: {
  45 + maxLength: 255,
  46 + placeholder: '请输入名称',
  47 + },
  48 + },
  49 + {
  50 + field: 'restEndpointUrlPattern',
  51 + label: '端点URL模式',
  52 + colProps: { span: 12 },
  53 + required: true,
  54 + defaultValue: ApiFormPartialConfig.restEndpointUrlPattern,
  55 + component: 'Input',
  56 + componentProps: {
  57 + maxLength: 255,
  58 + placeholder: '请输入Endpoint URL pattern',
  59 + },
  60 + },
  61 + {
  62 + field: 'requestMethod',
  63 + component: 'Select',
  64 + label: '请求方式',
  65 + colProps: { span: 12 },
  66 + defaultValue: ApiFormPartialConfig.requestMethod,
  67 + componentProps: {
  68 + placeholder: '请选择Request method',
  69 + options: ApiFormPartialConfig.getRequestMethod(),
  70 + },
  71 + },
  72 + {
  73 + field: 'enableProxy',
  74 + label: '是否启用',
  75 + colProps: { span: 12 },
  76 + component: 'Checkbox',
  77 + renderComponentContent: '启用代理',
  78 + },
  79 +
  80 + {
  81 + field: 'proxyHost',
  82 + label: '代理主机',
  83 + colProps: { span: 12 },
  84 + required: ApiFormPartialConfig.proxyHost,
  85 + component: 'Input',
  86 + componentProps: {
  87 + maxLength: 255,
  88 + placeholder: 'http或者https开头',
  89 + },
  90 + ifShow: ({ values }) => {
  91 + return !!values.enableProxy;
  92 + },
  93 + },
  94 + {
  95 + field: 'proxyPort',
  96 + label: '代理端口',
  97 + colProps: { span: 12 },
  98 + required: true,
  99 + component: 'InputNumber',
  100 + defaultValue: ApiFormPartialConfig.proxyPort,
  101 + componentProps: {
  102 + maxLength: 255,
  103 + placeholder: 'http或者https开头',
  104 + },
  105 + ifShow: ({ values }) => {
  106 + return !!values.enableProxy;
  107 + },
  108 + },
  109 + {
  110 + field: 'proxyUser',
  111 + label: '代理用户',
  112 + colProps: { span: 12 },
  113 + required: true,
  114 + component: 'Input',
  115 + componentProps: {
  116 + maxLength: 255,
  117 + placeholder: '请输入代理用户',
  118 + },
  119 + ifShow: ({ values }) => {
  120 + return !!values.enableProxy;
  121 + },
  122 + },
  123 + {
  124 + field: 'proxyPassword',
  125 + label: '代理密码',
  126 + colProps: { span: 12 },
  127 + required: true,
  128 + component: 'InputPassword',
  129 + componentProps: {
  130 + maxLength: 255,
  131 + placeholder: '请输入代理密码',
  132 + },
  133 + ifShow: ({ values }) => {
  134 + return !!values.enableProxy;
  135 + },
  136 + },
  137 +
  138 + {
  139 + field: 'useSystemProxyProperties',
  140 + label: '是否启用',
  141 + colProps: { span: 12 },
  142 + component: 'Checkbox',
  143 + renderComponentContent: '使用系统代理属性',
  144 + },
  145 + {
  146 + field: 'maxParallelRequestsCount',
  147 + label: '最大并行请求数',
  148 + colProps: { span: 12 },
  149 + required: true,
  150 + component: 'InputNumber',
  151 + defaultValue: ApiFormPartialConfig.maxParallelRequestsCount,
  152 + componentProps: {
  153 + maxLength: 255,
  154 + },
  155 + ifShow: ({ values }) => {
  156 + return !!values.useSystemProxyProperties;
  157 + },
  158 + },
  159 + {
  160 + field: 'ignoreRequestBody',
  161 + label: '是否启用',
  162 + colProps: { span: 12 },
  163 + component: 'Checkbox',
  164 + renderComponentContent: '无请求正文',
  165 + },
  166 + {
  167 + field: 'readTimeoutMs',
  168 + label: '读取超时(毫秒)',
  169 + colProps: { span: 12 },
  170 + required: true,
  171 + component: 'InputNumber',
  172 + defaultValue: ApiFormPartialConfig.readTimeoutMs,
  173 + componentProps: {
  174 + maxLength: 255,
  175 + },
  176 + ifShow: ({ values }) => {
  177 + return !values.useSystemProxyProperties;
  178 + },
  179 + },
  180 + {
  181 + field: 'maxParallelRequestsCount',
  182 + label: '最大并行请求数',
  183 + colProps: { span: 12 },
  184 + required: true,
  185 + component: 'InputNumber',
  186 + defaultValue: ApiFormPartialConfig.maxParallelRequestsCount,
  187 + componentProps: {
  188 + maxLength: 255,
  189 + },
  190 + ifShow: ({ values }) => {
  191 + return !values.useSystemProxyProperties;
  192 + },
  193 + },
  194 + {
  195 + field: 'headers',
  196 + label: 'Headers',
  197 + colProps: { span: 24 },
  198 + defaultValue: { 'Content-Type': 'application/json' },
  199 + component: 'JAddInput',
  200 + },
  201 +
  202 + {
  203 + field: 'useRedisQueueForMsgPersistence',
  204 + label: '是否启用',
  205 + colProps: { span: 12 },
  206 + component: 'Checkbox',
  207 + renderComponentContent: '使用redis队列进行消息持久性',
  208 + },
  209 + {
  210 + field: 'trimQueue',
  211 + label: '是否启用',
  212 + colProps: { span: 12 },
  213 + component: 'Checkbox',
  214 + renderComponentContent: '修剪redis队列',
  215 + ifShow: ({ values }) => {
  216 + return !!values.useRedisQueueForMsgPersistence;
  217 + },
  218 + },
  219 + {
  220 + field: 'maxQueueSize',
  221 + label: 'Redis队列最大数',
  222 + colProps: { span: 12 },
  223 + required: true,
  224 + component: 'InputNumber',
  225 + defaultValue: ApiFormPartialConfig.maxQueueSize,
  226 + componentProps: {
  227 + maxLength: 255,
  228 + },
  229 + ifShow: ({ values }) => {
  230 + return !!values.useRedisQueueForMsgPersistence;
  231 + },
  232 + },
  233 + {
  234 + field: 'type',
  235 + component: 'Select',
  236 + label: '凭据类型',
  237 + colProps: { span: 12 },
  238 + defaultValue: ApiFormPartialConfig.type,
  239 + componentProps: {
  240 + placeholder: '请选择凭据类型',
  241 + options: ApiFormPartialConfig.getType(),
  242 + },
  243 + },
  244 + {
  245 + field: 'uploadFiles',
  246 + component: 'Input',
  247 + label: '',
  248 + slot: 'uploadFilesSlot',
  249 + colProps: { span: 24 },
  250 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  251 + },
  252 + {
  253 + field: 'username',
  254 + label: '用户名',
  255 + colProps: { span: 12 },
  256 + component: 'Input',
  257 + required: true,
  258 + componentProps: {
  259 + maxLength: 255,
  260 + placeholder: '请输入用户名',
  261 + },
  262 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  263 + },
  264 + {
  265 + field: 'password',
  266 + label: '密码',
  267 + colProps: { span: 12 },
  268 + component: 'InputPassword',
  269 + required: true,
  270 + componentProps: {
  271 + maxLength: 255,
  272 + placeholder: '请输入密码',
  273 + },
  274 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  275 + },
  276 + {
  277 + field: 'password',
  278 + label: '密码',
  279 + colProps: { span: 12 },
  280 + component: 'InputPassword',
  281 + componentProps: {
  282 + maxLength: 255,
  283 + placeholder: '请输入密码',
  284 + },
  285 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  286 + },
  287 +
  288 + {
  289 + field: 'description',
  290 + label: '说明',
  291 + colProps: { span: 24 },
  292 + component: 'InputTextArea',
  293 + componentProps: {
  294 + maxLength: 255,
  295 + rows: 4,
  296 + placeholder: '请输入说明',
  297 + },
  298 + },
  299 +];
  1 +import DataFlowMethodIsApi from './DataFlowMethodIsApi.vue';
  2 +
  3 +export { DataFlowMethodIsApi };
  1 +<template>
  2 + <div>
  3 + <BasicForm @register="register" />
  4 + </div>
  5 +</template>
  6 +<script lang="ts" setup name="DataFlowMethodIsKafka">
  7 + import { BasicForm, useForm } from '/@/components/Form';
  8 + import { modelKafkaForm } from './config';
  9 + import { modelFormPublicConfig } from '../../../dataflowmodal/config';
  10 +
  11 + const [register, { validate, setFieldsValue, resetFields }] = useForm({
  12 + schemas: modelKafkaForm,
  13 + ...modelFormPublicConfig,
  14 + });
  15 +
  16 + const getValue = async () => {
  17 + const values = await validate();
  18 + if (!values) return;
  19 + return values;
  20 + };
  21 +
  22 + const setValue = (value) => setFieldsValue(value);
  23 +
  24 + const resetValue = () => resetFields();
  25 + defineExpose({
  26 + getValue,
  27 + setValue,
  28 + resetValue,
  29 + });
  30 +</script>
  31 +
  32 +<style lang="less" scoped></style>
  1 +import { FormSchema } from '/@/components/Form';
  2 +
  3 +/**
  4 + * Kafka表单相关默认值配置
  5 + */
  6 +class KafkaFormPartialConfig {
  7 + static topicPattern = 'my-topic'; //消息主题默认值
  8 + static bootstrapServers = 'localhost:9092'; //服务器
  9 + static retries = 0; //重连次数
  10 + static batchSize = 16384; //生产者并发
  11 + static linger = 0; //缓存时间
  12 + static bufferMemory = 33554432; //最大缓存
  13 + static acks = '-1'; //响应码
  14 + static keySerializer = 'org.apache.kafka.common.serialization.StringSerializer'; //键序列化
  15 + static valueSerializer = 'org.apache.kafka.common.serialization.StringSerializer'; //值序列化
  16 + static kafkaHeadersCharset = 'UTF-8'; //字符集
  17 +
  18 + //acks Select options配置
  19 + static getAcks() {
  20 + return [
  21 + { label: 'all', value: 'all' },
  22 + { label: '-1', value: '-1' },
  23 + { label: '0', value: '0' },
  24 + { label: '1', value: '1' },
  25 + ];
  26 + }
  27 + //kafkaHeadersCharset Select options配置
  28 + static getkafkaHeadersCharset() {
  29 + return [
  30 + { label: 'US-ASCII', value: 'US' },
  31 + { label: 'ISO-8859-1', value: 'ISO-8859-1' },
  32 + { label: 'UTF-8', value: 'UTF-8' },
  33 + { label: 'UTF-16BE', value: 'UTF-16BE' },
  34 + { label: 'UTF-16LE', value: 'UTF-16LE' },
  35 + { label: 'UTF-16', value: 'UTF-16' },
  36 + ];
  37 + }
  38 +}
  39 +
  40 +export const modelKafkaForm: FormSchema[] = [
  41 + {
  42 + field: 'name',
  43 + label: '名称',
  44 + colProps: { span: 12 },
  45 + required: true,
  46 + component: 'Input',
  47 + componentProps: {
  48 + maxLength: 255,
  49 + placeholder: '请输入名称',
  50 + },
  51 + },
  52 + {
  53 + field: 'topicPattern',
  54 + label: '消息主题',
  55 + colProps: { span: 12 },
  56 + required: true,
  57 + component: 'Input',
  58 + defaultValue: KafkaFormPartialConfig.topicPattern,
  59 + componentProps: {
  60 + maxLength: 255,
  61 + placeholder: '请输入消息主题',
  62 + },
  63 + },
  64 + {
  65 + field: 'bootstrapServers',
  66 + label: '服务器',
  67 + colProps: { span: 12 },
  68 + component: 'Input',
  69 + defaultValue: KafkaFormPartialConfig.bootstrapServers,
  70 + required: true,
  71 + componentProps: {
  72 + maxLength: 255,
  73 + placeholder: 'localhost:9092',
  74 + },
  75 + },
  76 + {
  77 + field: 'retries',
  78 + label: '重连次数',
  79 + colProps: { span: 12 },
  80 + component: 'InputNumber',
  81 + defaultValue: KafkaFormPartialConfig.retries,
  82 + componentProps: {
  83 + maxLength: 255,
  84 + },
  85 + },
  86 + {
  87 + field: 'batchSize',
  88 + label: '生产者并发',
  89 + colProps: { span: 12 },
  90 + component: 'InputNumber',
  91 + defaultValue: KafkaFormPartialConfig.batchSize,
  92 + componentProps: {
  93 + maxLength: 255,
  94 + },
  95 + },
  96 + {
  97 + field: 'linger',
  98 + label: '缓存时间',
  99 + colProps: { span: 12 },
  100 + component: 'InputNumber',
  101 + defaultValue: KafkaFormPartialConfig.linger,
  102 + componentProps: {
  103 + maxLength: 255,
  104 + },
  105 + },
  106 + {
  107 + field: 'bufferMemory',
  108 + label: '最大缓存',
  109 + colProps: { span: 12 },
  110 + component: 'InputNumber',
  111 + defaultValue: KafkaFormPartialConfig.bufferMemory,
  112 + componentProps: {
  113 + maxLength: 255,
  114 + },
  115 + },
  116 + {
  117 + field: 'acks',
  118 + component: 'Select',
  119 + label: '响应码',
  120 + colProps: { span: 12 },
  121 + defaultValue: KafkaFormPartialConfig.acks,
  122 + componentProps: {
  123 + placeholder: '请选择响应码',
  124 + options: KafkaFormPartialConfig.getAcks(),
  125 + },
  126 + },
  127 + {
  128 + field: 'keySerializer',
  129 + label: '键序列化',
  130 + colProps: { span: 24 },
  131 + required: true,
  132 + component: 'Input',
  133 + defaultValue: KafkaFormPartialConfig.keySerializer,
  134 + componentProps: {
  135 + maxLength: 255,
  136 + placeholder: 'org.apache.kafka.common.serialization.StringSerializer',
  137 + },
  138 + },
  139 + {
  140 + field: 'valueSerializer',
  141 + label: '值序列化',
  142 + colProps: { span: 24 },
  143 + required: true,
  144 + component: 'Input',
  145 + defaultValue: KafkaFormPartialConfig.valueSerializer,
  146 + componentProps: {
  147 + maxLength: 255,
  148 + placeholder: 'org.apache.kafka.common.serialization.StringSerializer',
  149 + },
  150 + },
  151 + {
  152 + field: 'otherProperties',
  153 + label: '其他属性',
  154 + colProps: { span: 24 },
  155 + component: 'JAddInput',
  156 + },
  157 + {
  158 + field: 'addMetadataKeyValuesAsKafkaHeaders',
  159 + label: '是否启用',
  160 + colProps: { span: 12 },
  161 + component: 'Checkbox',
  162 + renderComponentContent: '将消息的元数据以键值对的方式添加到Kafka消息头中',
  163 + },
  164 + {
  165 + field: 'kafkaHeadersCharset',
  166 + component: 'Select',
  167 + label: '字符集',
  168 + required: true,
  169 + colProps: { span: 12 },
  170 + defaultValue: KafkaFormPartialConfig.kafkaHeadersCharset,
  171 + componentProps: {
  172 + placeholder: '请选择字符集编码',
  173 + options: KafkaFormPartialConfig.getkafkaHeadersCharset(),
  174 + },
  175 + ifShow: ({ values }) => {
  176 + return !!values.addMetadataKeyValuesAsKafkaHeaders;
  177 + },
  178 + },
  179 + {
  180 + field: 'description',
  181 + label: '说明',
  182 + colProps: { span: 24 },
  183 + component: 'InputTextArea',
  184 + componentProps: {
  185 + maxLength: 255,
  186 + rows: 4,
  187 + placeholder: '请输入说明',
  188 + },
  189 + },
  190 +];
  1 +import DataFlowMethodIsKafka from './DataFlowMethodIsKafka.vue';
  2 +
  3 +export { DataFlowMethodIsKafka };
  1 +<template>
  2 + <div>
  3 + <BasicForm @register="register">
  4 + <template #uploadFilesSlot="{ model }">
  5 + <UploadFile
  6 + :url="credentialsFile.caCertFileName"
  7 + @fileUrlEmit="handleFileUrlEmitH"
  8 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  9 + />
  10 + <div class="h-4"></div>
  11 + <UploadFile
  12 + :url="credentialsFile.certFileName"
  13 + @fileUrlEmit="handleFileUrlEmitC"
  14 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  15 + />
  16 + <div class="h-4"></div>
  17 + <UploadFile
  18 + :url="credentialsFile.privateKeyFileName"
  19 + @fileUrlEmit="handleFileUrlEmitB"
  20 + v-show="model['type'] === CredentialsEnum.IS_PEM"
  21 + />
  22 + </template>
  23 + </BasicForm>
  24 + </div>
  25 +</template>
  26 +<script lang="ts" setup name="DataFlowMethodIsMqtt">
  27 + import { reactive } from 'vue';
  28 + import { BasicForm, useForm } from '/@/components/Form';
  29 + import { modeMqttForm } from './config';
  30 + import { UploadFile } from '../../../uploadfile';
  31 + import { CredentialsEnum } from './enum';
  32 + import { modelFormPublicConfig } from '../../../dataflowmodal/config';
  33 +
  34 + const credentialsFile = reactive({
  35 + caCertFileName: '',
  36 + certFileName: '',
  37 + privateKeyFileName: '',
  38 + });
  39 +
  40 + const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
  41 + schemas: modeMqttForm,
  42 + ...modelFormPublicConfig,
  43 + });
  44 +
  45 + const handleFileUrlEmitH = (fileUrl) => (credentialsFile.caCertFileName = fileUrl);
  46 +
  47 + const handleFileUrlEmitC = (fileUrl) => (credentialsFile.certFileName = fileUrl);
  48 +
  49 + const handleFileUrlEmitB = (fileUrl) => (credentialsFile.privateKeyFileName = fileUrl);
  50 +
  51 + const getValue = async () => {
  52 + const values = await validateFields();
  53 + if (!values) return;
  54 + const credentials = {
  55 + type: values['type'],
  56 + ...credentialsFile,
  57 + };
  58 + const mergeValues = {
  59 + ...values,
  60 + ...{ credentials },
  61 + };
  62 + return mergeValues;
  63 + };
  64 +
  65 + const setValue = (value) => {
  66 + const { credentials } = value;
  67 + if (credentials) {
  68 + for (let i in credentials) Reflect.set(credentialsFile, i, credentials[i]);
  69 + }
  70 + setFieldsValue(value);
  71 + };
  72 +
  73 + const resetValue = () => resetFields();
  74 + defineExpose({
  75 + getValue,
  76 + setValue,
  77 + resetValue,
  78 + });
  79 +</script>
  80 +
  81 +<style lang="less" scoped></style>
  1 +import { FormSchema } from '/@/components/Form';
  2 +import { isBasic, isPem } from '../enum';
  3 +
  4 +/**
  5 + * Mqtt表单相关默认值配置
  6 + */
  7 +class MqttFormPartialConfig {
  8 + static topicPattern = 'my-topic'; //消息主题默认值
  9 + static port = 1883; //端口
  10 + static connectTimeoutSec = 10; //连接超时(秒)
  11 + static appendClientIdSuffix = false; //appendClientIdSuffix
  12 + static cleanSession = true; //cleanSession
  13 + static ssl = false; //ssl
  14 + static type = 'anonymous'; //凭据类型
  15 +
  16 + //anonymous Select options配置
  17 + static getType() {
  18 + return [
  19 + { label: 'Anonymous', value: 'anonymous' },
  20 + { label: 'Basic', value: 'basic' },
  21 + { label: 'PEM', value: 'pem' },
  22 + ];
  23 + }
  24 +}
  25 +
  26 +export const modeMqttForm: FormSchema[] = [
  27 + {
  28 + field: 'name',
  29 + label: '名称',
  30 + colProps: { span: 12 },
  31 + component: 'Input',
  32 + required: true,
  33 + componentProps: {
  34 + maxLength: 255,
  35 + placeholder: '请输入名称',
  36 + },
  37 + },
  38 + {
  39 + field: 'topicPattern',
  40 + label: '主题模式',
  41 + colProps: { span: 12 },
  42 + required: true,
  43 + component: 'Input',
  44 + defaultValue: MqttFormPartialConfig.topicPattern,
  45 + componentProps: {
  46 + maxLength: 255,
  47 + placeholder: '请输入Topic pattern',
  48 + },
  49 + },
  50 + {
  51 + field: 'host',
  52 + label: '主机',
  53 + colProps: { span: 12 },
  54 + component: 'Input',
  55 + componentProps: {
  56 + maxLength: 255,
  57 + placeholder: '请输入Host',
  58 + },
  59 + },
  60 + {
  61 + field: 'port',
  62 + label: '端口',
  63 + colProps: { span: 12 },
  64 + component: 'InputNumber',
  65 + defaultValue: MqttFormPartialConfig.port,
  66 + required: true,
  67 + componentProps: {
  68 + maxLength: 255,
  69 + placeholder: '请输入Port',
  70 + },
  71 + },
  72 + {
  73 + field: 'connectTimeoutSec',
  74 + label: '连接超时(秒)',
  75 + colProps: { span: 12 },
  76 + component: 'InputNumber',
  77 + defaultValue: MqttFormPartialConfig.connectTimeoutSec,
  78 + required: true,
  79 + componentProps: {
  80 + maxLength: 255,
  81 + placeholder: '请输入Connection timeout (sec)',
  82 + },
  83 + },
  84 + {
  85 + field: 'clientId',
  86 + label: '客户端ID',
  87 + colProps: { span: 12 },
  88 + component: 'Input',
  89 + componentProps: ({ formActionType }) => {
  90 + const { updateSchema } = formActionType;
  91 + return {
  92 + onChange(e) {
  93 + const updateSchemaShowAppendClientIdSuffix = (show) => {
  94 + updateSchema({
  95 + field: 'appendClientIdSuffix',
  96 + show,
  97 + });
  98 + };
  99 + if (!e.data) updateSchemaShowAppendClientIdSuffix(false);
  100 + else {
  101 + updateSchemaShowAppendClientIdSuffix(true);
  102 + }
  103 + },
  104 + maxLength: 255,
  105 + placeholder: '请输入Client ID',
  106 + };
  107 + },
  108 + },
  109 + {
  110 + field: 'appendClientIdSuffix',
  111 + label: '',
  112 + colProps: { span: 12 },
  113 + defaultValue: MqttFormPartialConfig.appendClientIdSuffix,
  114 + component: 'Checkbox',
  115 + renderComponentContent: '将服务ID作为后缀添加到客户端ID',
  116 + show: false,
  117 + },
  118 + {
  119 + field: 'cleanSession',
  120 + label: '是否启用',
  121 + colProps: { span: 12 },
  122 + defaultValue: MqttFormPartialConfig.cleanSession,
  123 + component: 'Checkbox',
  124 + renderComponentContent: '清除会话',
  125 + },
  126 + {
  127 + field: 'ssl',
  128 + label: '是否启用',
  129 + colProps: { span: 12 },
  130 + defaultValue: MqttFormPartialConfig.ssl,
  131 + component: 'Checkbox',
  132 + renderComponentContent: '启用SSL',
  133 + },
  134 + {
  135 + field: 'type',
  136 + component: 'Select',
  137 + label: '凭据类型',
  138 + colProps: { span: 12 },
  139 + defaultValue: MqttFormPartialConfig.type,
  140 + componentProps: {
  141 + placeholder: '请选择Credentials',
  142 + options: MqttFormPartialConfig.getType(),
  143 + },
  144 + },
  145 + {
  146 + field: 'uploadFiles',
  147 + component: 'Input',
  148 + label: '',
  149 + slot: 'uploadFilesSlot',
  150 + colProps: { span: 24 },
  151 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  152 + },
  153 + {
  154 + field: 'username',
  155 + label: '用户名',
  156 + colProps: { span: 12 },
  157 + component: 'Input',
  158 + required: true,
  159 + componentProps: {
  160 + maxLength: 255,
  161 + placeholder: '请输入用户名',
  162 + },
  163 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  164 + },
  165 + {
  166 + field: 'password',
  167 + label: '密码',
  168 + colProps: { span: 12 },
  169 + component: 'InputPassword',
  170 + componentProps: {
  171 + maxLength: 255,
  172 + placeholder: '请输入密码',
  173 + },
  174 + ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),
  175 + },
  176 + {
  177 + field: 'password',
  178 + label: '密码',
  179 + colProps: { span: 12 },
  180 + component: 'InputPassword',
  181 + componentProps: {
  182 + maxLength: 255,
  183 + placeholder: '请输入密码',
  184 + },
  185 + ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),
  186 + },
  187 + {
  188 + field: 'description',
  189 + label: '说明',
  190 + colProps: { span: 24 },
  191 + component: 'InputTextArea',
  192 + componentProps: {
  193 + maxLength: 255,
  194 + rows: 4,
  195 + placeholder: '请输入说明',
  196 + },
  197 + },
  198 +];
  1 +/**
  2 + * Mqtt相关枚举配置项
  3 + */
  4 +
  5 +//凭据类型枚举配置项
  6 +export enum CredentialsEnum {
  7 + IS_ANONYMOUS = 'anonymous',
  8 + IS_BASIC = 'basic',
  9 + IS_PEM = 'pem',
  10 +}
  11 +
  12 +export const isBasic = (type: string) => {
  13 + return type === CredentialsEnum.IS_BASIC;
  14 +};
  15 +
  16 +export const isPem = (type: string) => {
  17 + return type === CredentialsEnum.IS_PEM;
  18 +};
  1 +import DataFlowMethodIsMqtt from './DataFlowMethodIsMqtt.vue';
  2 +
  3 +export { DataFlowMethodIsMqtt };
  1 +<template>
  2 + <div>
  3 + <BasicForm @register="register" />
  4 + </div>
  5 +</template>
  6 +<script lang="ts" setup name="DataFlowMethodIsRabbitMq">
  7 + import { BasicForm, useForm } from '/@/components/Form';
  8 + import { modeRabbitMqForm } from './config';
  9 + import { modelFormPublicConfig } from '../../../dataflowmodal/config';
  10 +
  11 + const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
  12 + schemas: modeRabbitMqForm,
  13 + ...modelFormPublicConfig,
  14 + });
  15 +
  16 + const getValue = async () => {
  17 + const values = await validateFields();
  18 + if (!values) return;
  19 + return values;
  20 + };
  21 +
  22 + const setValue = (value) => setFieldsValue(value);
  23 +
  24 + const resetValue = () => resetFields();
  25 + defineExpose({
  26 + getValue,
  27 + setValue,
  28 + resetValue,
  29 + });
  30 +</script>
  31 +<style lang="less" scoped></style>
  1 +import { FormSchema } from '/@/components/Form';
  2 +
  3 +/**
  4 + * RabbitMq表单相关默认值配置
  5 + */
  6 +class RabbitMqFormPartialConfig {
  7 + static topicPattern = 'my-topic'; //消息主题默认值
  8 + static host = true; //主机
  9 + static port = 5672; //端口
  10 + static virtualHost = '/'; //虚拟端口(以/开头)
  11 + static username = 'guest'; //用户名
  12 + static password = 'guest'; //密码
  13 + static connectionTimeout = 60000; //连接超时(毫秒)
  14 + static handshakeTimeout = 10000; //握手超时(毫秒)
  15 +
  16 + //anonymous Select options配置
  17 + static getMessageProperties() {
  18 + return [
  19 + { label: 'BASIC', value: 'BASIC' },
  20 + { label: 'TEXT_PLAIN', value: 'TEXT_PLAIN' },
  21 + { label: 'MINIMAL_BASIC', value: 'MINIMAL_BASIC' },
  22 + { label: 'MINIMAL_PERSISTENT_BASIC', value: 'MINIMAL_PERSISTENT_BASIC' },
  23 + { label: 'PERSISTENT_BASIC', value: 'PERSISTENT_BASIC' },
  24 + { label: 'PERSISTENT_TEXT_PLAIN', value: 'PERSISTENT_TEXT_PLAIN' },
  25 + ];
  26 + }
  27 +}
  28 +
  29 +export const modeRabbitMqForm: FormSchema[] = [
  30 + {
  31 + field: 'name',
  32 + label: '名称',
  33 + colProps: { span: 12 },
  34 + required: true,
  35 + component: 'Input',
  36 + componentProps: {
  37 + maxLength: 255,
  38 + placeholder: '请输入名称',
  39 + },
  40 + },
  41 + {
  42 + field: 'exchangeNamePattern',
  43 + label: '交换名称模式',
  44 + colProps: { span: 12 },
  45 + component: 'Input',
  46 + componentProps: {
  47 + maxLength: 255,
  48 + placeholder: '请输入模式',
  49 + },
  50 + },
  51 + {
  52 + field: 'routingKeyPattern',
  53 + label: '路由密钥模式',
  54 + colProps: { span: 12 },
  55 + component: 'Input',
  56 + componentProps: {
  57 + maxLength: 255,
  58 + placeholder: '请输入模式',
  59 + },
  60 + },
  61 + {
  62 + field: 'messageProperties',
  63 + component: 'Select',
  64 + label: '消息属性',
  65 + colProps: { span: 12 },
  66 + componentProps: {
  67 + placeholder: '请选择消息属性',
  68 + options: RabbitMqFormPartialConfig.getMessageProperties(),
  69 + },
  70 + },
  71 + {
  72 + field: 'host',
  73 + label: '主机',
  74 + colProps: { span: 12 },
  75 + component: 'Input',
  76 + required: RabbitMqFormPartialConfig.host,
  77 + defaultValue: 'localhost',
  78 + componentProps: {
  79 + maxLength: 255,
  80 + placeholder: 'localhost',
  81 + },
  82 + },
  83 + {
  84 + field: 'port',
  85 + label: '端口',
  86 + colProps: { span: 12 },
  87 + component: 'InputNumber',
  88 + defaultValue: RabbitMqFormPartialConfig.port,
  89 + required: true,
  90 + componentProps: {
  91 + maxLength: 255,
  92 + placeholder: '请输入Port',
  93 + },
  94 + },
  95 + {
  96 + field: 'virtualHost',
  97 + label: '虚拟端口',
  98 + colProps: { span: 12 },
  99 + component: 'Input',
  100 + defaultValue: RabbitMqFormPartialConfig.virtualHost,
  101 + componentProps: {
  102 + maxLength: 255,
  103 + placeholder: '/',
  104 + },
  105 + },
  106 + {
  107 + field: 'username',
  108 + label: '用户名',
  109 + colProps: { span: 12 },
  110 + component: 'Input',
  111 + defaultValue: RabbitMqFormPartialConfig.username,
  112 + componentProps: {
  113 + maxLength: 255,
  114 + placeholder: '请输入用户名',
  115 + },
  116 + },
  117 + {
  118 + field: 'password',
  119 + label: '密码',
  120 + colProps: { span: 12 },
  121 + component: 'InputPassword',
  122 + defaultValue: RabbitMqFormPartialConfig.password,
  123 + componentProps: {
  124 + maxLength: 255,
  125 + placeholder: '请输入密码',
  126 + },
  127 + },
  128 + {
  129 + field: 'automaticRecoveryEnabled',
  130 + label: '是否启用',
  131 + colProps: { span: 12 },
  132 + component: 'Checkbox',
  133 + renderComponentContent: '自动恢复',
  134 + },
  135 + {
  136 + field: 'connectionTimeout',
  137 + label: '连接超时(毫秒)',
  138 + colProps: { span: 12 },
  139 + component: 'InputNumber',
  140 + defaultValue: RabbitMqFormPartialConfig.connectionTimeout,
  141 + componentProps: {
  142 + maxLength: 255,
  143 + placeholder: '请输入Connection timeout (ms)',
  144 + },
  145 + },
  146 + {
  147 + field: 'handshakeTimeout',
  148 + label: '握手超时(毫秒)',
  149 + colProps: { span: 12 },
  150 + component: 'InputNumber',
  151 + defaultValue: RabbitMqFormPartialConfig.handshakeTimeout,
  152 + componentProps: {
  153 + maxLength: 255,
  154 + placeholder: '请输入Handshake timeout (ms)',
  155 + },
  156 + },
  157 + {
  158 + field: 'clientProperties',
  159 + label: '客户端属性',
  160 + colProps: { span: 24 },
  161 + component: 'JAddInput',
  162 + },
  163 + {
  164 + field: 'description',
  165 + label: '说明',
  166 + colProps: { span: 24 },
  167 + component: 'InputTextArea',
  168 + componentProps: {
  169 + maxLength: 255,
  170 + rows: 4,
  171 + placeholder: '请输入说明',
  172 + },
  173 + },
  174 +];
  1 +import DataFlowMethodIsRabbitMq from './DataFlowMethodIsRabbitMq.vue';
  2 +
  3 +export { DataFlowMethodIsRabbitMq };
  1 +<template>
  2 + <div class="data-flow-method">
  3 + <BasicForm @register="register" />
  4 + <Button
  5 + type="primary"
  6 + class="data-flow-method-button"
  7 + @click="currentDataFlowMethodHanleNextStep"
  8 + >下一步</Button
  9 + >
  10 + </div>
  11 +</template>
  12 +
  13 +<script lang="ts" setup name="DataFlowMethod">
  14 + import { BasicForm, useForm } from '/@/components/Form';
  15 + import { modeForm, modelFormPublicConfig } from './config';
  16 + import { BasicInfoFormField } from './enum';
  17 + import { BasicInfoRecord } from './types';
  18 + import { Button } from 'ant-design-vue';
  19 +
  20 + const props = defineProps({
  21 + saveContent: {
  22 + type: Function,
  23 + },
  24 + });
  25 +
  26 + const emit = defineEmits(['currentDataFlowMethodEmitNext']);
  27 +
  28 + const [register, { validateFields, setFieldsValue, resetFields }] = useForm({
  29 + schemas: modeForm(props.saveContent),
  30 + ...modelFormPublicConfig,
  31 + });
  32 +
  33 + const getValue = async () => {
  34 + const record = (await validateFields()) || {};
  35 + const { type, remark } = record;
  36 + const datasourceType = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_TYPE);
  37 + const convertDevices = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_DEVICE);
  38 + const convertProducts = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  39 + return {
  40 + type,
  41 + remark,
  42 + datasourceType,
  43 + datasourceContent: {
  44 + convertProducts,
  45 + convertDevices,
  46 + } as unknown as BasicInfoRecord,
  47 + };
  48 + };
  49 +
  50 + const setValue = (record: Recordable) => {
  51 + const value = {
  52 + ...record,
  53 + [BasicInfoFormField.DATA_SOURCE_PRODUCT]: record?.datasourceContent?.convertProducts || [],
  54 + [BasicInfoFormField.DATA_SOURCE_DEVICE]: record?.datasourceContent?.convertDevices,
  55 + [BasicInfoFormField.CONVERT_CONFIG_ID]: record?.id,
  56 + };
  57 + setFieldsValue(value);
  58 + };
  59 +
  60 + const currentDataFlowMethodHanleNextStep = () => {
  61 + emit('currentDataFlowMethodEmitNext', getValue());
  62 + };
  63 +
  64 + const resetValue = () => resetFields();
  65 + defineExpose({
  66 + getValue,
  67 + setValue,
  68 + resetValue,
  69 + });
  70 +</script>
  71 +<style lang="less" scoped>
  72 + .data-flow-method {
  73 + margin: 0 auto;
  74 + width: 600px;
  75 +
  76 + .data-flow-method-button {
  77 + position: absolute;
  78 + bottom: 10%;
  79 + right: 50%;
  80 + transform: translateX(50%);
  81 + }
  82 + }
  83 +</style>
  1 +<template>
  2 + <div>
  3 + <BasicModal
  4 + width="1000px"
  5 + v-bind="$attrs"
  6 + @register="registerDrawer"
  7 + @ok="handleSubmit"
  8 + destroy-on-close
  9 + @cancel="resetValue"
  10 + >
  11 + <div>
  12 + <a-steps :current="currentStep">
  13 + <a-step v-for="(item, index) in stepConfig" :title="item" :key="index" />
  14 + </a-steps>
  15 + </div>
  16 + <div>
  17 + <!-- 选择流转方式 -->
  18 + <DataFlowMethod
  19 + ref="dataFlowMethodRef"
  20 + v-show="currentStep === 0"
  21 + :save-content="handleSubmit"
  22 + @currentDataFlowMethodEmitNext="handleNextDataFlowParams"
  23 + />
  24 + <!-- 完善配置参数 -->
  25 + <DataFlowParams
  26 + ref="dataFlowParamsRef"
  27 + v-show="currentStep === 1"
  28 + :dataFlowType="dataFlowType"
  29 + @currentDataFlowParamsEmitPrevStep="handlePrevDataFlowMethod"
  30 + />
  31 + </div>
  32 + </BasicModal>
  33 + </div>
  34 +</template>
  35 +<script lang="ts" setup name="DataFlowModal">
  36 + import { ref, nextTick, reactive } from 'vue';
  37 + import { BasicModal, useModalInner } from '/@/components/Modal';
  38 + import { add } from '/@/components/Form/src/componentMap';
  39 + import TransferModal from '/@/components/Form/src/components/TransferModal.vue';
  40 + import TransferTableModal from '/@/components/Form/src/components/TransferTableModal.vue';
  41 + import { DataFlowMethod, DataFlowParams } from './index';
  42 + import { stepConfig, removeFieldByModeForm } from './config';
  43 + import { postAddConvertApi } from '/@/api/datamanager/dataManagerApi';
  44 + import { useMessage } from '/@/hooks/web/useMessage';
  45 + import { useUtil } from '../../hooks/index.hook';
  46 + import { BusinessDataFlowTextEnum } from '../../enum';
  47 +
  48 + add('TransferModal', TransferModal);
  49 +
  50 + add('TransferTableModal', TransferTableModal);
  51 +
  52 + const emit = defineEmits(['success', 'register']);
  53 +
  54 + const { hasEditOrView, modalProps, getValue, validateOtherProperity } = useUtil();
  55 +
  56 + const { createMessage } = useMessage();
  57 +
  58 + const currentStep = ref(0);
  59 +
  60 + const dataFlowType = ref('');
  61 +
  62 + const dataFlowMethodRef = ref<InstanceType<typeof DataFlowMethod>>();
  63 +
  64 + const dataFlowParamsRef = ref<InstanceType<typeof DataFlowParams>>();
  65 +
  66 + const businessText = ref('');
  67 +
  68 + const restData = reactive({
  69 + data: {},
  70 + });
  71 +
  72 + const [registerDrawer, { setModalProps, closeModal }] = useModalInner(async (data) => {
  73 + await nextTick();
  74 + resetValue();
  75 + const { text, record } = data;
  76 + businessText.value = text;
  77 + restData.data = record;
  78 + setModalProps(modalProps(businessText.value));
  79 + if (!record) return;
  80 + dataFlowType.value = record?.type;
  81 + dataFlowMethodRef.value?.setValue(record);
  82 + setValue(record);
  83 + });
  84 +
  85 + const handleSubmit = async (closeModalAfterSuccess = true) => {
  86 + try {
  87 + closeModalAfterSuccess && setModalProps({ confirmLoading: true });
  88 + const getDataFlowMethod = await dataFlowMethodRef.value?.getValue();
  89 + const { name, description, ...getDataFlowParams } = await dataFlowParamsRef.value?.getValue();
  90 + removeFieldByModeForm.forEach((item) => {
  91 + Reflect.deleteProperty(getDataFlowParams, item);
  92 + });
  93 + validateOtherProperity(
  94 + getDataFlowParams?.headers,
  95 + getDataFlowParams?.otherProperties,
  96 + getDataFlowParams?.clientProperties
  97 + );
  98 + const data = getValue(description, name, getDataFlowMethod, getDataFlowParams);
  99 + const rest = await postAddConvertApi({ ...restData.data, ...data });
  100 + if (rest) {
  101 + closeModalAfterSuccess && createMessage.success(`${businessText.value}成功`);
  102 + closeModalAfterSuccess && closeModal();
  103 + closeModalAfterSuccess && resetValue();
  104 + //fix 弹窗关闭时闪动问题
  105 + setTimeout(() => {
  106 + emit('success');
  107 + }, 100);
  108 + }
  109 + } finally {
  110 + setModalProps({ confirmLoading: false });
  111 + }
  112 + };
  113 +
  114 + //设置配置参数
  115 + const setValue = (record) => {
  116 + dataFlowParamsRef.value?.setValue({
  117 + ...record,
  118 + ...record?.configuration,
  119 + name: record?.name,
  120 + description: record?.additionalInfo?.description,
  121 + });
  122 + };
  123 +
  124 + //下一步
  125 + const handleNextDataFlowParams = async (value) => {
  126 + value
  127 + .then(async (res) => {
  128 + currentStep.value = 1;
  129 + const { type } = res;
  130 + dataFlowType.value = type;
  131 + await nextTick();
  132 + if (hasEditOrView(businessText.value)) {
  133 + setValue(restData.data);
  134 + }
  135 + if (businessText.value === BusinessDataFlowTextEnum.BUSINESS_MODAL_VIEW_TEXT) {
  136 + setModalProps({ showOkBtn: false });
  137 + } else {
  138 + setModalProps({ showOkBtn: true });
  139 + }
  140 + })
  141 + .catch(() => {
  142 + return;
  143 + });
  144 + };
  145 +
  146 + //上一步
  147 + const handlePrevDataFlowMethod = (value) => {
  148 + currentStep.value = value;
  149 + setModalProps({ showOkBtn: false });
  150 + if (hasEditOrView(businessText.value)) {
  151 + setValue(restData.data);
  152 + }
  153 + };
  154 +
  155 + const resetValue = () => {
  156 + currentStep.value = 0;
  157 + dataFlowMethodRef.value?.resetValue();
  158 + dataFlowParamsRef.value?.resetValue();
  159 + };
  160 +</script>
  1 +<template>
  2 + <div class="data-flow-params">
  3 + <div>
  4 + <DataFlowMethodIsKafka
  5 + ref="dataFlowMethodIsKafkaRef"
  6 + v-show="dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_KAFKA"
  7 + />
  8 + <DataFlowMethodIsMqtt
  9 + ref="dataFlowMethodIsMqttRef"
  10 + v-show="dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_MQTT"
  11 + />
  12 + <DataFlowMethodIsRabbitMq
  13 + ref="dataFlowMethodIsRabbitMqRef"
  14 + v-show="dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_RABBITMQ"
  15 + />
  16 + <DataFlowMethodIsApi
  17 + ref="dataFlowMethodIsApiRef"
  18 + v-show="dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_REST_API"
  19 + />
  20 + </div>
  21 + <Button
  22 + type="primary"
  23 + class="data-flow-params-button"
  24 + @click="currentDataFlowParamsHanlePrevStep"
  25 + >上一步</Button
  26 + >
  27 + </div>
  28 +</template>
  29 +<script lang="ts" setup="DataFlowParams">
  30 + import { ref, nextTick } from 'vue';
  31 + import { DataFlowMethodIsApi } from '../dataflowmethod/components/api';
  32 + import { DataFlowMethodIsKafka } from '../dataflowmethod/components/kafka';
  33 + import { DataFlowMethodIsMqtt } from '../dataflowmethod/components/mqtt';
  34 + import { DataFlowMethodIsRabbitMq } from '../dataflowmethod/components/rabbitmq';
  35 + import { BusinessDataFlowMethodEnum } from '../../enum';
  36 + import { Button } from 'ant-design-vue';
  37 +
  38 + const props = defineProps({
  39 + dataFlowType: {
  40 + type: String,
  41 + default: '',
  42 + },
  43 + });
  44 +
  45 + const emit = defineEmits(['currentDataFlowParamsEmitPrevStep']);
  46 +
  47 + const dataFlowMethodIsApiRef = ref<InstanceType<typeof DataFlowMethodIsApi>>();
  48 +
  49 + const dataFlowMethodIsKafkaRef = ref<InstanceType<typeof DataFlowMethodIsKafka>>();
  50 +
  51 + const dataFlowMethodIsMqttRef = ref<InstanceType<typeof DataFlowMethodIsMqtt>>();
  52 +
  53 + const dataFlowMethodIsRabbitMqRef = ref<InstanceType<typeof DataFlowMethodIsRabbitMq>>();
  54 +
  55 + const currentDataFlowParamsHanlePrevStep = () => {
  56 + emit('currentDataFlowParamsEmitPrevStep', 0);
  57 + };
  58 +
  59 + //表单配置项(kafka、mqtt、rabbitmq、restapi)
  60 + const dataFlowTypeGetForm = [
  61 + [
  62 + (dataFlowType) => dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_KAFKA,
  63 + () => dataFlowMethodIsKafkaRef.value?.getValue(),
  64 + (value) => dataFlowMethodIsKafkaRef.value?.setValue(value),
  65 + () => dataFlowMethodIsKafkaRef.value?.resetValue(),
  66 + ],
  67 + [
  68 + (dataFlowType) => dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_MQTT,
  69 + () => dataFlowMethodIsMqttRef.value?.getValue(),
  70 + (value) => dataFlowMethodIsMqttRef.value?.setValue(value),
  71 + () => dataFlowMethodIsMqttRef.value?.resetValue(),
  72 + ],
  73 + [
  74 + (dataFlowType) => dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_RABBITMQ,
  75 + () => dataFlowMethodIsRabbitMqRef.value?.getValue(),
  76 + (value) => dataFlowMethodIsRabbitMqRef.value?.setValue(value),
  77 + () => dataFlowMethodIsRabbitMqRef.value?.resetValue(),
  78 + ],
  79 + [
  80 + (dataFlowType) => dataFlowType === BusinessDataFlowMethodEnum.DATAFLOW_METHOD_REST_API,
  81 + () => dataFlowMethodIsApiRef.value?.getValue(),
  82 + (value) => dataFlowMethodIsApiRef.value?.setValue(value),
  83 + () => dataFlowMethodIsApiRef.value?.resetValue(),
  84 + ],
  85 + ];
  86 +
  87 + const getValue = () => {
  88 + const findDateFlow = dataFlowTypeGetForm.find((item) => item[0](props.dataFlowType));
  89 + if (!findDateFlow) return;
  90 + const getForm = findDateFlow[1](0);
  91 + return getForm;
  92 + };
  93 +
  94 + const setValue = async (value) => {
  95 + await nextTick();
  96 + const findDateFlow = dataFlowTypeGetForm.find((item) => item[0](props.dataFlowType));
  97 + if (!findDateFlow) return;
  98 + findDateFlow[2](value);
  99 + };
  100 +
  101 + const resetValue = () => {
  102 + const findDateFlow = dataFlowTypeGetForm.find((item) => item[0](props.dataFlowType));
  103 + if (!findDateFlow) return;
  104 + findDateFlow[3](0);
  105 + };
  106 + defineExpose({
  107 + getValue,
  108 + setValue,
  109 + resetValue,
  110 + });
  111 +</script>
  112 +<style lang="less" scoped>
  113 + .data-flow-params {
  114 + margin: 0 auto;
  115 + width: 600px;
  116 +
  117 + .data-flow-params-button {
  118 + position: absolute;
  119 + bottom: 5%;
  120 + right: 50%;
  121 + transform: translateX(50%);
  122 + }
  123 + }
  124 +</style>
  1 +import { FormSchema } from '/@/components/Form';
  2 +import { findDictItemByCode } from '/@/api/system/dict';
  3 +import { h, unref } from 'vue';
  4 +import { getDeviceProfile } from '/@/api/alarm/position';
  5 +import { BasicColumn, BasicTableProps } from '/@/components/Table';
  6 +import { devicePage } from '/@/api/device/deviceManager';
  7 +import { Tag } from 'ant-design-vue';
  8 +import { DeviceRecord } from '/@/api/device/model/deviceModel';
  9 +import { FETCH_SETTING } from '/@/components/Table/src/const';
  10 +import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';
  11 +import { useMessage } from '/@/hooks/web/useMessage';
  12 +import {
  13 + BasicInfoFormField,
  14 + DataSourceType,
  15 + DeviceStatusEnum,
  16 + DeviceStatusNameEnum,
  17 + DeviceTypeNameEnum,
  18 +} from '../enum';
  19 +
  20 +export const stepConfig = ['选择流转方式', '完善配置参数'];
  21 +
  22 +export const removeFieldByModeForm = ['name', 'description'];
  23 +
  24 +//表单通用配置
  25 +export const modelFormPublicConfig = {
  26 + labelWidth: 120,
  27 + actionColOptions: {
  28 + span: 14,
  29 + },
  30 + showResetButton: false,
  31 + showSubmitButton: false,
  32 +};
  33 +
  34 +const handleGroupDevice = (options: DeviceRecord[]) => {
  35 + const map = new Map<string, string[]>();
  36 + options.forEach((item) => {
  37 + if (map.has(item.profileId)) {
  38 + const deviceList = map.get(item.profileId)!;
  39 + deviceList.push(item.tbDeviceId);
  40 + } else {
  41 + map.set(item.profileId, [item.tbDeviceId]);
  42 + }
  43 + });
  44 + const value = Array.from(map.entries()).map(([product, devices]) => ({ product, devices }));
  45 +
  46 + return value;
  47 +};
  48 +
  49 +const deviceTableFormSchema: FormSchema[] = [
  50 + {
  51 + field: 'name',
  52 + label: '设备名称',
  53 + component: 'Input',
  54 + colProps: { span: 9 },
  55 + componentProps: {
  56 + placeholder: '请输入设备名称',
  57 + },
  58 + },
  59 + {
  60 + field: 'deviceType',
  61 + label: '设备类型',
  62 + component: 'ApiSelect',
  63 + colProps: { span: 9 },
  64 + componentProps: {
  65 + placeholder: '请选择设备类型',
  66 + api: findDictItemByCode,
  67 + params: {
  68 + dictCode: 'device_type',
  69 + },
  70 + labelField: 'itemText',
  71 + valueField: 'itemValue',
  72 + },
  73 + },
  74 +];
  75 +
  76 +const { clipboardRef, isSuccessRef } = useCopyToClipboard();
  77 +
  78 +const { createMessage } = useMessage();
  79 +
  80 +const deviceTableColumn: BasicColumn[] = [
  81 + {
  82 + title: '状态',
  83 + dataIndex: 'deviceState',
  84 + customRender: ({ text }) => {
  85 + return h(
  86 + Tag,
  87 + {
  88 + color:
  89 + text === DeviceStatusEnum.INACTIVE
  90 + ? 'warning'
  91 + : text === DeviceStatusEnum.OFFLINE
  92 + ? 'error'
  93 + : 'success',
  94 + },
  95 + () => DeviceStatusNameEnum[text]
  96 + );
  97 + },
  98 + },
  99 + {
  100 + title: '别名/设备名称',
  101 + dataIndex: 'name',
  102 + customRender: ({ record }) => {
  103 + return h('div', [
  104 + h(
  105 + 'div',
  106 + {
  107 + class: 'cursor-pointer',
  108 + onClick: () => {
  109 + clipboardRef.value = record.name;
  110 + if (unref(isSuccessRef)) createMessage.success('复制成功~');
  111 + },
  112 + },
  113 + [
  114 + record.alias && h('div', { class: 'truncate' }, record.alias),
  115 + h('div', { class: 'text-blue-400 truncate' }, record.name),
  116 + ]
  117 + ),
  118 + ]);
  119 + },
  120 + },
  121 + {
  122 + title: '设备类型',
  123 + dataIndex: 'deviceType',
  124 + customRender: ({ text }) => {
  125 + return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]);
  126 + },
  127 + },
  128 + {
  129 + title: '所属产品',
  130 + dataIndex: 'deviceProfile.name',
  131 + },
  132 + {
  133 + title: '所属组织',
  134 + dataIndex: 'organizationDTO.name',
  135 + },
  136 +];
  137 +
  138 +const TransferTableProps: BasicTableProps = {
  139 + formConfig: {
  140 + layout: 'inline',
  141 + labelWidth: 80,
  142 + schemas: deviceTableFormSchema,
  143 + actionColOptions: { span: 6 },
  144 + },
  145 + size: 'small',
  146 + maxHeight: 240,
  147 + useSearchForm: true,
  148 + columns: deviceTableColumn,
  149 + showIndexColumn: false,
  150 + fetchSetting: FETCH_SETTING,
  151 +} as BasicTableProps;
  152 +
  153 +export const modeForm = (submitFn?: Function): FormSchema[] => {
  154 + return [
  155 + {
  156 + field: BasicInfoFormField.CONVERT_CONFIG_ID,
  157 + label: '',
  158 + component: 'Input',
  159 + show: false,
  160 + },
  161 + {
  162 + field: BasicInfoFormField.DATA_SOURCE_TYPE,
  163 + label: '数据源',
  164 + component: 'RadioGroup',
  165 + defaultValue: DataSourceType.ALL,
  166 + componentProps: {
  167 + options: [
  168 + { label: '全部', value: DataSourceType.ALL },
  169 + { label: '产品', value: DataSourceType.PRODUCT },
  170 + { label: '设备', value: DataSourceType.DEVICE },
  171 + ],
  172 + },
  173 + },
  174 + {
  175 + field: BasicInfoFormField.DATA_SOURCE_PRODUCT,
  176 + label: '数据源产品',
  177 + component: 'TransferModal',
  178 + ifShow: ({ model }) => {
  179 + return model[BasicInfoFormField.DATA_SOURCE_TYPE] !== DataSourceType.ALL;
  180 + },
  181 + valueField: 'value',
  182 + changeEvent: 'update:value',
  183 + componentProps: ({ formActionType }) => {
  184 + const { setFieldsValue } = formActionType;
  185 + return {
  186 + api: getDeviceProfile,
  187 + labelField: 'name',
  188 + valueField: 'tbProfileId',
  189 + transferProps: {
  190 + listStyle: { height: '400px' },
  191 + showSearch: true,
  192 + filterOption: (inputValue: string, option: Recordable) => {
  193 + const upperCaseInputValue = inputValue.toUpperCase();
  194 + const upperCaseOptionValue = option.name.toUpperCase();
  195 + return upperCaseOptionValue.includes(upperCaseInputValue);
  196 + },
  197 + },
  198 + onChange: () => {
  199 + setFieldsValue({ [BasicInfoFormField.DATA_SOURCE_DEVICE]: [] });
  200 + },
  201 + };
  202 + },
  203 + },
  204 + {
  205 + field: BasicInfoFormField.DATA_SOURCE_DEVICE,
  206 + label: '数据源设备',
  207 + component: 'TransferTableModal',
  208 + ifShow: ({ model }) => {
  209 + return model[BasicInfoFormField.DATA_SOURCE_TYPE] === DataSourceType.DEVICE;
  210 + },
  211 + valueField: 'value',
  212 + changeEvent: 'update:value',
  213 + componentProps: ({ formActionType }) => {
  214 + const { getFieldsValue } = formActionType;
  215 + const values = getFieldsValue();
  216 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  217 + const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);
  218 +
  219 + return {
  220 + labelField: 'name',
  221 + valueField: 'tbDeviceId',
  222 + primaryKey: 'tbDeviceId',
  223 + pendingTableProps: {
  224 + ...TransferTableProps,
  225 + api: devicePage,
  226 + beforeFetch: (params) => {
  227 + const values = getFieldsValue();
  228 + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  229 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  230 + if (convertConfigId) {
  231 + Object.assign(params, { convertConfigId, selected: false });
  232 + }
  233 + return { ...params, deviceProfileIds };
  234 + },
  235 + } as BasicTableProps,
  236 + selectedTableProps: {
  237 + ...TransferTableProps,
  238 + // api
  239 + api: !!(convertConfigId && devices) ? devicePage : undefined,
  240 + beforeFetch: (params) => {
  241 + const values = getFieldsValue();
  242 + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  243 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  244 + if (convertConfigId) {
  245 + Object.assign(params, { convertConfigId, selected: true });
  246 + }
  247 + return { ...params, deviceProfileIds };
  248 + },
  249 + } as BasicTableProps,
  250 + initSelectedOptions: async ({ setSelectedTotal }) => {
  251 + const values = getFieldsValue();
  252 + const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);
  253 + const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);
  254 + const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);
  255 + if (convertConfigId && devices) {
  256 + const { items, total } = await devicePage({
  257 + page: 1,
  258 + pageSize: 10,
  259 + convertConfigId: values[BasicInfoFormField.CONVERT_CONFIG_ID],
  260 + deviceProfileIds,
  261 + selected: true,
  262 + });
  263 + setSelectedTotal(total);
  264 + return items;
  265 + }
  266 + return [];
  267 + },
  268 + onSelectedAfter: async () => {
  269 + submitFn && (await submitFn(false));
  270 + },
  271 + onRemoveAfter: async ({ reloadSelected }) => {
  272 + submitFn && (await submitFn(false));
  273 + reloadSelected();
  274 + },
  275 + transformValue: (_selectedRowKeys: string[], selectedRows: DeviceRecord[]) => {
  276 + return handleGroupDevice(selectedRows);
  277 + },
  278 + };
  279 + },
  280 + },
  281 + {
  282 + field: 'type',
  283 + label: '转换方式',
  284 + component: 'ApiSelect',
  285 + required: true,
  286 + colProps: {
  287 + span: 24,
  288 + },
  289 + componentProps({}) {
  290 + return {
  291 + api: findDictItemByCode,
  292 + params: {
  293 + dictCode: 'convert_data_to',
  294 + },
  295 + labelField: 'itemText',
  296 + valueField: 'itemValue',
  297 + };
  298 + },
  299 + },
  300 + {
  301 + field: 'remark',
  302 + label: '描述',
  303 + colProps: { span: 24 },
  304 + component: 'Input',
  305 + componentProps: {
  306 + maxLength: 255,
  307 + placeholder: '请输入描述',
  308 + },
  309 + },
  310 + ];
  311 +};
  1 +/**
  2 + * 数据流转相关枚举配置
  3 + */
  4 +
  5 +//业务 数据源配置枚举
  6 +export enum BasicInfoFormField {
  7 + DATA_SOURCE_TYPE = 'datasourceType',
  8 + DATA_SOURCE_PRODUCT = 'datasourceProduct',
  9 + DATA_SOURCE_DEVICE = 'datasourceDevice',
  10 + CONVERT_CONFIG_ID = 'convertConfigId',
  11 +}
  12 +
  13 +export enum DataSourceType {
  14 + ALL = 'ALL',
  15 + PRODUCT = 'PRODUCTS',
  16 + DEVICE = 'DEVICES',
  17 +}
  18 +
  19 +export enum DeviceStatusEnum {
  20 + OFFLINE = 'OFFLINE',
  21 + ONLINE = 'ONLINE',
  22 + INACTIVE = 'INACTIVE',
  23 +}
  24 +
  25 +export enum DeviceStatusNameEnum {
  26 + OFFLINE = '离线',
  27 + ONLINE = '在线',
  28 + INACTIVE = '待激活',
  29 +}
  30 +
  31 +export enum DeviceTypeEnum {
  32 + SENSOR = 'SENSOR',
  33 + DIRECT_CONNECTION = 'DIRECT_CONNECTION',
  34 + GATEWAY = 'GATEWAY',
  35 +}
  36 +
  37 +export enum DeviceTypeNameEnum {
  38 + SENSOR = '网关子设备',
  39 + DIRECT_CONNECTION = '直连设备',
  40 + GATEWAY = '网关设备',
  41 +}
  1 +import DataFlowModal from './DataFlowModal.vue';
  2 +import DataFlowMethod from './DataFlowMethod.vue';
  3 +import DataFlowParams from './DataFlowParams.vue';
  4 +
  5 +export { DataFlowModal, DataFlowMethod, DataFlowParams };
  1 +/**
  2 + * 选择流转方式相关类型定义
  3 + */
  4 +export interface ConvertDevice {
  5 + product: string;
  6 + devices: string[];
  7 +}
  8 +
  9 +export interface DatasourceContent {
  10 + convertProducts: string[];
  11 + convertDevices: ConvertDevice[];
  12 +}
  13 +
  14 +export interface BasicInfoRecord {
  15 + name?: string;
  16 + type: string;
  17 + remark: string;
  18 + datasourceType: string;
  19 + datasourceContent: DatasourceContent;
  20 +}
  1 +import UploadFile from './index.vue';
  2 +
  3 +export { UploadFile };
  1 +<template>
  2 + <div>
  3 + <a-upload-dragger
  4 + v-model:fileList="fileList.list"
  5 + name="file"
  6 + :multiple="false"
  7 + @change="handleChange($event)"
  8 + :before-upload="() => false"
  9 + >
  10 + <p class="ant-upload-drag-icon">
  11 + <InboxOutlined />
  12 + </p>
  13 + <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>
  14 + <p class="ant-upload-hint">
  15 + 支持扩展名:{{ supportFileType.join(' ') }}
  16 + <br />
  17 + 文件大小:最大支持{{ fileLimitSize }}M
  18 + </p>
  19 + </a-upload-dragger>
  20 + <Image
  21 + class="mt-2"
  22 + style="width: 6.25rem; height: 6.25rem"
  23 + v-if="url ? url : imgUrl"
  24 + :src="url ? url : imgUrl"
  25 + />
  26 + </div>
  27 +</template>
  28 +<script lang="ts" setup name="uploadfile">
  29 + import { ref, reactive } from 'vue';
  30 + import { InboxOutlined } from '@ant-design/icons-vue';
  31 + import { Image } from 'ant-design-vue';
  32 + import { useMessage } from '/@/hooks/web/useMessage';
  33 + import { uploadApi } from '/@/api/personal/index';
  34 +
  35 + defineProps({
  36 + url: {
  37 + type: String,
  38 + default: '',
  39 + },
  40 + });
  41 +
  42 + const emit = defineEmits(['fileUrlEmit']);
  43 +
  44 + const { createMessage } = useMessage();
  45 +
  46 + const imgUrl = ref('');
  47 +
  48 + const fileList = reactive<any>({
  49 + list: [],
  50 + });
  51 +
  52 + const supportFileType = ['image/png', 'image/png', 'image/jpeg', 'image/gif'];
  53 +
  54 + const fileLimitSize = 5;
  55 +
  56 + //验证图片类型和大小
  57 + const beforeUploadVerify = (type, size) => {
  58 + let status = false;
  59 + const limitImgSize = (size as number) / 1024 / 1024 < fileLimitSize;
  60 + if (!supportFileType.includes(type)) {
  61 + status = false;
  62 + const errorType = `只能上传其中${supportFileType.join(' ')}中的类型!`;
  63 + createMessage.error(errorType);
  64 + throw Error(errorType);
  65 + }
  66 + status = true;
  67 + if (!limitImgSize) {
  68 + status = false;
  69 + const errorType = `图片大小不能超过${fileLimitSize}MB!`;
  70 + createMessage.error(errorType);
  71 + throw Error(errorType);
  72 + }
  73 + status = true;
  74 + return status;
  75 + };
  76 +
  77 + const handleChange = async ({ file }) => {
  78 + const fileStatus = file.status;
  79 + const fileSize = file.size;
  80 + const fileType = file.type;
  81 + if (fileStatus === 'removed') {
  82 + fileList.list = [];
  83 + imgUrl.value = '';
  84 + } else {
  85 + if (!beforeUploadVerify(fileType, fileSize)) return;
  86 + fileList.list = [file];
  87 + const formData = new FormData();
  88 + formData.append('file', file);
  89 + const { fileStaticUri } = await uploadApi(formData);
  90 + if (!fileStaticUri) return;
  91 + imgUrl.value = fileStaticUri;
  92 + emit('fileUrlEmit', fileStaticUri);
  93 + }
  94 + };
  95 +</script>
  96 +
  97 +<style lang="less" scoped></style>
src/views/rule/dataFlow/config/index.ts renamed from src/views/rule/dataFlow/config.ts
1 -import { BasicColumn, FormSchema } from '/@/components/Table';  
2 -import { h } from 'vue';  
3 -import { Tag } from 'ant-design-vue';  
4 -  
5 -export const columns: BasicColumn[] = [  
6 - {  
7 - title: '数据流转名称',  
8 - dataIndex: 'name',  
9 - width: 200,  
10 - },  
11 - {  
12 - title: '途径',  
13 - dataIndex: 'type',  
14 - width: 200,  
15 - customRender: ({ record }) => {  
16 - const status = record.type;  
17 - const enable =  
18 - status === 'org.thingsboard.rule.engine.kafka.TbKafkaNode'  
19 - ? 'KafKa'  
20 - : record.type === 'org.thingsboard.rule.engine.mqtt.TbMqttNode'  
21 - ? 'MQTT'  
22 - : record.type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'  
23 - ? 'RabbitMQ'  
24 - : 'REST_API';  
25 - const color =  
26 - enable == 'KafKa'  
27 - ? '#0099FF'  
28 - : enable == 'MQTT'  
29 - ? '#7C7CC9'  
30 - : enable == 'RabbitMQ'  
31 - ? '#E8A15E'  
32 - : '#81B1AB';  
33 - const text =  
34 - enable == 'KafKa'  
35 - ? 'KafKa'  
36 - : enable == 'MQTT'  
37 - ? 'MQTT'  
38 - : enable == 'RabbitMQ'  
39 - ? 'RabbitMQ'  
40 - : 'REST_API';  
41 - return h(Tag, { color: color }, () => text);  
42 - },  
43 -  
44 - format: (_text: string, record: Recordable) => {  
45 - return record.type === 'org.thingsboard.rule.engine.kafka.TbKafkaNode'  
46 - ? 'KafKa'  
47 - : record.type === 'org.thingsboard.rule.engine.mqtt.TbMqttNode'  
48 - ? 'MQTT'  
49 - : record.type === 'org.thingsboard.rule.engine.rabbitmq.TbRabbitMqNode'  
50 - ? 'RabbitMQ'  
51 - : 'REST_API';  
52 - },  
53 - },  
54 - {  
55 - title: '状态',  
56 - dataIndex: 'status',  
57 - width: 120,  
58 - slots: { customRender: 'status' },  
59 - },  
60 - {  
61 - title: '描述',  
62 - dataIndex: 'remark',  
63 - width: 200,  
64 - },  
65 - {  
66 - title: '创建时间',  
67 - dataIndex: 'createTime',  
68 - width: 180,  
69 - },  
70 -];  
71 -  
72 -export const searchFormSchema: FormSchema[] = [  
73 - {  
74 - field: 'name',  
75 - label: '名称',  
76 - component: 'Input',  
77 - colProps: { span: 6 },  
78 - componentProps: {  
79 - maxLength: 36,  
80 - placeholder: '请输入名称',  
81 - },  
82 - },  
83 - {  
84 - field: 'status',  
85 - label: '状态',  
86 - component: 'Select',  
87 - componentProps: {  
88 - placeholder: '请选择状态',  
89 - options: [  
90 - { label: '启用', value: '1' },  
91 - { label: '禁用', value: '0' },  
92 - ],  
93 - },  
94 - colProps: { span: 6 },  
95 - },  
96 -]; 1 +import { BasicColumn, FormSchema, BasicTableProps } from '/@/components/Table';
  2 +import { h } from 'vue';
  3 +import { Tag } from 'ant-design-vue';
  4 +import { useUtil } from '../hooks/index.hook';
  5 +
  6 +const { dataFlowMapTextColor } = useUtil();
  7 +
  8 +export const columns: BasicColumn[] = [
  9 + {
  10 + title: '数据流转名称',
  11 + dataIndex: 'name',
  12 + width: 200,
  13 + },
  14 + {
  15 + title: '途径',
  16 + dataIndex: 'type',
  17 + width: 200,
  18 + customRender: ({ record: { type } }) => {
  19 + const findMethod = dataFlowMapTextColor(type);
  20 + return h(Tag, { color: findMethod?.textColor }, () => findMethod?.label);
  21 + },
  22 + },
  23 + {
  24 + title: '状态',
  25 + dataIndex: 'status',
  26 + width: 120,
  27 + slots: { customRender: 'status' },
  28 + },
  29 + {
  30 + title: '描述',
  31 + dataIndex: 'remark',
  32 + width: 200,
  33 + },
  34 + {
  35 + title: '创建时间',
  36 + dataIndex: 'createTime',
  37 + width: 180,
  38 + },
  39 +];
  40 +
  41 +export const searchFormSchema: FormSchema[] = [
  42 + {
  43 + field: 'name',
  44 + label: '名称',
  45 + component: 'Input',
  46 + colProps: { span: 6 },
  47 + componentProps: {
  48 + maxLength: 36,
  49 + placeholder: '请输入名称',
  50 + },
  51 + },
  52 + {
  53 + field: 'status',
  54 + label: '状态',
  55 + component: 'Select',
  56 + componentProps: {
  57 + placeholder: '请选择状态',
  58 + options: [
  59 + { label: '启用', value: '1' },
  60 + { label: '禁用', value: '0' },
  61 + ],
  62 + },
  63 + colProps: { span: 6 },
  64 + },
  65 +];
  66 +
  67 +export const defaultTableAttribute: BasicTableProps = {
  68 + title: '数据流转列表',
  69 + clickToRowSelect: false,
  70 + columns,
  71 + formConfig: {
  72 + labelWidth: 120,
  73 + schemas: searchFormSchema,
  74 + },
  75 + rowKey: 'id',
  76 + useSearchForm: true,
  77 + showTableSetting: true,
  78 + bordered: true,
  79 + showIndexColumn: false,
  80 + actionColumn: {
  81 + width: 180,
  82 + title: '操作',
  83 + dataIndex: 'action',
  84 + slots: { customRender: 'action' },
  85 + fixed: 'right',
  86 + },
  87 +};
1 -import { FormSchema } from '/@/components/Form';  
2 -import { findDictItemByCode } from '/@/api/system/dict';  
3 -import { h, ref, unref } from 'vue';  
4 -import { isExistDataManagerNameApi } from '/@/api/datamanager/dataManagerApi';  
5 -import { getDeviceProfile } from '/@/api/alarm/position';  
6 -import { BasicColumn, BasicTableProps } from '/@/components/Table';  
7 -import { devicePage } from '/@/api/device/deviceManager';  
8 -import { Tag } from 'ant-design-vue';  
9 -import { DeviceRecord } from '/@/api/device/model/deviceModel';  
10 -import { FETCH_SETTING } from '/@/components/Table/src/const';  
11 -import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard';  
12 -import { useMessage } from '/@/hooks/web/useMessage';  
13 -  
14 -const typeValue = ref('');  
15 -export enum CredentialsEnum {  
16 - IS_ANONYMOUS = 'anonymous',  
17 - IS_BASIC = 'basic',  
18 - IS_PEM = 'pem',  
19 -}  
20 -export const isBasic = (type: string) => {  
21 - return type === CredentialsEnum.IS_BASIC;  
22 -};  
23 -export const isPem = (type: string) => {  
24 - return type === CredentialsEnum.IS_PEM;  
25 -};  
26 -  
27 -export enum DataSourceType {  
28 - ALL = 'ALL',  
29 - PRODUCT = 'PRODUCTS',  
30 - DEVICE = 'DEVICES',  
31 -}  
32 -  
33 -export enum BasicInfoFormField {  
34 - DATA_SOURCE_TYPE = 'datasourceType',  
35 - DATA_SOURCE_PRODUCT = 'datasourceProduct',  
36 - DATA_SOURCE_DEVICE = 'datasourceDevice',  
37 - CONVERT_CONFIG_ID = 'convertConfigId',  
38 -}  
39 -  
40 -export enum DeviceStatusEnum {  
41 - OFFLINE = 'OFFLINE',  
42 - ONLINE = 'ONLINE',  
43 - INACTIVE = 'INACTIVE',  
44 -}  
45 -  
46 -export enum DeviceStatusNameEnum {  
47 - OFFLINE = '离线',  
48 - ONLINE = '在线',  
49 - INACTIVE = '待激活',  
50 -}  
51 -  
52 -export enum DeviceTypeEnum {  
53 - SENSOR = 'SENSOR',  
54 - DIRECT_CONNECTION = 'DIRECT_CONNECTION',  
55 - GATEWAY = 'GATEWAY',  
56 -}  
57 -  
58 -export enum DeviceTypeNameEnum {  
59 - SENSOR = '网关子设备',  
60 - DIRECT_CONNECTION = '直连设备',  
61 - GATEWAY = '网关设备',  
62 -}  
63 -  
64 -const handleGroupDevice = (options: DeviceRecord[]) => {  
65 - const map = new Map<string, string[]>();  
66 - options.forEach((item) => {  
67 - if (map.has(item.profileId)) {  
68 - const deviceList = map.get(item.profileId)!;  
69 - deviceList.push(item.tbDeviceId);  
70 - } else {  
71 - map.set(item.profileId, [item.tbDeviceId]);  
72 - }  
73 - });  
74 - const value = Array.from(map.entries()).map(([product, devices]) => ({ product, devices }));  
75 -  
76 - return value;  
77 -};  
78 -  
79 -const deviceTableFormSchema: FormSchema[] = [  
80 - {  
81 - field: 'name',  
82 - label: '设备名称',  
83 - component: 'Input',  
84 - colProps: { span: 9 },  
85 - componentProps: {  
86 - placeholder: '请输入设备名称',  
87 - },  
88 - },  
89 - {  
90 - field: 'deviceType',  
91 - label: '设备类型',  
92 - component: 'ApiSelect',  
93 - colProps: { span: 9 },  
94 - componentProps: {  
95 - placeholder: '请选择设备类型',  
96 - api: findDictItemByCode,  
97 - params: {  
98 - dictCode: 'device_type',  
99 - },  
100 - labelField: 'itemText',  
101 - valueField: 'itemValue',  
102 - },  
103 - },  
104 -];  
105 -const { clipboardRef, isSuccessRef } = useCopyToClipboard();  
106 -const { createMessage } = useMessage();  
107 -const deviceTableColumn: BasicColumn[] = [  
108 - {  
109 - title: '状态',  
110 - dataIndex: 'deviceState',  
111 - customRender: ({ text }) => {  
112 - return h(  
113 - Tag,  
114 - {  
115 - color:  
116 - text === DeviceStatusEnum.INACTIVE  
117 - ? 'warning'  
118 - : text === DeviceStatusEnum.OFFLINE  
119 - ? 'error'  
120 - : 'success',  
121 - },  
122 - () => DeviceStatusNameEnum[text]  
123 - );  
124 - },  
125 - },  
126 - {  
127 - title: '别名/设备名称',  
128 - dataIndex: 'name',  
129 - customRender: ({ record }) => {  
130 - return h('div', [  
131 - h(  
132 - 'div',  
133 - {  
134 - class: 'cursor-pointer',  
135 - onClick: () => {  
136 - clipboardRef.value = record.name;  
137 - if (unref(isSuccessRef)) createMessage.success('复制成功~');  
138 - },  
139 - },  
140 - [  
141 - record.alias && h('div', { class: 'truncate' }, record.alias),  
142 - h('div', { class: 'text-blue-400 truncate' }, record.name),  
143 - ]  
144 - ),  
145 - ]);  
146 - },  
147 - },  
148 - {  
149 - title: '设备类型',  
150 - dataIndex: 'deviceType',  
151 - customRender: ({ text }) => {  
152 - return h(Tag, { color: 'success' }, () => DeviceTypeNameEnum[text]);  
153 - },  
154 - },  
155 - {  
156 - title: '所属产品',  
157 - dataIndex: 'deviceProfile.name',  
158 - },  
159 - {  
160 - title: '所属组织',  
161 - dataIndex: 'organizationDTO.name',  
162 - },  
163 -];  
164 -  
165 -const TransferTableProps: BasicTableProps = {  
166 - formConfig: {  
167 - layout: 'inline',  
168 - labelWidth: 80,  
169 - schemas: deviceTableFormSchema,  
170 - actionColOptions: { span: 6 },  
171 - },  
172 - size: 'small',  
173 - maxHeight: 240,  
174 - useSearchForm: true,  
175 - columns: deviceTableColumn,  
176 - showIndexColumn: false,  
177 - fetchSetting: FETCH_SETTING,  
178 -} as BasicTableProps;  
179 -  
180 -export const modeForm = (submitFn?: Function): FormSchema[] => {  
181 - return [  
182 - {  
183 - field: BasicInfoFormField.CONVERT_CONFIG_ID,  
184 - label: '',  
185 - component: 'Input',  
186 - show: false,  
187 - },  
188 - {  
189 - field: BasicInfoFormField.DATA_SOURCE_TYPE,  
190 - label: '数据源',  
191 - component: 'RadioGroup',  
192 - defaultValue: DataSourceType.ALL,  
193 - componentProps: {  
194 - options: [  
195 - { label: '全部', value: DataSourceType.ALL },  
196 - { label: '产品', value: DataSourceType.PRODUCT },  
197 - { label: '设备', value: DataSourceType.DEVICE },  
198 - ],  
199 - },  
200 - },  
201 - {  
202 - field: BasicInfoFormField.DATA_SOURCE_PRODUCT,  
203 - label: '数据源产品',  
204 - component: 'TransferModal',  
205 - ifShow: ({ model }) => {  
206 - return model[BasicInfoFormField.DATA_SOURCE_TYPE] !== DataSourceType.ALL;  
207 - },  
208 - valueField: 'value',  
209 - changeEvent: 'update:value',  
210 - componentProps: ({ formActionType }) => {  
211 - const { setFieldsValue } = formActionType;  
212 - return {  
213 - api: getDeviceProfile,  
214 - labelField: 'name',  
215 - valueField: 'tbProfileId',  
216 - transferProps: {  
217 - listStyle: { height: '400px' },  
218 - showSearch: true,  
219 - filterOption: (inputValue: string, option: Recordable) => {  
220 - const upperCaseInputValue = inputValue.toUpperCase();  
221 - const upperCaseOptionValue = option.name.toUpperCase();  
222 - return upperCaseOptionValue.includes(upperCaseInputValue);  
223 - },  
224 - },  
225 - onChange: () => {  
226 - setFieldsValue({ [BasicInfoFormField.DATA_SOURCE_DEVICE]: [] });  
227 - },  
228 - };  
229 - },  
230 - },  
231 - {  
232 - field: BasicInfoFormField.DATA_SOURCE_DEVICE,  
233 - label: '数据源设备',  
234 - component: 'TransferTableModal',  
235 - ifShow: ({ model }) => {  
236 - return model[BasicInfoFormField.DATA_SOURCE_TYPE] === DataSourceType.DEVICE;  
237 - },  
238 - valueField: 'value',  
239 - changeEvent: 'update:value',  
240 - componentProps: ({ formActionType }) => {  
241 - const { getFieldsValue } = formActionType;  
242 - const values = getFieldsValue();  
243 - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);  
244 - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);  
245 -  
246 - return {  
247 - labelField: 'name',  
248 - valueField: 'tbDeviceId',  
249 - primaryKey: 'tbDeviceId',  
250 - pendingTableProps: {  
251 - ...TransferTableProps,  
252 - api: devicePage,  
253 - beforeFetch: (params) => {  
254 - const values = getFieldsValue();  
255 - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);  
256 - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);  
257 - if (convertConfigId) {  
258 - Object.assign(params, { convertConfigId, selected: false });  
259 - }  
260 - return { ...params, deviceProfileIds };  
261 - },  
262 - } as BasicTableProps,  
263 - selectedTableProps: {  
264 - ...TransferTableProps,  
265 - // api  
266 - api: !!(convertConfigId && devices) ? devicePage : undefined,  
267 - beforeFetch: (params) => {  
268 - const values = getFieldsValue();  
269 - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);  
270 - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);  
271 - if (convertConfigId) {  
272 - Object.assign(params, { convertConfigId, selected: true });  
273 - }  
274 - return { ...params, deviceProfileIds };  
275 - },  
276 - } as BasicTableProps,  
277 - initSelectedOptions: async ({ setSelectedTotal }) => {  
278 - const values = getFieldsValue();  
279 - const convertConfigId = Reflect.get(values, BasicInfoFormField.CONVERT_CONFIG_ID);  
280 - const deviceProfileIds = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_PRODUCT);  
281 - const devices = Reflect.get(values, BasicInfoFormField.DATA_SOURCE_DEVICE);  
282 - if (convertConfigId && devices) {  
283 - const { items, total } = await devicePage({  
284 - page: 1,  
285 - pageSize: 10,  
286 - convertConfigId: values[BasicInfoFormField.CONVERT_CONFIG_ID],  
287 - deviceProfileIds,  
288 - selected: true,  
289 - });  
290 - setSelectedTotal(total);  
291 - return items;  
292 - }  
293 - return [];  
294 - },  
295 - onSelectedAfter: async () => {  
296 - submitFn && (await submitFn(false));  
297 - },  
298 - onRemoveAfter: async ({ reloadSelected }) => {  
299 - submitFn && (await submitFn(false));  
300 - reloadSelected();  
301 - },  
302 - transformValue: (_selectedRowKeys: string[], selectedRows: DeviceRecord[]) => {  
303 - return handleGroupDevice(selectedRows);  
304 - },  
305 - };  
306 - },  
307 - },  
308 - {  
309 - field: 'type',  
310 - label: '转换方式',  
311 - component: 'ApiSelect',  
312 - required: true,  
313 - colProps: {  
314 - span: 24,  
315 - },  
316 - componentProps({}) {  
317 - return {  
318 - api: findDictItemByCode,  
319 - params: {  
320 - dictCode: 'convert_data_to',  
321 - },  
322 - labelField: 'itemText',  
323 - valueField: 'itemValue',  
324 - onChange(value) {  
325 - typeValue.value = value;  
326 - },  
327 - };  
328 - },  
329 - },  
330 - {  
331 - field: 'remark',  
332 - label: '描述',  
333 - colProps: { span: 24 },  
334 - component: 'Input',  
335 - componentProps: {  
336 - maxLength: 255,  
337 - placeholder: '请输入描述',  
338 - },  
339 - },  
340 - ];  
341 -};  
342 -  
343 -export const modeKafkaForm: FormSchema[] = [  
344 - {  
345 - field: 'name',  
346 - label: '名称',  
347 - colProps: { span: 12 },  
348 - required: true,  
349 - component: 'Input',  
350 - componentProps: {  
351 - maxLength: 255,  
352 - placeholder: '请输入名称',  
353 - },  
354 - dynamicRules: () => {  
355 - return [  
356 - {  
357 - required: true,  
358 - validator(_, value) {  
359 - return new Promise((resolve, reject) => {  
360 - if (value == '') {  
361 - reject('请输入名称');  
362 - } else {  
363 - resolve();  
364 - }  
365 - });  
366 - },  
367 - },  
368 - ];  
369 - },  
370 - },  
371 - {  
372 - field: 'topicPattern',  
373 - label: '消息主题',  
374 - colProps: { span: 12 },  
375 - required: true,  
376 - component: 'Input',  
377 - defaultValue: 'my-topic',  
378 - componentProps: {  
379 - maxLength: 255,  
380 - placeholder: '请输入消息主题',  
381 - },  
382 - },  
383 - {  
384 - field: 'bootstrapServers',  
385 - label: '服务器',  
386 - colProps: { span: 12 },  
387 - component: 'Input',  
388 - defaultValue: 'localhost:9092',  
389 - required: true,  
390 - componentProps: {  
391 - maxLength: 255,  
392 - placeholder: 'localhost:9092',  
393 - },  
394 - },  
395 - {  
396 - field: 'retries',  
397 - label: '重连次数',  
398 - colProps: { span: 12 },  
399 - component: 'InputNumber',  
400 - defaultValue: 0,  
401 - componentProps: {  
402 - maxLength: 255,  
403 - },  
404 - },  
405 - {  
406 - field: 'batchSize',  
407 - label: '生产者并发',  
408 - colProps: { span: 12 },  
409 - component: 'InputNumber',  
410 - defaultValue: 16384,  
411 - componentProps: {  
412 - maxLength: 255,  
413 - },  
414 - },  
415 - {  
416 - field: 'linger',  
417 - label: '缓存时间',  
418 - colProps: { span: 12 },  
419 - component: 'InputNumber',  
420 - defaultValue: 0,  
421 - componentProps: {  
422 - maxLength: 255,  
423 - },  
424 - },  
425 - {  
426 - field: 'bufferMemory',  
427 - label: '最大缓存',  
428 - colProps: { span: 12 },  
429 - component: 'InputNumber',  
430 - defaultValue: 33554432,  
431 - componentProps: {  
432 - maxLength: 255,  
433 - },  
434 - },  
435 - {  
436 - field: 'acks',  
437 - component: 'Select',  
438 - label: '响应码',  
439 - colProps: { span: 12 },  
440 - defaultValue: '-1',  
441 - componentProps: {  
442 - placeholder: '请选择响应码',  
443 - options: [  
444 - { label: 'all', value: 'all' },  
445 - { label: '-1', value: '-1' },  
446 - { label: '0', value: '0' },  
447 - { label: '1', value: '1' },  
448 - ],  
449 - },  
450 - },  
451 - {  
452 - field: 'keySerializer',  
453 - label: '键序列化',  
454 - colProps: { span: 24 },  
455 - required: true,  
456 - component: 'Input',  
457 - defaultValue: 'org.apache.kafka.common.serialization.StringSerializer',  
458 - componentProps: {  
459 - maxLength: 255,  
460 - placeholder: 'org.apache.kafka.common.serialization.StringSerializer',  
461 - },  
462 - },  
463 - {  
464 - field: 'valueSerializer',  
465 - label: '值序列化',  
466 - colProps: { span: 24 },  
467 - required: true,  
468 - component: 'Input',  
469 - defaultValue: 'org.apache.kafka.common.serialization.StringSerializer',  
470 - componentProps: {  
471 - maxLength: 255,  
472 - placeholder: 'org.apache.kafka.common.serialization.StringSerializer',  
473 - },  
474 - },  
475 - {  
476 - field: 'otherProperties',  
477 - label: '其他属性',  
478 - colProps: { span: 24 },  
479 - component: 'JAddInput',  
480 - subLabel: '不可重复',  
481 - },  
482 - {  
483 - field: 'addMetadataKeyValuesAsKafkaHeaders',  
484 - label: '是否启用',  
485 - colProps: { span: 12 },  
486 - component: 'Checkbox',  
487 - renderComponentContent: '将消息的元数据以键值对的方式添加到Kafka消息头中',  
488 - },  
489 - {  
490 - field: 'kafkaHeadersCharset',  
491 - component: 'Select',  
492 - label: '字符集',  
493 - required: true,  
494 - colProps: { span: 12 },  
495 - defaultValue: 'UTF-8',  
496 - componentProps: {  
497 - placeholder: '请选择字符集编码',  
498 - options: [  
499 - { label: 'US-ASCII', value: 'US' },  
500 - { label: 'ISO-8859-1', value: 'ISO-8859-1' },  
501 - { label: 'UTF-8', value: 'UTF-8' },  
502 - { label: 'UTF-16BE', value: 'UTF-16BE' },  
503 - { label: 'UTF-16LE', value: 'UTF-16LE' },  
504 - { label: 'UTF-16', value: 'UTF-16' },  
505 - ],  
506 - },  
507 - ifShow: ({ values }) => {  
508 - return !!values.addMetadataKeyValuesAsKafkaHeaders;  
509 - },  
510 - },  
511 - {  
512 - field: 'description',  
513 - label: '说明',  
514 - colProps: { span: 24 },  
515 - component: 'InputTextArea',  
516 - componentProps: {  
517 - maxLength: 255,  
518 - rows: 4,  
519 - placeholder: '请输入说明',  
520 - },  
521 - },  
522 -];  
523 -  
524 -export const modeMqttForm: FormSchema[] = [  
525 - {  
526 - field: 'name',  
527 - label: '名称',  
528 - colProps: { span: 12 },  
529 - component: 'Input',  
530 - componentProps: {  
531 - maxLength: 255,  
532 - placeholder: '请输入名称',  
533 - },  
534 - },  
535 - {  
536 - field: 'topicPattern',  
537 - label: '主题模式',  
538 - colProps: { span: 12 },  
539 - required: true,  
540 - component: 'Input',  
541 - defaultValue: 'my-topic',  
542 - componentProps: {  
543 - maxLength: 255,  
544 - placeholder: '请输入Topic pattern',  
545 - },  
546 - },  
547 - {  
548 - field: 'host',  
549 - label: '主机',  
550 - colProps: { span: 12 },  
551 - component: 'Input',  
552 - componentProps: {  
553 - maxLength: 255,  
554 - placeholder: '请输入Host',  
555 - },  
556 - },  
557 - {  
558 - field: 'port',  
559 - label: '端口',  
560 - colProps: { span: 12 },  
561 - component: 'InputNumber',  
562 - defaultValue: 1883,  
563 - required: true,  
564 - componentProps: {  
565 - maxLength: 255,  
566 - placeholder: '请输入Port',  
567 - },  
568 - },  
569 - {  
570 - field: 'connectTimeoutSec',  
571 - label: '连接超时(秒)',  
572 - colProps: { span: 12 },  
573 - component: 'InputNumber',  
574 - defaultValue: 10,  
575 - required: true,  
576 - componentProps: {  
577 - maxLength: 255,  
578 - placeholder: '请输入Connection timeout (sec)',  
579 - },  
580 - },  
581 - {  
582 - field: 'clientId',  
583 - label: '客户端ID',  
584 - colProps: { span: 12 },  
585 - component: 'Input',  
586 - componentProps: ({ formActionType }) => {  
587 - const { updateSchema } = formActionType;  
588 - return {  
589 - onChange(e) {  
590 - if (!e.data) {  
591 - updateSchema({  
592 - field: 'appendClientIdSuffix',  
593 - show: false,  
594 - });  
595 - } else {  
596 - updateSchema({  
597 - field: 'appendClientIdSuffix',  
598 - show: true,  
599 - });  
600 - }  
601 - },  
602 - maxLength: 255,  
603 - placeholder: '请输入Client ID',  
604 - };  
605 - },  
606 - },  
607 - {  
608 - field: 'appendClientIdSuffix',  
609 - label: '',  
610 - colProps: { span: 12 },  
611 - defaultValue: false,  
612 - component: 'Checkbox',  
613 - renderComponentContent: '将服务ID作为后缀添加到客户端ID',  
614 - show: false,  
615 - },  
616 - {  
617 - field: 'cleanSession',  
618 - label: '是否启用',  
619 - colProps: { span: 12 },  
620 - defaultValue: true,  
621 - component: 'Checkbox',  
622 - renderComponentContent: '清除会话',  
623 - },  
624 - {  
625 - field: 'ssl',  
626 - label: '是否启用',  
627 - colProps: { span: 12 },  
628 - defaultValue: false,  
629 - component: 'Checkbox',  
630 - renderComponentContent: '启用SSL',  
631 - },  
632 - {  
633 - field: 'type',  
634 - component: 'Select',  
635 - label: '凭据类型',  
636 - colProps: { span: 12 },  
637 - defaultValue: 'anonymous',  
638 - componentProps: {  
639 - placeholder: '请选择Credentials',  
640 - options: [  
641 - { label: 'Anonymous', value: 'anonymous' },  
642 - { label: 'Basic', value: 'basic' },  
643 - { label: 'PEM', value: 'pem' },  
644 - ],  
645 - },  
646 - },  
647 - {  
648 - field: 'username',  
649 - label: '用户名',  
650 - colProps: { span: 12 },  
651 - component: 'Input',  
652 - required: true,  
653 - componentProps: {  
654 - maxLength: 255,  
655 - placeholder: '请输入用户名',  
656 - },  
657 - ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),  
658 - },  
659 - {  
660 - field: 'password',  
661 - label: '密码',  
662 - colProps: { span: 12 },  
663 - component: 'InputPassword',  
664 - componentProps: {  
665 - maxLength: 255,  
666 - placeholder: '请输入密码',  
667 - },  
668 - ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),  
669 - },  
670 - {  
671 - field: '4',  
672 - label: '',  
673 - colProps: { span: 24 },  
674 - component: 'Input',  
675 - slot: 'uploadAdd1',  
676 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
677 - },  
678 - {  
679 - field: '11',  
680 - label: '',  
681 - colProps: { span: 24 },  
682 - component: 'Input',  
683 - slot: 'showImg1',  
684 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
685 - },  
686 - {  
687 - field: '5',  
688 - label: '',  
689 - colProps: { span: 24 },  
690 - component: 'Input',  
691 - slot: 'uploadAdd2',  
692 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
693 - },  
694 - {  
695 - field: '1111',  
696 - label: '',  
697 - colProps: { span: 24 },  
698 - component: 'Input',  
699 - slot: 'showImg2',  
700 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
701 - },  
702 - {  
703 - field: '6',  
704 - label: '',  
705 - colProps: { span: 24 },  
706 - component: 'Input',  
707 - slot: 'uploadAdd3',  
708 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
709 - },  
710 - {  
711 - field: '111111',  
712 - label: '',  
713 - colProps: { span: 24 },  
714 - component: 'Input',  
715 - slot: 'showImg3',  
716 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
717 - },  
718 - {  
719 - field: 'password',  
720 - label: '密码',  
721 - colProps: { span: 12 },  
722 - component: 'InputPassword',  
723 - componentProps: {  
724 - maxLength: 255,  
725 - placeholder: '请输入密码',  
726 - },  
727 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
728 - },  
729 - {  
730 - field: 'description',  
731 - label: '说明',  
732 - colProps: { span: 24 },  
733 - component: 'InputTextArea',  
734 - componentProps: {  
735 - maxLength: 255,  
736 - rows: 4,  
737 - placeholder: '请输入说明',  
738 - },  
739 - },  
740 -];  
741 -  
742 -export const modeRabbitMqForm: FormSchema[] = [  
743 - {  
744 - field: 'name',  
745 - label: '名称',  
746 - colProps: { span: 12 },  
747 - required: true,  
748 - component: 'Input',  
749 - componentProps: {  
750 - maxLength: 255,  
751 - placeholder: '请输入名称',  
752 - },  
753 - dynamicRules: () => {  
754 - return [  
755 - {  
756 - required: true,  
757 - validator(_, value) {  
758 - return new Promise((resolve, reject) => {  
759 - if (value == '') {  
760 - reject('请输入名称');  
761 - } else {  
762 - resolve();  
763 - }  
764 - });  
765 - },  
766 - },  
767 - ];  
768 - },  
769 - },  
770 - {  
771 - field: 'exchangeNamePattern',  
772 - label: '交换名称模式',  
773 - colProps: { span: 12 },  
774 - component: 'Input',  
775 - componentProps: {  
776 - maxLength: 255,  
777 - placeholder: '请输入模式',  
778 - },  
779 - },  
780 - {  
781 - field: 'routingKeyPattern',  
782 - label: '路由密钥模式',  
783 - colProps: { span: 12 },  
784 - component: 'Input',  
785 - componentProps: {  
786 - maxLength: 255,  
787 - placeholder: '请输入模式',  
788 - },  
789 - },  
790 - {  
791 - field: 'messageProperties',  
792 - component: 'Select',  
793 - label: '消息属性',  
794 - colProps: { span: 12 },  
795 - componentProps: {  
796 - placeholder: '请选择消息属性',  
797 - options: [  
798 - { label: 'BASIC', value: 'BASIC' },  
799 - { label: 'TEXT_PLAIN', value: 'TEXT_PLAIN' },  
800 - { label: 'MINIMAL_BASIC', value: 'MINIMAL_BASIC' },  
801 - { label: 'MINIMAL_PERSISTENT_BASIC', value: 'MINIMAL_PERSISTENT_BASIC' },  
802 - { label: 'PERSISTENT_BASIC', value: 'PERSISTENT_BASIC' },  
803 - { label: 'PERSISTENT_TEXT_PLAIN', value: 'PERSISTENT_TEXT_PLAIN' },  
804 - ],  
805 - },  
806 - },  
807 - {  
808 - field: 'host',  
809 - label: '主机',  
810 - colProps: { span: 12 },  
811 - component: 'Input',  
812 - required: true,  
813 - defaultValue: 'localhost',  
814 - componentProps: {  
815 - maxLength: 255,  
816 - placeholder: 'localhost',  
817 - },  
818 - },  
819 - {  
820 - field: 'port',  
821 - label: '端口',  
822 - colProps: { span: 12 },  
823 - component: 'InputNumber',  
824 - defaultValue: 5672,  
825 - required: true,  
826 - componentProps: {  
827 - maxLength: 255,  
828 - placeholder: '请输入Port',  
829 - },  
830 - },  
831 - {  
832 - field: 'virtualHost',  
833 - label: '虚拟端口(以/开头)',  
834 - colProps: { span: 12 },  
835 - component: 'Input',  
836 - defaultValue: '/',  
837 - componentProps: {  
838 - maxLength: 255,  
839 - placeholder: '/',  
840 - },  
841 - },  
842 - {  
843 - field: 'username',  
844 - label: '用户名',  
845 - colProps: { span: 12 },  
846 - component: 'Input',  
847 - defaultValue: 'guest',  
848 - componentProps: {  
849 - maxLength: 255,  
850 - placeholder: '请输入用户名',  
851 - },  
852 - },  
853 - {  
854 - field: 'password',  
855 - label: '密码',  
856 - colProps: { span: 12 },  
857 - component: 'InputPassword',  
858 - defaultValue: 'guest',  
859 - componentProps: {  
860 - maxLength: 255,  
861 - placeholder: '请输入密码',  
862 - },  
863 - },  
864 - {  
865 - field: 'automaticRecoveryEnabled',  
866 - label: '是否启用',  
867 - colProps: { span: 12 },  
868 - component: 'Checkbox',  
869 - renderComponentContent: '自动恢复',  
870 - },  
871 - {  
872 - field: 'connectionTimeout',  
873 - label: '连接超时(毫秒)',  
874 - colProps: { span: 12 },  
875 - component: 'InputNumber',  
876 - defaultValue: 60000,  
877 - componentProps: {  
878 - maxLength: 255,  
879 - placeholder: '请输入Connection timeout (ms)',  
880 - },  
881 - },  
882 - {  
883 - field: 'handshakeTimeout',  
884 - label: '握手超时(毫秒)',  
885 - colProps: { span: 12 },  
886 - component: 'InputNumber',  
887 - defaultValue: 10000,  
888 - componentProps: {  
889 - maxLength: 255,  
890 - placeholder: '请输入Handshake timeout (ms)',  
891 - },  
892 - },  
893 - {  
894 - field: 'clientProperties',  
895 - label: '客户端属性',  
896 - colProps: { span: 24 },  
897 - component: 'JAddInput',  
898 - subLabel: '不可重复',  
899 - },  
900 - {  
901 - field: 'description',  
902 - label: '说明',  
903 - colProps: { span: 24 },  
904 - component: 'InputTextArea',  
905 - componentProps: {  
906 - maxLength: 255,  
907 - rows: 4,  
908 - placeholder: '请输入说明',  
909 - },  
910 - },  
911 -];  
912 -  
913 -export const modeApiForm: FormSchema[] = [  
914 - {  
915 - field: 'name',  
916 - label: '名称',  
917 - colProps: { span: 12 },  
918 - required: true,  
919 - component: 'Input',  
920 - componentProps: {  
921 - maxLength: 255,  
922 - placeholder: '请输入名称',  
923 - },  
924 - dynamicRules: ({ values }) => {  
925 - return [  
926 - {  
927 - required: true,  
928 - validator(_, value) {  
929 - return new Promise((resolve, reject) => {  
930 - if (value == '') {  
931 - reject('请输入名称');  
932 - } else {  
933 - if (values.name) {  
934 - isExistDataManagerNameApi({  
935 - name: value,  
936 - type:  
937 - typeValue.value == ''  
938 - ? 'org.thingsboard.rule.engine.rest.TbRestApiCallNode'  
939 - : typeValue.value,  
940 - }).then((data) => {  
941 - if (data == true) {  
942 - // createMessage.error('名称已存在');  
943 - resolve();  
944 - } else {  
945 - resolve();  
946 - }  
947 - });  
948 - } else {  
949 - resolve();  
950 - }  
951 - }  
952 - });  
953 - },  
954 - },  
955 - ];  
956 - },  
957 - },  
958 - {  
959 - field: 'restEndpointUrlPattern',  
960 - label: '端点URL模式',  
961 - colProps: { span: 12 },  
962 - required: true,  
963 - defaultValue: 'http://localhost/api',  
964 - component: 'Input',  
965 - componentProps: {  
966 - maxLength: 255,  
967 - placeholder: '请输入Endpoint URL pattern',  
968 - },  
969 - },  
970 - {  
971 - field: 'requestMethod',  
972 - component: 'Select',  
973 - label: '请求方式',  
974 - colProps: { span: 12 },  
975 - defaultValue: 'POST',  
976 - componentProps: {  
977 - placeholder: '请选择Request method',  
978 - options: [  
979 - { label: 'GET', value: 'GET' },  
980 - { label: 'POST', value: 'POST' },  
981 - { label: 'PUT', value: 'PUT' },  
982 - { label: 'DELETE', value: 'DELETE' },  
983 - ],  
984 - },  
985 - },  
986 - {  
987 - field: 'enableProxy',  
988 - label: '是否启用',  
989 - colProps: { span: 12 },  
990 - component: 'Checkbox',  
991 - renderComponentContent: '启用代理',  
992 - },  
993 -  
994 - {  
995 - field: 'proxyHost',  
996 - label: '代理主机',  
997 - colProps: { span: 12 },  
998 - required: true,  
999 - component: 'Input',  
1000 - componentProps: {  
1001 - maxLength: 255,  
1002 - placeholder: 'http或者https开头',  
1003 - },  
1004 - ifShow: ({ values }) => {  
1005 - return !!values.enableProxy;  
1006 - },  
1007 - },  
1008 - {  
1009 - field: 'proxyPort',  
1010 - label: '代理端口',  
1011 - colProps: { span: 12 },  
1012 - required: true,  
1013 - component: 'InputNumber',  
1014 - defaultValue: 0,  
1015 - componentProps: {  
1016 - maxLength: 255,  
1017 - placeholder: 'http或者https开头',  
1018 - },  
1019 - ifShow: ({ values }) => {  
1020 - return !!values.enableProxy;  
1021 - },  
1022 - },  
1023 - {  
1024 - field: 'proxyUser',  
1025 - label: '代理用户',  
1026 - colProps: { span: 12 },  
1027 - required: true,  
1028 - component: 'Input',  
1029 - componentProps: {  
1030 - maxLength: 255,  
1031 - placeholder: '请输入代理用户',  
1032 - },  
1033 - ifShow: ({ values }) => {  
1034 - return !!values.enableProxy;  
1035 - },  
1036 - },  
1037 - {  
1038 - field: 'proxyPassword',  
1039 - label: '代理密码',  
1040 - colProps: { span: 12 },  
1041 - required: true,  
1042 - component: 'InputPassword',  
1043 - componentProps: {  
1044 - maxLength: 255,  
1045 - placeholder: '请输入代理密码',  
1046 - },  
1047 - ifShow: ({ values }) => {  
1048 - return !!values.enableProxy;  
1049 - },  
1050 - },  
1051 -  
1052 - {  
1053 - field: 'useSystemProxyProperties',  
1054 - label: '是否启用',  
1055 - colProps: { span: 12 },  
1056 - component: 'Checkbox',  
1057 - renderComponentContent: '使用系统代理属性',  
1058 - },  
1059 - {  
1060 - field: 'maxParallelRequestsCount',  
1061 - label: '最大并行请求数',  
1062 - colProps: { span: 12 },  
1063 - required: true,  
1064 - component: 'InputNumber',  
1065 - defaultValue: 0,  
1066 - componentProps: {  
1067 - maxLength: 255,  
1068 - },  
1069 - ifShow: ({ values }) => {  
1070 - return !!values.useSystemProxyProperties;  
1071 - },  
1072 - },  
1073 - {  
1074 - field: 'ignoreRequestBody',  
1075 - label: '是否启用',  
1076 - colProps: { span: 12 },  
1077 - component: 'Checkbox',  
1078 - renderComponentContent: '无请求正文',  
1079 - },  
1080 - {  
1081 - field: 'readTimeoutMs',  
1082 - label: '读取超时(毫秒)',  
1083 - colProps: { span: 12 },  
1084 - required: true,  
1085 - component: 'InputNumber',  
1086 - defaultValue: 0,  
1087 - componentProps: {  
1088 - maxLength: 255,  
1089 - },  
1090 - ifShow: ({ values }) => {  
1091 - return !values.useSystemProxyProperties;  
1092 - },  
1093 - },  
1094 - {  
1095 - field: 'maxParallelRequestsCount',  
1096 - label: '最大并行请求数',  
1097 - colProps: { span: 12 },  
1098 - required: true,  
1099 - component: 'InputNumber',  
1100 - defaultValue: 0,  
1101 - componentProps: {  
1102 - maxLength: 255,  
1103 - },  
1104 - ifShow: ({ values }) => {  
1105 - return !values.useSystemProxyProperties;  
1106 - },  
1107 - },  
1108 - {  
1109 - field: 'headers',  
1110 - label: 'Headers',  
1111 - colProps: { span: 24 },  
1112 - defaultValue: { 'Content-Type': 'application/json' },  
1113 - component: 'JAddInput',  
1114 - subLabel: '不可重复',  
1115 - },  
1116 -  
1117 - {  
1118 - field: 'useRedisQueueForMsgPersistence',  
1119 - label: '是否启用',  
1120 - colProps: { span: 12 },  
1121 - component: 'Checkbox',  
1122 - renderComponentContent: '使用redis队列进行消息持久性',  
1123 - },  
1124 - {  
1125 - field: 'trimQueue',  
1126 - label: '是否启用',  
1127 - colProps: { span: 12 },  
1128 - component: 'Checkbox',  
1129 - renderComponentContent: '修剪redis队列',  
1130 - ifShow: ({ values }) => {  
1131 - return !!values.useRedisQueueForMsgPersistence;  
1132 - },  
1133 - },  
1134 - {  
1135 - field: 'maxQueueSize',  
1136 - label: 'Redis队列最大数',  
1137 - colProps: { span: 12 },  
1138 - required: true,  
1139 - component: 'InputNumber',  
1140 - defaultValue: 0,  
1141 - componentProps: {  
1142 - maxLength: 255,  
1143 - },  
1144 - ifShow: ({ values }) => {  
1145 - return !!values.useRedisQueueForMsgPersistence;  
1146 - },  
1147 - },  
1148 -  
1149 - {  
1150 - field: 'type',  
1151 - component: 'Select',  
1152 - label: '凭据类型',  
1153 - colProps: { span: 12 },  
1154 - defaultValue: 'anonymous',  
1155 - componentProps: {  
1156 - placeholder: '请选择凭据类型',  
1157 - options: [  
1158 - { label: 'Anonymous', value: 'anonymous' },  
1159 - { label: 'Basic', value: 'basic' },  
1160 - { label: 'PEM', value: 'pem' },  
1161 - ],  
1162 - },  
1163 - },  
1164 - {  
1165 - field: 'username',  
1166 - label: '用户名',  
1167 - colProps: { span: 12 },  
1168 - component: 'Input',  
1169 - required: true,  
1170 - componentProps: {  
1171 - maxLength: 255,  
1172 - placeholder: '请输入用户名',  
1173 - },  
1174 - ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),  
1175 - },  
1176 - {  
1177 - field: 'password',  
1178 - label: '密码',  
1179 - colProps: { span: 12 },  
1180 - component: 'InputPassword',  
1181 - required: true,  
1182 - componentProps: {  
1183 - maxLength: 255,  
1184 - placeholder: '请输入密码',  
1185 - },  
1186 - ifShow: ({ values }) => isBasic(Reflect.get(values, 'type')),  
1187 - },  
1188 - {  
1189 - field: '1',  
1190 - label: '',  
1191 - colProps: { span: 24 },  
1192 - component: 'Input',  
1193 - slot: 'uploadAdd1',  
1194 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1195 - },  
1196 - {  
1197 - field: '11',  
1198 - label: '',  
1199 - colProps: { span: 24 },  
1200 - component: 'Input',  
1201 - slot: 'showImg1',  
1202 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1203 - },  
1204 - {  
1205 - field: '1',  
1206 - label: '',  
1207 - colProps: { span: 24 },  
1208 - component: 'Input',  
1209 - slot: 'uploadAdd2',  
1210 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1211 - },  
1212 - {  
1213 - field: '1111',  
1214 - label: '',  
1215 - colProps: { span: 24 },  
1216 - component: 'Input',  
1217 - slot: 'showImg2',  
1218 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1219 - },  
1220 - {  
1221 - field: '1',  
1222 - label: '',  
1223 - colProps: { span: 24 },  
1224 - component: 'Input',  
1225 - slot: 'uploadAdd3',  
1226 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1227 - },  
1228 - {  
1229 - field: '111111',  
1230 - label: '',  
1231 - colProps: { span: 24 },  
1232 - component: 'Input',  
1233 - slot: 'showImg3',  
1234 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1235 - },  
1236 - {  
1237 - field: 'password',  
1238 - label: '密码',  
1239 - colProps: { span: 12 },  
1240 - component: 'InputPassword',  
1241 - componentProps: {  
1242 - maxLength: 255,  
1243 - placeholder: '请输入密码',  
1244 - },  
1245 - ifShow: ({ values }) => isPem(Reflect.get(values, 'type')),  
1246 - },  
1247 -  
1248 - {  
1249 - field: 'description',  
1250 - label: '说明',  
1251 - colProps: { span: 24 },  
1252 - component: 'InputTextArea',  
1253 - componentProps: {  
1254 - maxLength: 255,  
1255 - rows: 4,  
1256 - placeholder: '请输入说明',  
1257 - },  
1258 - },  
1259 -];  
1 -<template>  
2 - <div class="transfer-config-mode">  
3 - <BasicForm :showSubmitButton="false" @register="register">  
4 - <template #uploadAdd1="{ field }">  
5 - <span style="display: none">{{ field }}</span>  
6 - <a-upload-dragger  
7 - v-model:fileList="fileList1"  
8 - name="file"  
9 - :multiple="false"  
10 - @change="handleChange('T', $event)"  
11 - :before-upload="() => false"  
12 - >  
13 - <p class="ant-upload-drag-icon">  
14 - <InboxOutlined />  
15 - </p>  
16 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
17 - <p class="ant-upload-hint">  
18 - 支持扩展名:.jpeg .png .jpg ...  
19 - <br />  
20 - 文件大小:最大支持5M  
21 - </p>  
22 - </a-upload-dragger>  
23 - </template>  
24 - <template #showImg1="{ field }">  
25 - <span style="display: none">{{ field }}</span>  
26 - <img  
27 - v-if="showImg1"  
28 - :src="showImg1Pic"  
29 - alt="avatar"  
30 - style="width: 6.25rem; height: 6.25rem"  
31 - />  
32 - </template>  
33 - <template #uploadAdd2="{ field }">  
34 - <span style="display: none">{{ field }}</span>  
35 - <a-upload-dragger  
36 - v-model:fileList="fileList2"  
37 - name="file"  
38 - :multiple="false"  
39 - @change="handleChange('F', $event)"  
40 - :before-upload="() => false"  
41 - >  
42 - <p class="ant-upload-drag-icon">  
43 - <InboxOutlined />  
44 - </p>  
45 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
46 - <p class="ant-upload-hint">  
47 - 支持扩展名:.jpeg .png .jpg ...  
48 - <br />  
49 - 文件大小:最大支持5M  
50 - </p>  
51 - </a-upload-dragger>  
52 - </template>  
53 - <template #showImg2="{ field }">  
54 - <span style="display: none">{{ field }}</span>  
55 - <img  
56 - v-if="showImg2"  
57 - :src="showImg2Pic"  
58 - alt="avatar"  
59 - style="width: 6.25rem; height: 6.25rem"  
60 - />  
61 - </template>  
62 - <template #uploadAdd3="{ field }">  
63 - <span style="display: none">{{ field }}</span>  
64 - <a-upload-dragger  
65 - v-model:fileList="fileList3"  
66 - name="file"  
67 - :multiple="false"  
68 - @change="handleChange('C', $event)"  
69 - :before-upload="() => false"  
70 - >  
71 - <p class="ant-upload-drag-icon">  
72 - <InboxOutlined />  
73 - </p>  
74 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
75 - <p class="ant-upload-hint">  
76 - 支持扩展名:.jpeg .png .jpg ...  
77 - <br />  
78 - 文件大小:最大支持5M  
79 - </p>  
80 - </a-upload-dragger>  
81 - </template>  
82 - <template #showImg3="{ field }">  
83 - <span style="display: none">{{ field }}</span>  
84 - <img  
85 - v-if="showImg3"  
86 - :src="showImg3Pic"  
87 - alt="avatar"  
88 - style="width: 6.25rem; height: 6.25rem"  
89 - />  
90 - </template>  
91 - </BasicForm>  
92 - </div>  
93 -</template>  
94 -<script lang="ts">  
95 - import { defineComponent, ref, reactive, nextTick } from 'vue';  
96 - import { BasicForm, useForm } from '/@/components/Form';  
97 - import { modeApiForm, CredentialsEnum } from '../config';  
98 - import { InboxOutlined } from '@ant-design/icons-vue';  
99 - import { Upload } from 'ant-design-vue';  
100 - import { useMessage } from '/@/hooks/web/useMessage';  
101 - import { uploadApi } from '/@/api/personal/index';  
102 -  
103 - export default defineComponent({  
104 - components: {  
105 - BasicForm,  
106 - InboxOutlined,  
107 - [Upload.Dragger.name]: Upload.Dragger,  
108 - },  
109 - emits: ['next', 'prev', 'register'],  
110 - setup(_, { emit }) {  
111 - const showImg1 = ref(false);  
112 - const showImg1Pic = ref('');  
113 - const showImg2 = ref(false);  
114 - const showImg2Pic = ref('');  
115 - const showImg3 = ref(false);  
116 - const showImg3Pic = ref('');  
117 - const { createMessage } = useMessage();  
118 - let caCertFileName = ref('');  
119 - let privateKeyFileName = ref('');  
120 - let certFileName = ref('');  
121 - let fileList1: any = ref<[]>([]);  
122 - let fileList2: any = ref<[]>([]);  
123 - let fileList3: any = ref<[]>([]);  
124 - const credentialsV: any = reactive({  
125 - credentials: {  
126 - type: '',  
127 - },  
128 - });  
129 - const sonValues: any = reactive({  
130 - configuration: {},  
131 - });  
132 - const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({  
133 - labelWidth: 120,  
134 - schemas: modeApiForm,  
135 - actionColOptions: {  
136 - span: 14,  
137 - },  
138 - resetButtonOptions: {  
139 - text: '上一步',  
140 - },  
141 - resetFunc: customResetFunc,  
142 - submitFunc: customSubmitFunc,  
143 - });  
144 -  
145 - const setStepTwoFieldsValueFunc = (v, v1, v2) => {  
146 - setFieldsValue(v);  
147 - setFieldsValue({  
148 - name: v1,  
149 - description: v2,  
150 - });  
151 - setFieldsValue({  
152 - password: v.credentials?.password,  
153 - username: v.credentials?.username,  
154 - type: v.credentials?.type,  
155 - });  
156 - fileList1.value = [{ name: v.credentials?.caCertFileName.slice(39), uid: '4' }];  
157 - fileList2.value = [{ name: v.credentials?.certFileName.slice(39), uid: '5' }];  
158 - fileList3.value = [{ name: v.credentials?.privateKeyFileName.slice(39), uid: '6' }];  
159 - caCertFileName.value = v.credentials?.caCertFileName;  
160 - certFileName.value = v.credentials?.certFileName;  
161 - privateKeyFileName.value = v.credentials?.privateKeyFileName;  
162 - const iscaCertFileNamePic = v.credentials?.caCertFileName.split('.').pop();  
163 - const iscertFileNamePic = v.credentials?.certFileName.split('.').pop();  
164 - const isprivateKeyFileNamePic = v.credentials?.privateKeyFileName.split('.').pop();  
165 - if (  
166 - iscaCertFileNamePic == 'jpg' ||  
167 - iscaCertFileNamePic == 'png' ||  
168 - iscaCertFileNamePic == 'jpeg' ||  
169 - iscaCertFileNamePic == 'gif'  
170 - ) {  
171 - showImg1.value = true;  
172 - showImg1Pic.value = v.credentials?.caCertFileName;  
173 - } else {  
174 - showImg1.value = false;  
175 - }  
176 - if (  
177 - iscertFileNamePic == 'jpg' ||  
178 - iscertFileNamePic == 'png' ||  
179 - iscertFileNamePic == 'jpeg' ||  
180 - iscertFileNamePic == 'gif'  
181 - ) {  
182 - showImg2.value = true;  
183 - showImg2Pic.value = v.credentials?.certFileName;  
184 - } else {  
185 - showImg2.value = false;  
186 - }  
187 - if (  
188 - isprivateKeyFileNamePic == 'jpg' ||  
189 - isprivateKeyFileNamePic == 'png' ||  
190 - isprivateKeyFileNamePic == 'jpeg' ||  
191 - isprivateKeyFileNamePic == 'gif'  
192 - ) {  
193 - showImg3.value = true;  
194 - showImg3Pic.value = v.credentials?.privateKeyFileName;  
195 - } else {  
196 - showImg3.value = false;  
197 - }  
198 - };  
199 - const customClearStepTwoValueFunc = async () => {  
200 - nextTick(() => {  
201 - defineClearFunc();  
202 - fileList1.value = [];  
203 - fileList2.value = [];  
204 - fileList3.value = [];  
205 - caCertFileName.value = '';  
206 - privateKeyFileName.value = '';  
207 - certFileName.value = '';  
208 - showImg1.value = false;  
209 - showImg1Pic.value = '';  
210 - showImg2.value = false;  
211 - showImg2Pic.value = '';  
212 - showImg3.value = false;  
213 - showImg3Pic.value = '';  
214 - });  
215 - };  
216 - async function customResetFunc() {  
217 - emit('prev');  
218 - }  
219 - async function customSubmitFunc() {  
220 - try {  
221 - const values = await validate();  
222 - emit('next', values);  
223 - } catch (error) {  
224 - } finally {  
225 - }  
226 - }  
227 - /**  
228 - * 上传图片  
229 - */  
230 - const handleChange = async (e, { file }) => {  
231 - if (file.status === 'removed') {  
232 - if (e == 'T') {  
233 - fileList1.value = [];  
234 - showImg1.value = false;  
235 - showImg1Pic.value = '';  
236 - caCertFileName.value = '';  
237 - } else if (e == 'F') {  
238 - fileList2.value = [];  
239 - showImg2.value = false;  
240 - showImg2Pic.value = '';  
241 - certFileName.value = '';  
242 - } else {  
243 - fileList3.value = [];  
244 - showImg3.value = false;  
245 - showImg3Pic.value = '';  
246 - privateKeyFileName.value = '';  
247 - }  
248 - } else {  
249 - const isLt5M = file.size / 1024 / 1024 < 5;  
250 - if (!isLt5M) {  
251 - createMessage.error('图片大小不能超过5MB!');  
252 - } else {  
253 - e == 'T'  
254 - ? (fileList1.value = [file])  
255 - : e == 'F'  
256 - ? (fileList2.value = [file])  
257 - : (fileList3.value = [file]);  
258 - const formData = new FormData();  
259 - formData.append('file', file);  
260 - const response = await uploadApi(formData);  
261 - if (response.fileStaticUri) {  
262 - if (e == 'T') {  
263 - caCertFileName.value = response.fileStaticUri;  
264 - const iscaCertFileNamePic = caCertFileName.value.split('.').pop();  
265 - if (  
266 - iscaCertFileNamePic == 'jpg' ||  
267 - iscaCertFileNamePic == 'png' ||  
268 - iscaCertFileNamePic == 'jpeg' ||  
269 - iscaCertFileNamePic == 'gif'  
270 - ) {  
271 - showImg1.value = true;  
272 - showImg1Pic.value = response.fileStaticUri;  
273 - } else {  
274 - showImg1.value = false;  
275 - }  
276 - } else if (e == 'F') {  
277 - certFileName.value = response.fileStaticUri;  
278 - const iscertFileNamePic = certFileName.value.split('.').pop();  
279 - if (  
280 - iscertFileNamePic == 'jpg' ||  
281 - iscertFileNamePic == 'png' ||  
282 - iscertFileNamePic == 'jpeg' ||  
283 - iscertFileNamePic == 'gif'  
284 - ) {  
285 - showImg2.value = true;  
286 - showImg2Pic.value = response.fileStaticUri;  
287 - } else {  
288 - showImg2.value = false;  
289 - }  
290 - } else {  
291 - privateKeyFileName.value = response.fileStaticUri;  
292 - const isprivateKeyFileNamePic = privateKeyFileName.value.split('.').pop();  
293 - if (  
294 - isprivateKeyFileNamePic == 'jpg' ||  
295 - isprivateKeyFileNamePic == 'png' ||  
296 - isprivateKeyFileNamePic == 'jpeg' ||  
297 - isprivateKeyFileNamePic == 'gif'  
298 - ) {  
299 - showImg3.value = true;  
300 - showImg3Pic.value = response.fileStaticUri;  
301 - } else {  
302 - showImg3.value = false;  
303 - }  
304 - }  
305 - }  
306 - }  
307 - }  
308 - };  
309 -  
310 - const getSonValueFunc = async () => {  
311 - sonValues.configuration = await validate();  
312 - credentialsV.credentials.type = sonValues.configuration.type;  
313 - if (credentialsV.credentials.type == CredentialsEnum.IS_BASIC) {  
314 - credentialsV.credentials.username = sonValues.configuration.username;  
315 - credentialsV.credentials.password = sonValues.configuration.password;  
316 - sonValues.configuration.username = undefined;  
317 - sonValues.configuration.password = undefined;  
318 - } else if (credentialsV.credentials.type == CredentialsEnum.IS_PEM) {  
319 - credentialsV.credentials.caCertFileName = caCertFileName.value;  
320 - credentialsV.credentials.certFileName = certFileName.value;  
321 - credentialsV.credentials.privateKeyFileName = privateKeyFileName.value;  
322 - credentialsV.credentials.password = sonValues.configuration.password;  
323 - }  
324 - Object.assign(sonValues.configuration, credentialsV);  
325 - return sonValues;  
326 - };  
327 - return {  
328 - register,  
329 - setStepTwoFieldsValueFunc,  
330 - customClearStepTwoValueFunc,  
331 - getSonValueFunc,  
332 - handleChange,  
333 - fileList1,  
334 - fileList2,  
335 - fileList3,  
336 - caCertFileName,  
337 - privateKeyFileName,  
338 - certFileName,  
339 - showImg1,  
340 - showImg1Pic,  
341 - showImg2,  
342 - showImg2Pic,  
343 - showImg3,  
344 - showImg3Pic,  
345 - };  
346 - },  
347 - });  
348 -</script>  
349 -<style lang="less" scoped>  
350 - :deep(.ant-col-24) {  
351 - margin-bottom: 20px !important;  
352 - }  
353 - :deep(.ant-btn-default) {  
354 - color: white;  
355 - background: #377dff;  
356 - }  
357 -</style>  
1 -<template>  
2 - <div class="transfer-config-mode">  
3 - <BasicForm :showSubmitButton="false" @register="register" />  
4 - </div>  
5 -</template>  
6 -<script lang="ts">  
7 - import { defineComponent, ref, reactive, nextTick } from 'vue';  
8 - import { BasicForm, useForm } from '/@/components/Form';  
9 - import { modeKafkaForm } from '../config';  
10 - import { Alert, Divider, Descriptions } from 'ant-design-vue';  
11 -  
12 - export default defineComponent({  
13 - components: {  
14 - BasicForm,  
15 - [Alert.name]: Alert,  
16 - [Divider.name]: Divider,  
17 - [Descriptions.name]: Descriptions,  
18 - [Descriptions.Item.name]: Descriptions.Item,  
19 - },  
20 - emits: ['next', 'prev', 'register'],  
21 - setup(_, { emit }) {  
22 - const keyAndValueArr: any = ref<[]>([]);  
23 - const vType = ref('');  
24 - const sonValues = reactive({  
25 - configuration: {},  
26 - });  
27 - const clearName = ref('');  
28 - const [register, { validate, setFieldsValue, resetFields: defineClearFunc, clearValidate }] =  
29 - useForm({  
30 - labelWidth: 130,  
31 - schemas: modeKafkaForm,  
32 - actionColOptions: {  
33 - span: 14,  
34 - },  
35 - resetButtonOptions: {  
36 - text: '上一步',  
37 - },  
38 - resetFunc: customResetFunc,  
39 - });  
40 -  
41 - const clearValidateFunc = async () => {  
42 - await clearValidate(['name']);  
43 - };  
44 -  
45 - const setStepTwoFieldsValueFunc = async (v, v1, v2) => {  
46 - clearName.value = v1;  
47 - setFieldsValue(v);  
48 - vType.value = v1;  
49 - setFieldsValue({  
50 - name: v1,  
51 - description: v2,  
52 - });  
53 - };  
54 -  
55 - const customClearStepTwoValueFunc = async () => {  
56 - nextTick(() => {  
57 - defineClearFunc();  
58 - });  
59 - };  
60 - async function customResetFunc() {  
61 - emit('prev');  
62 - }  
63 - const getSonValueFunc = async () => {  
64 - try {  
65 - sonValues.configuration = await validate();  
66 - Object.assign(sonValues.configuration);  
67 - return sonValues;  
68 - } catch (e) {  
69 - return e;  
70 - }  
71 - };  
72 - return {  
73 - clearValidateFunc,  
74 - getSonValueFunc,  
75 - keyAndValueArr,  
76 - register,  
77 - setStepTwoFieldsValueFunc,  
78 - customClearStepTwoValueFunc,  
79 - customResetFunc,  
80 - };  
81 - },  
82 - });  
83 -</script>  
84 -  
85 -<style lang="less" scoped>  
86 - :deep(.ant-btn-default) {  
87 - color: white;  
88 - background: #377dff;  
89 - }  
90 -</style>  
1 -<template>  
2 - <div class="transfer-config-mode">  
3 - <BasicForm :showSubmitButton="false" @register="register">  
4 - <template #uploadAdd1="{ field }">  
5 - <span style="display: none">{{ field }}</span>  
6 - <a-upload-dragger  
7 - v-model:fileList="fileList1"  
8 - name="file"  
9 - :key="1"  
10 - :multiple="false"  
11 - @change="handleChange('T', $event)"  
12 - :before-upload="() => false"  
13 - >  
14 - <p class="ant-upload-drag-icon">  
15 - <InboxOutlined />  
16 - </p>  
17 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
18 - <p class="ant-upload-hint">  
19 - 支持扩展名:.jpeg .png .jpg ...  
20 - <br />  
21 - 文件大小:最大支持5M  
22 - </p>  
23 - </a-upload-dragger>  
24 - </template>  
25 - <template #showImg1="{ field }">  
26 - <span style="display: none">{{ field }}</span>  
27 - <img  
28 - v-if="showImg1"  
29 - :src="showImg1Pic"  
30 - alt="avatar"  
31 - style="width: 6.25rem; height: 6.25rem"  
32 - />  
33 - </template>  
34 - <div style="margin-top: 50px"></div>  
35 - <template #uploadAdd2="{ field }">  
36 - <span style="display: none">{{ field }}</span>  
37 - <a-upload-dragger  
38 - v-model:fileList="fileList2"  
39 - name="file"  
40 - :key="2"  
41 - :multiple="false"  
42 - @change="handleChange('F', $event)"  
43 - :before-upload="() => false"  
44 - >  
45 - <p class="ant-upload-drag-icon">  
46 - <InboxOutlined />  
47 - </p>  
48 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
49 - <p class="ant-upload-hint">  
50 - 支持扩展名:.jpeg .png .jpg ...  
51 - <br />  
52 - 文件大小:最大支持5M  
53 - </p>  
54 - </a-upload-dragger>  
55 - </template>  
56 - <template #showImg2="{ field }">  
57 - <span style="display: none">{{ field }}</span>  
58 - <img  
59 - v-if="showImg2"  
60 - :src="showImg2Pic"  
61 - alt="avatar"  
62 - style="width: 6.25rem; height: 6.25rem"  
63 - />  
64 - </template>  
65 - <div style="margin-top: 50px"></div>  
66 - <template #uploadAdd3="{ field }">  
67 - <span style="display: none">{{ field }}</span>  
68 - <a-upload-dragger  
69 - v-model:fileList="fileList3"  
70 - name="file"  
71 - :key="3"  
72 - :multiple="false"  
73 - @change="handleChange('C', $event)"  
74 - :before-upload="() => false"  
75 - >  
76 - <p class="ant-upload-drag-icon">  
77 - <InboxOutlined />  
78 - </p>  
79 - <p class="ant-upload-text">点击或将文件拖拽到这里上传</p>  
80 - <p class="ant-upload-hint">  
81 - 支持扩展名:.jpeg .png .jpg ...  
82 - <br />  
83 - 文件大小:最大支持5M  
84 - </p>  
85 - </a-upload-dragger>  
86 - </template>  
87 - <template #showImg3="{ field }">  
88 - <span style="display: none">{{ field }}</span>  
89 - <img  
90 - v-if="showImg3"  
91 - :src="showImg3Pic"  
92 - alt="avatar"  
93 - style="width: 6.25rem; height: 6.25rem"  
94 - />  
95 - </template>  
96 - </BasicForm>  
97 - </div>  
98 -</template>  
99 -<script lang="ts">  
100 - import { defineComponent, ref, reactive, nextTick } from 'vue';  
101 - import { BasicForm, useForm } from '/@/components/Form';  
102 - import { CredentialsEnum, modeMqttForm } from '../config';  
103 - import { InboxOutlined } from '@ant-design/icons-vue';  
104 - import { Alert, Divider, Descriptions, Upload } from 'ant-design-vue';  
105 - import { uploadApi } from '/@/api/personal/index';  
106 - import { useMessage } from '/@/hooks/web/useMessage';  
107 -  
108 - export default defineComponent({  
109 - components: {  
110 - BasicForm,  
111 - [Alert.name]: Alert,  
112 - [Divider.name]: Divider,  
113 - [Descriptions.name]: Descriptions,  
114 - [Descriptions.Item.name]: Descriptions.Item,  
115 - InboxOutlined,  
116 - [Upload.Dragger.name]: Upload.Dragger,  
117 - },  
118 - emits: ['next', 'prev', 'register'],  
119 - setup(_, { emit }) {  
120 - const showImg1 = ref(false);  
121 - const showImg1Pic = ref('');  
122 - const showImg2 = ref(false);  
123 - const showImg2Pic = ref('');  
124 - const showImg3 = ref(false);  
125 - const showImg3Pic = ref('');  
126 - const { createMessage } = useMessage();  
127 - let caCertFileName = ref('');  
128 - let privateKeyFileName = ref('');  
129 - let certFileName = ref('');  
130 - let fileList1: any = ref<[]>([]);  
131 - let fileList2: any = ref<[]>([]);  
132 - let fileList3: any = ref<[]>([]);  
133 - const credentialsV: any = reactive({  
134 - credentials: {  
135 - type: '',  
136 - },  
137 - });  
138 - const sonValues: any = reactive({  
139 - configuration: {},  
140 - });  
141 - const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({  
142 - labelWidth: 120,  
143 - schemas: modeMqttForm,  
144 - actionColOptions: {  
145 - span: 14,  
146 - },  
147 - resetButtonOptions: {  
148 - text: '上一步',  
149 - },  
150 - resetFunc: customResetFunc,  
151 - submitFunc: customSubmitFunc,  
152 - });  
153 -  
154 - /**  
155 - * 上传图片  
156 - */  
157 - const handleChange = async (e, { file }) => {  
158 - if (file.status === 'removed') {  
159 - if (e == 'T') {  
160 - fileList1.value = [];  
161 - showImg1.value = false;  
162 - showImg1Pic.value = '';  
163 - caCertFileName.value = '';  
164 - } else if (e == 'F') {  
165 - fileList2.value = [];  
166 - showImg2.value = false;  
167 - showImg2Pic.value = '';  
168 - certFileName.value = '';  
169 - } else {  
170 - fileList3.value = [];  
171 - showImg3.value = false;  
172 - showImg3Pic.value = '';  
173 - privateKeyFileName.value = '';  
174 - }  
175 - } else {  
176 - const isLt5M = file.size / 1024 / 1024 < 5;  
177 - if (!isLt5M) {  
178 - createMessage.error('图片大小不能超过5MB!');  
179 - } else {  
180 - e == 'T'  
181 - ? (fileList1.value = [file])  
182 - : e == 'F'  
183 - ? (fileList2.value = [file])  
184 - : (fileList3.value = [file]);  
185 - const formData = new FormData();  
186 - formData.append('file', file);  
187 - const response = await uploadApi(formData);  
188 - if (response.fileStaticUri) {  
189 - if (e == 'T') {  
190 - caCertFileName.value = response.fileStaticUri;  
191 - const iscaCertFileNamePic = caCertFileName.value.split('.').pop();  
192 - if (  
193 - iscaCertFileNamePic == 'jpg' ||  
194 - iscaCertFileNamePic == 'png' ||  
195 - iscaCertFileNamePic == 'jpeg' ||  
196 - iscaCertFileNamePic == 'gif'  
197 - ) {  
198 - showImg1.value = true;  
199 - showImg1Pic.value = response.fileStaticUri;  
200 - } else {  
201 - showImg1.value = false;  
202 - }  
203 - } else if (e == 'F') {  
204 - certFileName.value = response.fileStaticUri;  
205 - const iscertFileNamePic = certFileName.value.split('.').pop();  
206 - if (  
207 - iscertFileNamePic == 'jpg' ||  
208 - iscertFileNamePic == 'png' ||  
209 - iscertFileNamePic == 'jpeg' ||  
210 - iscertFileNamePic == 'gif'  
211 - ) {  
212 - showImg2.value = true;  
213 - showImg2Pic.value = response.fileStaticUri;  
214 - } else {  
215 - showImg2.value = false;  
216 - }  
217 - } else {  
218 - privateKeyFileName.value = response.fileStaticUri;  
219 - const isprivateKeyFileNamePic = privateKeyFileName.value.split('.').pop();  
220 - if (  
221 - isprivateKeyFileNamePic == 'jpg' ||  
222 - isprivateKeyFileNamePic == 'png' ||  
223 - isprivateKeyFileNamePic == 'jpeg' ||  
224 - isprivateKeyFileNamePic == 'gif'  
225 - ) {  
226 - showImg3.value = true;  
227 - showImg3Pic.value = response.fileStaticUri;  
228 - } else {  
229 - showImg3.value = false;  
230 - }  
231 - }  
232 - }  
233 - }  
234 - }  
235 - };  
236 - const setStepTwoFieldsValueFunc = (v, v1, v2) => {  
237 - setFieldsValue(v);  
238 - setFieldsValue({  
239 - name: v1,  
240 - description: v2,  
241 - });  
242 - setFieldsValue({  
243 - password: v.credentials?.password,  
244 - username: v.credentials?.username,  
245 - type: v.credentials?.type,  
246 - });  
247 - fileList1.value = [  
248 - {  
249 - name: v.credentials?.caCertFileName.slice(39),  
250 - uid: '1',  
251 - },  
252 - ];  
253 - fileList2.value = [  
254 - {  
255 - name: v.credentials?.certFileName.slice(39),  
256 - uid: '2',  
257 - },  
258 - ];  
259 - fileList3.value = [  
260 - {  
261 - name: v.credentials?.privateKeyFileName.slice(39),  
262 - uid: '3',  
263 - },  
264 - ];  
265 - caCertFileName.value = v.credentials?.caCertFileName;  
266 - certFileName.value = v.credentials?.certFileName;  
267 - privateKeyFileName.value = v.credentials?.privateKeyFileName;  
268 - const iscaCertFileNamePic = v.credentials?.caCertFileName.split('.').pop();  
269 - const iscertFileNamePic = v.credentials?.certFileName.split('.').pop();  
270 - const isprivateKeyFileNamePic = v.credentials?.privateKeyFileName.split('.').pop();  
271 - if (  
272 - iscaCertFileNamePic == 'jpg' ||  
273 - iscaCertFileNamePic == 'png' ||  
274 - iscaCertFileNamePic == 'jpeg' ||  
275 - iscaCertFileNamePic == 'gif'  
276 - ) {  
277 - showImg1.value = true;  
278 - showImg1Pic.value = v.credentials?.caCertFileName;  
279 - } else {  
280 - showImg1.value = false;  
281 - }  
282 - if (  
283 - iscertFileNamePic == 'jpg' ||  
284 - iscertFileNamePic == 'png' ||  
285 - iscertFileNamePic == 'jpeg' ||  
286 - iscertFileNamePic == 'gif'  
287 - ) {  
288 - showImg2.value = true;  
289 - showImg2Pic.value = v.credentials?.certFileName;  
290 - } else {  
291 - showImg2.value = false;  
292 - }  
293 - if (  
294 - isprivateKeyFileNamePic == 'jpg' ||  
295 - isprivateKeyFileNamePic == 'png' ||  
296 - isprivateKeyFileNamePic == 'jpeg' ||  
297 - isprivateKeyFileNamePic == 'gif'  
298 - ) {  
299 - showImg3.value = true;  
300 - showImg3Pic.value = v.credentials?.privateKeyFileName;  
301 - } else {  
302 - showImg3.value = false;  
303 - }  
304 - };  
305 - const customClearStepTwoValueFunc = async () => {  
306 - nextTick(() => {  
307 - defineClearFunc();  
308 - fileList1.value = [];  
309 - fileList2.value = [];  
310 - fileList3.value = [];  
311 - caCertFileName.value = '';  
312 - privateKeyFileName.value = '';  
313 - certFileName.value = '';  
314 - showImg1.value = false;  
315 - showImg1Pic.value = '';  
316 - showImg2.value = false;  
317 - showImg2Pic.value = '';  
318 - showImg3.value = false;  
319 - showImg3Pic.value = '';  
320 - });  
321 - };  
322 - async function customResetFunc() {  
323 - emit('prev');  
324 - }  
325 - async function customSubmitFunc() {  
326 - try {  
327 - const values = await validate();  
328 - emit('next', values);  
329 - } catch (error) {  
330 - } finally {  
331 - }  
332 - }  
333 - const getSonValueFunc = async () => {  
334 - sonValues.configuration = await validate();  
335 - credentialsV.credentials.type = sonValues.configuration.type;  
336 - if (credentialsV.credentials.type == CredentialsEnum.IS_BASIC) {  
337 - credentialsV.credentials.username = sonValues.configuration.username;  
338 - credentialsV.credentials.password = sonValues.configuration.password;  
339 - sonValues.configuration.username = undefined;  
340 - sonValues.configuration.password = undefined;  
341 - } else if (credentialsV.credentials.type == CredentialsEnum.IS_PEM) {  
342 - credentialsV.credentials.caCertFileName = caCertFileName.value;  
343 - credentialsV.credentials.certFileName = certFileName.value;  
344 - credentialsV.credentials.privateKeyFileName = privateKeyFileName.value;  
345 - }  
346 - if (!sonValues.configuration.clientId) {  
347 - sonValues.configuration.clientId = null;  
348 - }  
349 - Object.assign(sonValues.configuration, credentialsV);  
350 - return sonValues;  
351 - };  
352 - return {  
353 - getSonValueFunc,  
354 - register,  
355 - setStepTwoFieldsValueFunc,  
356 - customClearStepTwoValueFunc,  
357 - fileList1,  
358 - fileList2,  
359 - fileList3,  
360 - handleChange,  
361 - caCertFileName,  
362 - privateKeyFileName,  
363 - certFileName,  
364 - showImg1,  
365 - showImg1Pic,  
366 - showImg2,  
367 - showImg2Pic,  
368 - showImg3,  
369 - showImg3Pic,  
370 - };  
371 - },  
372 - });  
373 -</script>  
374 -  
375 -<style lang="less" scoped>  
376 - :deep(.ant-col-24) {  
377 - margin-bottom: 20px !important;  
378 - }  
379 -  
380 - :deep(.ant-btn-default) {  
381 - color: white;  
382 - background: #377dff;  
383 - }  
384 -</style>  
1 -<template>  
2 - <div class="transfer-config-mode">  
3 - <BasicForm :showSubmitButton="false" @register="register" />  
4 - </div>  
5 -</template>  
6 -<script lang="ts">  
7 - import { defineComponent, reactive, nextTick } from 'vue';  
8 - import { BasicForm, useForm } from '/@/components/Form';  
9 - import { modeRabbitMqForm } from '../config';  
10 -  
11 - export default defineComponent({  
12 - components: {  
13 - BasicForm,  
14 - },  
15 - emits: ['next', 'prev', 'register'],  
16 - setup(_, { emit }) {  
17 - const sonValues = reactive({  
18 - configuration: {},  
19 - });  
20 -  
21 - const [register, { validate, setFieldsValue, resetFields: defineClearFunc }] = useForm({  
22 - labelWidth: 140,  
23 - schemas: modeRabbitMqForm,  
24 - actionColOptions: {  
25 - span: 14,  
26 - },  
27 - resetButtonOptions: {  
28 - text: '上一步',  
29 - },  
30 -  
31 - resetFunc: customResetFunc,  
32 - submitFunc: customSubmitFunc,  
33 - });  
34 -  
35 - const setStepTwoFieldsValueFunc = (v, v1, v2) => {  
36 - setFieldsValue(v);  
37 - setFieldsValue({  
38 - name: v1,  
39 - description: v2,  
40 - });  
41 - };  
42 - const customClearStepTwoValueFunc = async () => {  
43 - nextTick(() => {  
44 - defineClearFunc();  
45 - });  
46 - };  
47 - async function customResetFunc() {  
48 - emit('prev');  
49 - }  
50 - async function customSubmitFunc() {  
51 - try {  
52 - const values = await validate();  
53 - emit('next', values);  
54 - } catch (error) {  
55 - } finally {  
56 - }  
57 - }  
58 -  
59 - const getSonValueFunc = async () => {  
60 - sonValues.configuration = await validate();  
61 - Object.assign(sonValues.configuration);  
62 - return sonValues;  
63 - };  
64 -  
65 - return {  
66 - getSonValueFunc,  
67 - register,  
68 - setStepTwoFieldsValueFunc,  
69 - customClearStepTwoValueFunc,  
70 - };  
71 - },  
72 - });  
73 -</script>  
74 -<style lang="less" scoped>  
75 - :deep(.ant-btn-default) {  
76 - color: white;  
77 - background: #377dff;  
78 - }  
79 -</style>  
1 -<template>  
2 - <div class="transfer-config-mode">  
3 - <BasicForm @register="register" />  
4 - </div>  
5 -</template>  
6 -  
7 -<script lang="ts">  
8 - import { defineComponent, ref, nextTick } from 'vue';  
9 - import { BasicForm, useForm } from '/@/components/Form';  
10 - import { BasicInfoFormField, modeForm } from './config';  
11 - import { Select, Input, Divider } from 'ant-design-vue';  
12 -  
13 - export interface ConvertDevice {  
14 - product: string;  
15 - devices: string[];  
16 - }  
17 -  
18 - export interface DatasourceContent {  
19 - convertProducts: string[];  
20 - convertDevices: ConvertDevice[];  
21 - }  
22 -  
23 - export interface BasicInfoRecord {  
24 - name?: string;  
25 - type: string;  
26 - remark: string;  
27 - datasourceType: string;  
28 - datasourceContent: DatasourceContent;  
29 - }  
30 -  
31 - export default defineComponent({  
32 - components: {  
33 - BasicForm,  
34 - [Select.name]: Select,  
35 - [Input.name]: Input,  
36 - [Input.Group.name]: Input.Group,  
37 - [Divider.name]: Divider,  
38 - },  
39 - props: {  
40 - saveContent: {  
41 - type: Function,  
42 - },  
43 - },  
44 - emits: ['next', 'resetFunc', 'register'],  
45 - setup(props, { emit }) {  
46 - const sonValues = ref<BasicInfoRecord>({} as unknown as BasicInfoRecord);  
47 - const [register, { validateFields, setFieldsValue, resetFields }] = useForm({  
48 - labelWidth: 100,  
49 - schemas: modeForm(props.saveContent),  
50 - actionColOptions: {  
51 - span: 14,  
52 - },  
53 - showResetButton: false,  
54 - submitButtonOptions: {  
55 - text: '下一步',  
56 - },  
57 - submitFunc: customSubmitFunc,  
58 - });  
59 - //提交数据  
60 - async function customSubmitFunc() {  
61 - try {  
62 - const values = await validateFields();  
63 - emit('next', values);  
64 - } catch (error) {}  
65 - }  
66 - //回显数据  
67 - const setStepOneFieldsValueFunc = (record: Recordable) => {  
68 - const value = {  
69 - ...record,  
70 - [BasicInfoFormField.DATA_SOURCE_PRODUCT]:  
71 - record?.datasourceContent?.convertProducts || [],  
72 - [BasicInfoFormField.DATA_SOURCE_DEVICE]: record?.datasourceContent?.convertDevices,  
73 - // [BasicInfoFormField.DATA_SOURCE_DEVICE]:  
74 - // (record?.datasourceContent?.convertDevices || []).reduce((prev, next) => {  
75 - // return [...prev, ...(next?.devices || [])];  
76 - // }, []) || [],  
77 - };  
78 - setFieldsValue(value);  
79 - };  
80 -  
81 - //清空数据  
82 - const customResetStepOneFunc = () => {  
83 - nextTick(() => {  
84 - resetFields();  
85 - });  
86 - };  
87 - const getSonValueFunc = async () => {  
88 - const record = (await validateFields()) || {};  
89 - const { type, remark } = record;  
90 - const datasourceType = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_TYPE);  
91 - const convertDevices = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_DEVICE);  
92 - const convertProducts = Reflect.get(record, BasicInfoFormField.DATA_SOURCE_PRODUCT);  
93 -  
94 - sonValues.value = {  
95 - type,  
96 - remark,  
97 - datasourceType,  
98 - datasourceContent: {  
99 - convertProducts,  
100 - convertDevices,  
101 - },  
102 - };  
103 - return sonValues.value;  
104 - };  
105 - return {  
106 - getSonValueFunc,  
107 - register,  
108 - setStepOneFieldsValueFunc,  
109 - customResetStepOneFunc,  
110 - };  
111 - },  
112 - });  
113 -</script>  
114 -<style lang="less">  
115 - .transfer-config-mode {  
116 - margin: 0 auto;  
117 - width: 600px;  
118 - }  
119 -</style>