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>