Commit 1a84167fb93024bb3a698f28b063a150e9adeaa3

Authored by ww
1 parent ba5016e3

feat: 完成Flow类所有组件

Showing 48 changed files with 2495 additions and 91 deletions
... ... @@ -5,6 +5,7 @@
5 5 "public/resource/tinymce/langs"
6 6 ],
7 7 "cSpell.words": [
  8 + "ACKS",
8 9 "clazz",
9 10 "Cmds",
10 11 "COAP",
... ... @@ -19,9 +20,12 @@
19 20 "noconflict",
20 21 "notif",
21 22 "PROTOBUF",
  23 + "Rabbitmq",
22 24 "rtsp",
23 25 "SCADA",
  26 + "SMTPS",
24 27 "SNMP",
  28 + "TSLV",
25 29 "UNACK",
26 30 "unref",
27 31 "vben",
... ...
... ... @@ -5,6 +5,7 @@ import { defHttp } from '/@/utils/http/axios';
5 5 enum Api {
6 6 GET_DEVICE_INFOS = '/tenant/deviceInfos',
7 7 GET_DEVICE_TYPE = '/device/types',
  8 + TENANT_QUEUE = '/tenant/queues',
8 9 }
9 10
10 11 export const getDeviceInfos = () => {
... ... @@ -24,3 +25,13 @@ export const getDeviceTypes = () => {
24 25 { joinPrefix: false }
25 26 );
26 27 };
  28 +
  29 +export const getTenantQueue = (params: Recordable) => {
  30 + return defHttp.get<string[]>(
  31 + {
  32 + url: Api.TENANT_QUEUE,
  33 + params,
  34 + },
  35 + { joinPrefix: false }
  36 + );
  37 +};
... ...
... ... @@ -3,6 +3,7 @@ import { RuleChainType } from '/@/views/rule/designer/types/ruleNode';
3 3
4 4 enum Api {
5 5 SAVE = '/ruleChain/metadata',
  6 + GET_RULE_CHAINES = '/ruleChains',
6 7 }
7 8
8 9 export const getRuleChainData = (id: string) => {
... ... @@ -23,3 +24,15 @@ export const saveRuleChainData = (data: RuleChainType) => {
23 24 { joinPrefix: false }
24 25 );
25 26 };
  27 +
  28 +export const getRuleChains = (params: Recordable) => {
  29 + return defHttp.get(
  30 + {
  31 + url: Api.GET_RULE_CHAINES,
  32 + params,
  33 + },
  34 + {
  35 + joinPrefix: false,
  36 + }
  37 + );
  38 +};
... ...
... ... @@ -14,6 +14,7 @@
14 14 import { get, omit } from 'lodash-es';
15 15 import { LoadingOutlined } from '@ant-design/icons-vue';
16 16 import { useI18n } from '/@/hooks/web/useI18n';
  17 + import { useDebounceFn } from '@vueuse/shared';
17 18
18 19 const emit = defineEmits(['options-change', 'change']);
19 20 const props = withDefaults(
... ... @@ -53,7 +54,7 @@
53 54 const { labelField, valueField = 'value', numberToString } = props;
54 55 return unref(options).reduce((prev, next: Recordable) => {
55 56 if (next) {
56   - const value = next[valueField];
  57 + const value = get(next, valueField);
57 58 prev.push({
58 59 label: next[labelField],
59 60 value: numberToString ? `${value}` : value,
... ... @@ -122,6 +123,7 @@
122 123 onChangeHook({ options });
123 124 }
124 125
  126 + const debounceSearchFunction = useDebounceFn(handleSearch, 300);
125 127 async function handleSearch(params?: string) {
126 128 let { searchApi, api } = props;
127 129 if (!searchApi || !isFunction(searchApi)) {
... ... @@ -156,7 +158,7 @@
156 158 show-search
157 159 @change="handleChange"
158 160 :options="getOptions"
159   - @search="handleSearch"
  161 + @search="debounceSearchFunction"
160 162 v-model:value="state"
161 163 >
162 164 <template #[item]="data" v-for="item in Object.keys($slots)">
... ...
... ... @@ -40,16 +40,19 @@
40 40 accept?: string;
41 41 maxSize?: number;
42 42 disabled?: boolean;
43   - listType?: string;
  43 + listType?: 'text' | 'picture-card' | 'picture';
44 44 multiple?: boolean;
45 45 maxFileLimit?: number;
46   - showUploadList?: boolean | { showPreviewIcon?: boolean; showRemoveIcon?: boolean };
  46 + showUploadList?: InstanceType<typeof Upload>['$props']['showUploadList'];
47 47 transformFile?: (file: File) => string | Blob | Promise<string | Blob | File>;
48 48 api: (file: string | Blob | Promise<string | Blob | File>) => Promise<FileItem>;
  49 + overFileLimitHiddenUploadEntry?: boolean;
49 50 }>(),
50 51 {
51 52 fileList: () => [],
52 53 maxSize: 5 * 1024 * 1024,
  54 + overFileLimitHiddenUploadEntry: true,
  55 + listType: 'text',
53 56 showUploadList: () => ({ showPreviewIcon: true, showRemoveIcon: true }),
54 57 }
55 58 );
... ... @@ -75,7 +78,7 @@
75 78
76 79 const getMaxFileLimit = computed(() => {
77 80 const { maxFileLimit } = props;
78   - return isPictureCard.value ? 1 : maxFileLimit;
  81 + return isPictureCard.value ? 1 : maxFileLimit || 1;
79 82 });
80 83
81 84 const handleUpload = async (file: File | string | Blob | Promise<string | Blob | File>) => {
... ... @@ -131,11 +134,15 @@
131 134 :list-type="props.listType"
132 135 :disabled="getDisabled"
133 136 :before-upload="handleBeforeUpload"
  137 + :show-upload-list="showUploadList"
134 138 @preview="handlePreview"
135 139 @download="handleDownload"
136 140 :remove="handleRemove"
137 141 >
138   - <Spin v-if="!fileList.length" :spinning="loading">
  142 + <Spin
  143 + v-if="!(fileList.length >= getMaxFileLimit) || overFileLimitHiddenUploadEntry"
  144 + :spinning="loading"
  145 + >
139 146 <div class="w-full h-full flex flex-col justify-center content-center">
140 147 <Tooltip title="点击上传或拖拽上传">
141 148 <InboxOutlined class="text-[3rem] !text-blue-500" />
... ...
... ... @@ -135,4 +135,6 @@ export type ComponentType =
135 135 | 'JavascriptEditorWithTestModal'
136 136 | 'AttributeConfiguration'
137 137 | 'CorrelationFilters'
138   - | 'RelationsQuery';
  138 + | 'RelationsQuery'
  139 + | 'CredentialsCard'
  140 + | 'ApiComplete';
... ...
... ... @@ -241,3 +241,95 @@ export enum ScopeNameEnum {
241 241 CLIENT_SCOPE = '客户端属性',
242 242 SHARED_SCOPE = '共享属性',
243 243 }
  244 +
  245 +// External Queue type
  246 +export enum QueueTypeEnum {
  247 + STANDARD = 'STANDARD',
  248 + FIFO = 'FIFO',
  249 +}
  250 +
  251 +export enum QueueTypeNameEnum {
  252 + STANDARD = 'Standard',
  253 + FIFO = 'FIFO',
  254 +}
  255 +
  256 +// Charset encoding
  257 +export enum CharsetEncodingEnum {
  258 + US_ASCII = 'US_ASCII',
  259 + ISO_8859_1 = 'ISO_8859_1',
  260 + UTF_8 = 'UTF_8',
  261 + UTF_16BE = 'UTF_16BE',
  262 + UTF_16LE = 'UTF_16LE',
  263 + UTF_16 = 'UTF_16',
  264 +}
  265 +
  266 +export enum CharsetEncodingNameEnum {
  267 + US_ASCII = 'US-ASCII',
  268 + ISO_8859_1 = 'ISO-8859-1',
  269 + UTF_8 = 'UTF-8',
  270 + UTF_16BE = 'UTF-16BE',
  271 + UTF_16LE = 'UTF-16LE',
  272 + UTF_16 = 'UTF-16',
  273 +}
  274 +
  275 +// Rabbitmq Message properties
  276 +export enum MessagePropertiesEnum {
  277 + BASIC = 'BASIC',
  278 + TEXT_PLAIN = 'TEXT_PLAIN',
  279 + MINIMAL_BASIC = 'MINIMAL_BASIC',
  280 + MINIMAL_PERSISTENT_BASIC = 'MINIMAL_PERSISTENT_BASIC',
  281 + PERSISTENT_BASIC = 'PERSISTENT_BASIC',
  282 + PERSISTENT_TEXT_PLAIN = 'PERSISTENT_TEXT_PLAIN',
  283 +}
  284 +
  285 +// rest api call Request method
  286 +export enum RequestMethodEnum {
  287 + GET = 'GET',
  288 + POST = 'POST',
  289 + PUT = 'PUT',
  290 + DELETE = 'DELETE',
  291 +}
  292 +
  293 +export enum ProtocolEnum {
  294 + HTTP = 'HTTP',
  295 + HTTPS = 'HTTPS',
  296 +}
  297 +
  298 +export enum ProtocolNameEnum {
  299 + HTTP = 'http',
  300 + HTTPS = 'https',
  301 +}
  302 +
  303 +export enum EmailProtocolEnum {
  304 + SMTP = 'SMTP',
  305 + SMTPS = 'SMTPS',
  306 +}
  307 +
  308 +export enum EmailProtocolNameEnum {
  309 + SMTP = 'smtp',
  310 + SMTPS = 'smtps',
  311 +}
  312 +
  313 +export enum TSLVersionEnum {
  314 + TSLV1 = 'TSLV1',
  315 + TSLV1_1 = 'TSLV1_1',
  316 + TSLV1_2 = 'TSLV1_2',
  317 + TSLV1_3 = 'TSLV1_3',
  318 +}
  319 +
  320 +export enum TSLVersionNameEnum {
  321 + TSLV1 = 'TSLV1',
  322 + TSLV1_1 = 'TSLV1.1',
  323 + TSLV1_2 = 'TSLV1.2',
  324 + TSLV1_3 = 'TSLV1.3',
  325 +}
  326 +
  327 +export enum SMSServiceProviderEnum {
  328 + AWS_SNS = 'AWS_SNS',
  329 + TWILIO = 'TWILIO',
  330 +}
  331 +
  332 +export enum SMSServiceProviderNameEnum {
  333 + AWS_SNS = '亚马逊社交网站',
  334 + TWILIO = 'Twilio',
  335 +}
... ...
  1 +// Alarm notice
  2 +export enum AlarmNoticeFieldsEnum {
  3 + CONFIGURATION = 'CONFIGURATION',
  4 +}
  5 +
  6 +export enum AlarmNoticeFieldsNameEnum {
  7 + CONFIGURATION = '配置',
  8 +}
  9 +
  10 +// aws sns
  11 +export enum AwsSnsFieldsEnum {
  12 + TOPIC_ARN_PATTERN = 'topicArnPattern',
  13 + ACCESS_KEY_ID = 'accessKeyId',
  14 + SECRET_ACCESS_KEY = 'secretAccessKey',
  15 + REGION = 'region',
  16 +}
  17 +
  18 +export enum AwsSnsFieldsNameEnum {
  19 + TOPIC_ARN_PATTERN = 'Topic ARN pattern',
  20 + ACCESS_KEY_ID = 'AWS Access Key ID',
  21 + SECRET_ACCESS_KEY = 'AWS Secret Access Key',
  22 + REGION = 'AWS Region',
  23 +}
  24 +
  25 +// Aws sqs
  26 +export enum AwsSqsFieldsEnum {
  27 + QUEUE_TYPE = 'queueType',
  28 + QUEUE_URL_PATTERN = 'queueUrlPattern',
  29 + DELAY_SECONDS = 'delaySeconds',
  30 + MESSAGE_ATTRIBUTES = 'messageAttributes',
  31 + ACCESS_KEY_ID = 'accessKeyId',
  32 + SECRET_ACCESS_KEY = 'secretAccessKey',
  33 + REGION = 'region',
  34 +}
  35 +
  36 +export enum AwsSqsFieldsNameEnum {
  37 + QUEUE_TYPE = 'Queue type',
  38 + QUEUE_URL_PATTERN = 'Queue URL pattern',
  39 + DELAY_SECONDS = 'Delay(seconds)',
  40 + MESSAGE_ATTRIBUTES = 'Message attributes',
  41 + ACCESS_KEY_ID = 'AWS Access Key ID',
  42 + SECRET_ACCESS_KEY = 'AWS Secret Access Key',
  43 + REGION = 'AWS Region',
  44 +}
  45 +
  46 +// Azure iot hub
  47 +export enum AzureIotHubFieldsEnum {
  48 + TOPIC_PATTERN = 'topicPattern',
  49 + HOST = 'host',
  50 + PORT = 'port',
  51 + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec',
  52 + CLIENT_ID = 'clientId',
  53 + CLEAN_SESSION = 'cleanSession',
  54 + SSL = 'ssl',
  55 + CREDENTIALS = 'credentials',
  56 +
  57 + TYPE = 'type',
  58 + SAS_KEY = 'sasKey',
  59 + CA_CERT = 'caCert',
  60 + CA_CERT_FILE_NAME = 'caCertFileName',
  61 + PRIVATE_KEY = 'privateKey',
  62 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  63 + CERT = 'cert',
  64 + CERT_FILE_NAME = 'certFileName',
  65 + PASSWORD = 'password',
  66 +}
  67 +
  68 +export enum AzureIotHubFieldsNameEnum {
  69 + TOPIC_PATTERN = 'Topic',
  70 + HOST = 'Hostname',
  71 + PORT = 'port',
  72 + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec',
  73 + CLIENT_ID = 'Device ID',
  74 + CLEAN_SESSION = 'cleanSession',
  75 + SSL = 'ssl',
  76 + CREDENTIALS = 'credentials',
  77 +
  78 + TYPE = 'Credentials type',
  79 + SAS_KEY = 'sasKey',
  80 + CA_CERT = 'CA certificate file',
  81 + CA_CERT_FILE_NAME = 'caCertFileName',
  82 + PRIVATE_KEY = 'Client private key file',
  83 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  84 + CERT = 'Client certificate file',
  85 + CERT_FILE_NAME = 'certFileName',
  86 + PASSWORD = 'Private key password',
  87 +}
  88 +
  89 +// GCP pubsub
  90 +export enum GcpPubsubFieldsEnum {
  91 + PROJECT_ID = 'projectId',
  92 + TOPIC_NAME = 'topicName',
  93 + SERVICE_ACCOUNT_KEY = 'serviceAccountKey',
  94 + SERVICE_ACCOUNT_KEY_FILE_NAME = 'serviceAccountKeyFileName',
  95 + MESSAGE_ATTRIBUTES = 'messageAttributes',
  96 +}
  97 +
  98 +export enum GcpPubsubFieldsNameEnum {
  99 + PROJECT_ID = 'GCP project ID',
  100 + TOPIC_NAME = 'Topic name',
  101 + SERVICE_ACCOUNT_KEY = 'GCP service account key file',
  102 + SERVICE_ACCOUNT_KEY_FILE_NAME = 'serviceAccountKeyFileName',
  103 + MESSAGE_ATTRIBUTES = 'Message attributes',
  104 +}
  105 +
  106 +// Kafka
  107 +export enum KafkaFieldsEnum {
  108 + TOPIC_PATTERN = 'topicPattern',
  109 + BOOTSTRAP_SERVERS = 'bootstrapServers',
  110 + RETRIES = 'retries',
  111 + BATCH_SIZE = 'batchSize',
  112 + LINGER = 'linger',
  113 + BUFFER_MEMORY = 'bufferMemory',
  114 + ACKS = 'acks',
  115 + KEY_SERIALIZER = 'keySerializer',
  116 + VALUE_SERIALIZER = 'valueSerializer',
  117 + OTHER_PROPERTIES = 'otherProperties',
  118 + ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS = 'addMetadataKeyValuesAsKafkaHeaders',
  119 + KAFKA_HEADERS_CHARSET = 'kafkaHeadersCharset',
  120 +}
  121 +
  122 +export enum KafkaFieldsNameEnum {
  123 + TOPIC_PATTERN = 'Topic pattern',
  124 + BOOTSTRAP_SERVERS = 'Bootstrap servers',
  125 + RETRIES = 'Automatically retry times if fails',
  126 + BATCH_SIZE = 'Produces batch size in bytes',
  127 + LINGER = 'Time to buffer locally(ms)',
  128 + BUFFER_MEMORY = 'Client buffer max size in bytes',
  129 + ACKS = 'Number of acknowledgments',
  130 + KEY_SERIALIZER = 'Key serializer',
  131 + VALUE_SERIALIZER = 'Value serializer',
  132 + OTHER_PROPERTIES = 'Other properties',
  133 + ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS = 'Add Message metadata key-value pairs to Kafka record headers',
  134 + KAFKA_HEADERS_CHARSET = 'Charset encoding',
  135 +}
  136 +
  137 +// Mqtt
  138 +export enum MqttFieldsEnum {
  139 + TOPIC_PATTERN = 'topicPattern',
  140 + HOST = 'host',
  141 + PORT = 'port',
  142 + CONNECT_TIMEOUT_SEC = 'connectTimeoutSec',
  143 + CLIENT_ID = 'clientId',
  144 + APPEND_CLIENT_ID_SUFFIX = 'appendClientIdSuffix',
  145 + CLEAN_SESSION = 'cleanSession',
  146 + SSL = 'ssl',
  147 + CREDENTIALS = 'credentials',
  148 +
  149 + TYPE = 'type',
  150 + PASSWORD = 'password',
  151 + CA_CERT = 'caCert',
  152 + CA_CERT_FILE_NAME = 'caCertFileName',
  153 + PRIVATE_KEY = 'privateKey',
  154 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  155 + CERT = 'cert',
  156 + CERT_FILE_NAME = 'certFileName',
  157 + USERNAME = 'username',
  158 +}
  159 +
  160 +export enum MqttFieldsNameEnum {
  161 + TOPIC_PATTERN = 'Topic pattern',
  162 + HOST = 'Hose',
  163 + PORT = 'Port',
  164 + CONNECT_TIMEOUT_SEC = 'Connection timeout(sec)',
  165 + CLIENT_ID = 'Client ID',
  166 + APPEND_CLIENT_ID_SUFFIX = 'Add Service ID as suffix to Client ID',
  167 + CLEAN_SESSION = 'Clean session',
  168 + SSL = 'Enable SSL',
  169 + CREDENTIALS = 'credentials',
  170 +
  171 + TYPE = 'Credentials type',
  172 + PASSWORD = 'Password',
  173 + CA_CERT = 'Server CA certificate file',
  174 + CA_CERT_FILE_NAME = 'caCertFileName',
  175 + PRIVATE_KEY = 'Client private key file',
  176 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  177 + CERT = 'Client certificate file',
  178 + CERT_FILE_NAME = 'certFileName',
  179 + USERNAME = 'Username',
  180 +}
  181 +
  182 +// Rabbitmq
  183 +export enum RabbitmqFieldsEnum {
  184 + EXCHANGE_NAME_PATTERN = 'exchangeNamePattern',
  185 + ROUTING_KEY_PATTERN = 'routingKeyPattern',
  186 + MESSAGE_PROPERTIES = 'messageProperties',
  187 + HOST = 'host',
  188 + PORT = 'port',
  189 + VIRTUAL_HOST = 'virtualHost',
  190 + USERNAME = 'username',
  191 + PASSWORD = 'password',
  192 + AUTOMATIC_RECOVERY_ENABLED = 'automaticRecoveryEnabled',
  193 + CONNECTION_TIMEOUT = 'connectionTimeout',
  194 + HANDSHAKE_TIMEOUT = 'handshakeTimeout',
  195 + CLIENT_PROPERTIES = 'clientProperties',
  196 +}
  197 +
  198 +export enum RabbitmqFieldsNameEnum {
  199 + EXCHANGE_NAME_PATTERN = 'Exchange name pattern',
  200 + ROUTING_KEY_PATTERN = 'Routing key pattern',
  201 + MESSAGE_PROPERTIES = 'Message properties',
  202 + HOST = 'Host',
  203 + PORT = 'Port',
  204 + VIRTUAL_HOST = 'Virtual host',
  205 + USERNAME = 'Username',
  206 + PASSWORD = 'Password',
  207 + AUTOMATIC_RECOVERY_ENABLED = 'Automatic recovery',
  208 + CONNECTION_TIMEOUT = 'Connection timeout(ms)',
  209 + HANDSHAKE_TIMEOUT = 'Handshake timeout(ms)',
  210 + CLIENT_PROPERTIES = 'Client properties',
  211 +}
  212 +
  213 +// Rest api call
  214 +export enum RestApiCallFieldsEnum {
  215 + REST_ENDPOINT_URL_PATTERN = 'restEndpointUrlPattern',
  216 + REQUEST_METHOD = 'requestMethod',
  217 + USE_SIMPLE_CLIENT_HTTP_FACTORY = 'useSimpleClientHttpFactory',
  218 + IGNORE_REQUEST_BODY = 'ignoreRequestBody',
  219 + ENABLE_PROXY = 'enableProxy',
  220 + USE_SYSTEM_PROXY_PROPERTIES = 'useSystemProxyProperties',
  221 + PROXY_SCHEME = 'proxyScheme',
  222 + PROXY_HOST = 'proxyHost',
  223 + PROXY_PORT = 'proxyPort',
  224 + PROXY_USER = 'proxyUser',
  225 + PROXY_PASSWORD = 'proxyPassword',
  226 + READ_TIMEOUT_MS = 'readTimeoutMs',
  227 + MAX_PARALLEL_REQUESTS_COUNT = 'maxParallelRequestsCount',
  228 + HEADERS = 'headers',
  229 + USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE = 'useRedisQueueForMsgPersistence',
  230 + TRIM_QUEUE = 'trimQueue',
  231 + MAX_QUEUE_SIZE = 'maxQueueSize',
  232 + CREDENTIALS = 'credentials',
  233 +
  234 + TYPE = 'type',
  235 + PASSWORD = 'password',
  236 + CA_CERT = 'caCert',
  237 + CA_CERT_FILE_NAME = 'caCertFileName',
  238 + PRIVATE_KEY = 'privateKey',
  239 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  240 + CERT = 'cert',
  241 + CERT_FILE_NAME = 'certFileName',
  242 + USERNAME = 'username',
  243 +}
  244 +
  245 +export enum RestApiCallFieldsNameEnum {
  246 + REST_ENDPOINT_URL_PATTERN = 'Endpoint URL pattern',
  247 + REQUEST_METHOD = 'requestMethod',
  248 + USE_SIMPLE_CLIENT_HTTP_FACTORY = 'useSimpleClientHttpFactory',
  249 + IGNORE_REQUEST_BODY = 'ignoreRequestBody',
  250 + ENABLE_PROXY = 'enableProxy',
  251 + USE_SYSTEM_PROXY_PROPERTIES = 'useSystemProxyProperties',
  252 + PROXY_SCHEME = 'proxyScheme',
  253 + PROXY_HOST = 'proxyHost',
  254 + PROXY_PORT = 'proxyPort',
  255 + PROXY_USER = 'proxyUser',
  256 + PROXY_PASSWORD = 'proxyPassword',
  257 + READ_TIMEOUT_MS = 'readTimeoutMs',
  258 + MAX_PARALLEL_REQUESTS_COUNT = 'maxParallelRequestsCount',
  259 + HEADERS = 'headers',
  260 + USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE = 'useRedisQueueForMsgPersistence',
  261 + TRIM_QUEUE = 'trimQueue',
  262 + MAX_QUEUE_SIZE = 'maxQueueSize',
  263 + CREDENTIALS = 'credentials',
  264 +
  265 + TYPE = 'Credentials type',
  266 + PASSWORD = 'Password',
  267 + CA_CERT = 'Server CA certificate file',
  268 + CA_CERT_FILE_NAME = 'caCertFileName',
  269 + PRIVATE_KEY = 'Client private key file',
  270 + PRIVATE_KEY_FILE_NAME = 'privateKeyFileName',
  271 + CERT = 'Client certificate file',
  272 + CERT_FILE_NAME = 'certFileName',
  273 + USERNAME = 'Username',
  274 +}
  275 +
  276 +// send email
  277 +export enum SendEmailFieldsEnum {
  278 + USE_SYSTEM_SMTP_SETTINGS = 'useSystemSmtpSettings',
  279 + SMTP_PROTOCOL = 'smtpProtocol',
  280 + SMTP_HOST = 'smtpHost',
  281 + SMTP_PORT = 'smtpPort',
  282 + TIMEOUT = 'timeout',
  283 + ENABLE_TLS = 'enableTls',
  284 + TLS_VERSION = 'tlsVersion',
  285 + ENABLE_PROXY = 'enableProxy',
  286 + PROXY_HOST = 'proxyHost',
  287 + PROXY_PORT = 'proxyPort',
  288 + PROXY_USER = 'proxyUser',
  289 + PROXY_PASSWORD = 'proxyPassword',
  290 + USERNAME = 'username',
  291 + PASSWORD = 'password',
  292 +}
  293 +
  294 +export enum SendEmailFieldsNameEnum {
  295 + USE_SYSTEM_SMTP_SETTINGS = 'Use system SMTP settings',
  296 + SMTP_PROTOCOL = 'Protocol',
  297 + SMTP_HOST = 'SMTP host',
  298 + SMTP_PORT = 'SMTP port',
  299 + TIMEOUT = 'Timeout ms',
  300 + ENABLE_TLS = 'Enable TLS',
  301 + TLS_VERSION = 'TLS version',
  302 + ENABLE_PROXY = 'Enable proxy',
  303 + PROXY_HOST = 'Proxy host',
  304 + PROXY_PORT = 'Proxy port',
  305 + PROXY_USER = 'Proxy user',
  306 + PROXY_PASSWORD = 'Proxy password',
  307 + USERNAME = 'Username',
  308 + PASSWORD = 'Password',
  309 +}
  310 +
  311 +export enum SendSMSFieldsEnum {
  312 + NUMBERS_TO_TEMPLATE = 'numbersToTemplate',
  313 + SMS_MESSAGE_TEMPLATE = 'smsMessageTemplate',
  314 + USE_SYSTEM_SMS_SETTINGS = 'useSystemSmsSettings',
  315 + SMS_PROVIDER_CONFIGURATION = 'smsProviderConfiguration',
  316 +
  317 + ACCESS_KEY_ID = 'accessKeyId',
  318 + SECRET_ACCESS_KEY = 'secretAccessKey',
  319 + REGION = 'region',
  320 + TYPE = 'type',
  321 + NUMBER_FROM = 'numberFrom',
  322 + ACCOUNT_SID = 'accountSid',
  323 + ACCOUNT_TOKEN = 'accountToken',
  324 +}
  325 +
  326 +export enum SendSMSFieldsNameEnum {
  327 + NUMBERS_TO_TEMPLATE = 'Phone Numbers To Template',
  328 + SMS_MESSAGE_TEMPLATE = 'SMS message Template',
  329 + USE_SYSTEM_SMS_SETTINGS = 'User system SMS provider settings',
  330 + SMS_PROVIDER_CONFIGURATION = 'smsProviderConfiguration',
  331 +
  332 + ACCESS_KEY_ID = 'AWS访问密钥ID',
  333 + SECRET_ACCESS_KEY = 'AWS访问密钥',
  334 + REGION = 'AWS地区',
  335 + TYPE = 'SMS服务商类型',
  336 + NUMBER_FROM = '发送方电话号码',
  337 + ACCOUNT_SID = 'Twilio账户SID',
  338 + ACCOUNT_TOKEN = 'Twilio账户令牌',
  339 +}
... ...
  1 +export enum CheckPointFieldsEnum {
  2 + QUEUE_NAME = 'queueName',
  3 +}
  4 +
  5 +export enum CheckPointFieldsNameEnum {
  6 + QUEUE_NAME = '队列名称',
  7 +}
  8 +
  9 +export enum RuleChainFieldsEnum {
  10 + RULE_CHAIN_ID = 'ruleChainId',
  11 +}
  12 +
  13 +export enum RuleChainFieldsNameEnum {
  14 + RULE_CHAIN_ID = '规则链',
  15 +}
... ...
... ... @@ -9,6 +9,7 @@ export const InputConfig: NodeItemConfigType = {
9 9 ...keys,
10 10 categoryType: RuleNodeTypeEnum.ENTRY,
11 11 clazz: EntryCategoryComponentEnum.INPUT,
  12 + disableAction: true,
12 13 maxConnectionPoint: 1,
13 14 backgroundColor: '#95E898',
14 15 configurationDescriptor: {
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { AlarmNoticeFieldsEnum, AlarmNoticeFieldsNameEnum } from '../../../enum/formField/external';
2 2 import { FormSchema } from '/@/components/Form';
3 3
4 4 export const formSchemas: FormSchema[] = [
5 5 {
6   - field: NodeBindDataFieldEnum.NAME,
7   - component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  6 + field: AlarmNoticeFieldsEnum.CONFIGURATION,
  7 + component: 'JSONEditor',
  8 + label: AlarmNoticeFieldsNameEnum.CONFIGURATION,
  9 + valueField: 'value',
  10 + changeEvent: 'update:value',
9 11 },
10 12 ];
... ...
... ... @@ -3,6 +3,8 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { useJsonParse } from '/@/hooks/business/useJsonParse';
  7 + import { AlarmNoticeFieldsEnum } from '../../../enum/formField/external';
6 8
7 9 defineProps<{
8 10 config: NodeData;
... ... @@ -16,12 +18,12 @@
16 18 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 19 await validate();
18 20 const value = getFieldsValue() || {};
19   - return value;
  21 + return useJsonParse(value?.[AlarmNoticeFieldsEnum.CONFIGURATION]).value || {};
20 22 };
21 23
22 24 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 25 resetFields();
24   - setFieldsValue(value);
  26 + setFieldsValue({ [AlarmNoticeFieldsEnum.CONFIGURATION]: JSON.stringify(value, null, 2) });
25 27 };
26 28
27 29 defineExpose({
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { AwsSnsFieldsEnum, AwsSnsFieldsNameEnum } from '../../../enum/formField/external';
2 2 import { FormSchema } from '/@/components/Form';
3 3
4 4 export const formSchemas: FormSchema[] = [
5 5 {
6   - field: NodeBindDataFieldEnum.NAME,
  6 + field: AwsSnsFieldsEnum.TOPIC_ARN_PATTERN,
  7 + label: AwsSnsFieldsNameEnum.TOPIC_ARN_PATTERN,
7 8 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  9 + required: true,
  10 + componentProps: {
  11 + placeholder: `请输入${AwsSnsFieldsNameEnum.TOPIC_ARN_PATTERN}`,
  12 + },
  13 + },
  14 + {
  15 + field: AwsSnsFieldsEnum.ACCESS_KEY_ID,
  16 + label: AwsSnsFieldsNameEnum.ACCESS_KEY_ID,
  17 + component: 'Input',
  18 + required: true,
  19 + componentProps: {
  20 + placeholder: `请输入${AwsSnsFieldsNameEnum.ACCESS_KEY_ID}`,
  21 + },
  22 + },
  23 + {
  24 + field: AwsSnsFieldsEnum.SECRET_ACCESS_KEY,
  25 + label: AwsSnsFieldsNameEnum.SECRET_ACCESS_KEY,
  26 + component: 'Input',
  27 + required: true,
  28 + componentProps: {
  29 + placeholder: `请输入${AwsSnsFieldsNameEnum.SECRET_ACCESS_KEY}`,
  30 + },
  31 + },
  32 + {
  33 + field: AwsSnsFieldsEnum.REGION,
  34 + label: AwsSnsFieldsNameEnum.REGION,
  35 + component: 'Input',
  36 + required: true,
  37 + componentProps: {
  38 + placeholder: `请输入${AwsSnsFieldsNameEnum.REGION}`,
  39 + },
9 40 },
10 41 ];
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { QueueTypeEnum, QueueTypeNameEnum } from '../../../enum/form';
  2 +import { AwsSqsFieldsEnum, AwsSqsFieldsNameEnum } from '../../../enum/formField/external';
  3 +import { AttributeConfiguration } from '../../../src/components/AttributeConfiguration';
  4 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  5 +
  6 +useComponentRegister('AttributeConfiguration', AttributeConfiguration);
3 7
4 8 export const formSchemas: FormSchema[] = [
5 9 {
6   - field: NodeBindDataFieldEnum.NAME,
  10 + field: AwsSqsFieldsEnum.QUEUE_TYPE,
  11 + label: AwsSqsFieldsNameEnum.QUEUE_TYPE,
  12 + component: 'Select',
  13 + required: true,
  14 + componentProps: {
  15 + options: Object.keys(QueueTypeEnum).map((value) => ({
  16 + label: QueueTypeNameEnum[value],
  17 + value,
  18 + })),
  19 + getPopupContainer: () => document.body,
  20 + placeholder: `请选择${AwsSqsFieldsNameEnum.QUEUE_TYPE}`,
  21 + },
  22 + },
  23 + {
  24 + field: AwsSqsFieldsEnum.QUEUE_URL_PATTERN,
  25 + label: AwsSqsFieldsNameEnum.QUEUE_URL_PATTERN,
  26 + component: 'Input',
  27 + required: true,
  28 + componentProps: {
  29 + placeholder: `请输入${AwsSqsFieldsNameEnum.QUEUE_URL_PATTERN}`,
  30 + },
  31 + },
  32 + {
  33 + field: AwsSqsFieldsEnum.DELAY_SECONDS,
  34 + label: AwsSqsFieldsNameEnum.DELAY_SECONDS,
  35 + component: 'Input',
  36 + required: true,
  37 + helpMessage: [
  38 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  39 + ],
  40 + show: ({ model }) => model[AwsSqsFieldsEnum.QUEUE_TYPE] === QueueTypeEnum.STANDARD,
  41 + componentProps: {
  42 + placeholder: `请输入${AwsSqsFieldsNameEnum.DELAY_SECONDS}`,
  43 + },
  44 + },
  45 + {
  46 + field: AwsSqsFieldsEnum.MESSAGE_ATTRIBUTES,
  47 + label: AwsSqsFieldsNameEnum.MESSAGE_ATTRIBUTES,
  48 + component: 'AttributeConfiguration',
  49 + helpMessage:
  50 + 'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',
  51 + slot: AwsSqsFieldsEnum.MESSAGE_ATTRIBUTES,
  52 + },
  53 + {
  54 + field: AwsSqsFieldsEnum.ACCESS_KEY_ID,
  55 + label: AwsSqsFieldsNameEnum.ACCESS_KEY_ID,
  56 + component: 'Input',
  57 + required: true,
  58 + componentProps: {
  59 + placeholder: `请输入${AwsSqsFieldsNameEnum.ACCESS_KEY_ID}`,
  60 + },
  61 + },
  62 + {
  63 + field: AwsSqsFieldsEnum.SECRET_ACCESS_KEY,
  64 + label: AwsSqsFieldsNameEnum.SECRET_ACCESS_KEY,
  65 + component: 'Input',
  66 + required: true,
  67 + componentProps: {
  68 + placeholder: `请输入${AwsSqsFieldsNameEnum.SECRET_ACCESS_KEY}`,
  69 + },
  70 + },
  71 + {
  72 + field: AwsSqsFieldsEnum.REGION,
  73 + label: AwsSqsFieldsNameEnum.REGION,
7 74 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  75 + required: true,
  76 + componentProps: {
  77 + placeholder: `请输入${AwsSqsFieldsNameEnum.REGION}`,
  78 + },
9 79 },
10 80 ];
... ...
... ... @@ -3,11 +3,16 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { AttributeConfiguration } from '../../../src/components/AttributeConfiguration';
  7 + import { ref, unref } from 'vue';
  8 + import { AwsSqsFieldsEnum } from '../../../enum/formField/external';
6 9
7 10 defineProps<{
8 11 config: NodeData;
9 12 }>();
10 13
  14 + const attributeConfigurationElRef = ref<Nullable<InstanceType<typeof AttributeConfiguration>>>();
  15 +
11 16 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 17 schemas: formSchemas,
13 18 showActionButtonGroup: false,
... ... @@ -15,13 +20,18 @@
15 20
16 21 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 22 await validate();
  23 + await unref(attributeConfigurationElRef)?.validate();
18 24 const value = getFieldsValue() || {};
19   - return value;
  25 + const messageFields = unref(attributeConfigurationElRef)?.getFieldsValue();
  26 + return { ...value, [AwsSqsFieldsEnum.MESSAGE_ATTRIBUTES]: messageFields };
20 27 };
21 28
22 29 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 30 resetFields();
24 31 setFieldsValue(value);
  32 + unref(attributeConfigurationElRef)?.setFieldsValue(
  33 + value?.[AwsSqsFieldsEnum.MESSAGE_ATTRIBUTES]
  34 + );
25 35 };
26 36
27 37 defineExpose({
... ... @@ -31,5 +41,15 @@
31 41 </script>
32 42
33 43 <template>
34   - <BasicForm @register="register" />
  44 + <BasicForm @register="register">
  45 + <template #messageAttributes="{ field, model }">
  46 + <AttributeConfiguration
  47 + ref="attributeConfigurationElRef"
  48 + v-model:value="model[field]"
  49 + keyLabel="Name"
  50 + valueLabel="Value"
  51 + :allowEmpty="true"
  52 + />
  53 + </template>
  54 + </BasicForm>
35 55 </template>
... ...
  1 +import {
  2 + AzureIotHubFieldsEnum,
  3 + AzureIotHubFieldsNameEnum,
  4 +} from '../../../../enum/formField/external';
  5 +import { FormSchema } from '/@/components/Form';
  6 +
  7 +export enum CredentialsTypeEnum {
  8 + PEM = 'cert.PEM',
  9 + SHARED_ACCESS_SIGNATURE = 'sas',
  10 +}
  11 +
  12 +export enum CredentialsTypeNameEnum {
  13 + PEM = 'PEM',
  14 + SHARED_ACCESS_SIGNATURE = 'Shared Access Signature',
  15 +}
  16 +
  17 +export interface FileItemType {
  18 + uid: string;
  19 + name: string;
  20 + data?: any;
  21 +}
  22 +
  23 +export const getFileData = async (file: FileItemType) => {
  24 + return new Promise((resolve) => {
  25 + const fileReader = new FileReader();
  26 + fileReader.readAsText(file as unknown as File);
  27 + fileReader.onload = () => {
  28 + if (fileReader.DONE === fileReader.readyState) {
  29 + resolve({
  30 + uid: file.uid,
  31 + name: file.name,
  32 + data: fileReader.result,
  33 + });
  34 + }
  35 + };
  36 + });
  37 +};
  38 +
  39 +export const credentialsTypeOptions = [
  40 + {
  41 + label: CredentialsTypeNameEnum.SHARED_ACCESS_SIGNATURE,
  42 + value: CredentialsTypeEnum.SHARED_ACCESS_SIGNATURE,
  43 + },
  44 + { label: CredentialsTypeNameEnum.PEM, value: CredentialsTypeEnum.PEM },
  45 +];
  46 +
  47 +export const formSchemas = (
  48 + setType: (
  49 + value: CredentialsTypeEnum,
  50 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  51 + ) => void
  52 +): FormSchema[] => {
  53 + return [
  54 + {
  55 + field: AzureIotHubFieldsEnum.TYPE,
  56 + label: AzureIotHubFieldsNameEnum.TYPE,
  57 + component: 'Select',
  58 + required: true,
  59 + defaultValue: CredentialsTypeEnum.SHARED_ACCESS_SIGNATURE,
  60 + componentProps: ({ formActionType }) => {
  61 + const { setFieldsValue } = formActionType;
  62 + return {
  63 + options: credentialsTypeOptions,
  64 + placeholder: `请选择${AzureIotHubFieldsNameEnum.TYPE}`,
  65 + getPopupContainer: () => document.body,
  66 + onChange(
  67 + value: CredentialsTypeEnum,
  68 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  69 + ) {
  70 + setType(value, option);
  71 + setFieldsValue({
  72 + [AzureIotHubFieldsEnum.CA_CERT]: [],
  73 + [AzureIotHubFieldsEnum.CA_CERT_FILE_NAME]: null,
  74 + [AzureIotHubFieldsEnum.CERT]: [],
  75 + [AzureIotHubFieldsEnum.CERT_FILE_NAME]: null,
  76 + [AzureIotHubFieldsEnum.PRIVATE_KEY]: [],
  77 + [AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME]: null,
  78 + [AzureIotHubFieldsEnum.PASSWORD]: null,
  79 + [AzureIotHubFieldsEnum.SAS_KEY]: null,
  80 + });
  81 + },
  82 + };
  83 + },
  84 + },
  85 + {
  86 + field: AzureIotHubFieldsEnum.SAS_KEY,
  87 + label: AzureIotHubFieldsNameEnum.SAS_KEY,
  88 + required: true,
  89 + component: 'Input',
  90 + ifShow: ({ model }) =>
  91 + model[AzureIotHubFieldsEnum.TYPE] === CredentialsTypeEnum.SHARED_ACCESS_SIGNATURE,
  92 + componentProps: {
  93 + placeholder: `请输入${AzureIotHubFieldsNameEnum.SAS_KEY}`,
  94 + },
  95 + },
  96 + {
  97 + field: AzureIotHubFieldsEnum.CA_CERT_FILE_NAME,
  98 + label: AzureIotHubFieldsNameEnum.CA_CERT_FILE_NAME,
  99 + component: 'InputPassword',
  100 + show: false,
  101 + },
  102 + {
  103 + field: AzureIotHubFieldsEnum.CA_CERT,
  104 + label: AzureIotHubFieldsNameEnum.CA_CERT,
  105 + component: 'ApiUpload',
  106 + valueField: 'fileList',
  107 + changeEvent: 'update:fileList',
  108 + componentProps: ({ formActionType }) => {
  109 + const { setFieldsValue } = formActionType;
  110 + return {
  111 + overFileLimitHiddenUploadEntry: true,
  112 + api: getFileData,
  113 + 'onUpdate:fileList'(file: FileItemType[]) {
  114 + setFieldsValue({ [AzureIotHubFieldsEnum.CA_CERT_FILE_NAME]: file?.[0]?.name });
  115 + },
  116 + };
  117 + },
  118 + },
  119 + {
  120 + field: AzureIotHubFieldsEnum.CERT_FILE_NAME,
  121 + label: AzureIotHubFieldsNameEnum.CERT_FILE_NAME,
  122 + component: 'InputPassword',
  123 + show: false,
  124 + },
  125 + {
  126 + field: AzureIotHubFieldsEnum.CERT,
  127 + label: AzureIotHubFieldsNameEnum.CERT,
  128 + component: 'ApiUpload',
  129 + valueField: 'fileList',
  130 + changeEvent: 'update:fileList',
  131 + required: true,
  132 + ifShow: ({ model }) => model[AzureIotHubFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  133 + componentProps: ({ formActionType }) => {
  134 + const { setFieldsValue } = formActionType;
  135 + return {
  136 + overFileLimitHiddenUploadEntry: true,
  137 + api: getFileData,
  138 + 'onUpdate:fileList'(file: FileItemType[]) {
  139 + setFieldsValue({ [AzureIotHubFieldsEnum.CERT_FILE_NAME]: file?.[0]?.name });
  140 + },
  141 + };
  142 + },
  143 + },
  144 + {
  145 + field: AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME,
  146 + label: AzureIotHubFieldsNameEnum.PRIVATE_KEY_FILE_NAME,
  147 + component: 'InputPassword',
  148 + show: false,
  149 + },
  150 + {
  151 + field: AzureIotHubFieldsEnum.PRIVATE_KEY,
  152 + label: AzureIotHubFieldsNameEnum.PRIVATE_KEY,
  153 + component: 'ApiUpload',
  154 + valueField: 'fileList',
  155 + changeEvent: 'update:fileList',
  156 + required: true,
  157 + ifShow: ({ model }) => model[AzureIotHubFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  158 + componentProps: ({ formActionType }) => {
  159 + const { setFieldsValue } = formActionType;
  160 + return {
  161 + overFileLimitHiddenUploadEntry: true,
  162 + api: getFileData,
  163 + 'onUpdate:fileList'(file: FileItemType[]) {
  164 + setFieldsValue({ [AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME]: file?.[0]?.name });
  165 + },
  166 + };
  167 + },
  168 + },
  169 + {
  170 + field: AzureIotHubFieldsEnum.PASSWORD,
  171 + label: AzureIotHubFieldsNameEnum.PASSWORD,
  172 + component: 'InputPassword',
  173 + ifShow: ({ model }) => model[AzureIotHubFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  174 + componentProps: {
  175 + placeholder: `请输入${AzureIotHubFieldsNameEnum.PASSWORD}`,
  176 + },
  177 + },
  178 + ];
  179 +};
... ...
  1 +export { default as CredentialsCard } from './index.vue';
... ...
  1 +<script setup lang="ts">
  2 + import { Collapse } from 'ant-design-vue';
  3 + import { BasicForm, useForm } from '/@/components/Form';
  4 + import { credentialsTypeOptions, FileItemType, formSchemas } from './config';
  5 + import { ref, watch } from 'vue';
  6 + import { buildUUID } from '/@/utils/uuid';
  7 + import { CredentialsTypeEnum, CredentialsTypeNameEnum } from '../../../../enum/form';
  8 + import { AzureIotHubFieldsEnum } from '../../../../enum/formField/external';
  9 +
  10 + const props = withDefaults(
  11 + defineProps<{
  12 + value?: Recordable;
  13 + }>(),
  14 + {
  15 + value: () => ({}),
  16 + }
  17 + );
  18 +
  19 + const activeKey = ref('credentials');
  20 +
  21 + const type = ref(CredentialsTypeNameEnum.SHARED_ACCESS_SIGNATURE);
  22 +
  23 + const [register, { getFieldsValue, setFieldsValue, validate }] = useForm({
  24 + schemas: formSchemas(setCredentialsType),
  25 + showActionButtonGroup: false,
  26 + layout: 'vertical',
  27 + });
  28 +
  29 + function setCredentialsType(
  30 + _value: CredentialsTypeEnum,
  31 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  32 + ) {
  33 + type.value = option.label;
  34 + }
  35 +
  36 + const getFileValue = (file: FileItemType[]) => {
  37 + return file?.[0]?.data || null;
  38 + };
  39 +
  40 + const setFileValueByKey = (
  41 + value: Recordable,
  42 + key: AzureIotHubFieldsEnum,
  43 + fileNameKey: AzureIotHubFieldsEnum
  44 + ) => {
  45 + return value[key]
  46 + ? [{ uid: buildUUID(), name: value[fileNameKey], data: value[key] } as FileItemType]
  47 + : [];
  48 + };
  49 +
  50 + const getValueByKey = (value: Recordable, key: AzureIotHubFieldsEnum) => {
  51 + return value?.[key] || null;
  52 + };
  53 +
  54 + const getValues = () => {
  55 + const value = getFieldsValue();
  56 + return {
  57 + [AzureIotHubFieldsEnum.CA_CERT]: getFileValue(value?.[AzureIotHubFieldsEnum.CA_CERT]),
  58 + [AzureIotHubFieldsEnum.CA_CERT_FILE_NAME]: getValueByKey(
  59 + value,
  60 + AzureIotHubFieldsEnum.CA_CERT_FILE_NAME
  61 + ),
  62 + [AzureIotHubFieldsEnum.CA_CERT]: getFileValue(value?.[AzureIotHubFieldsEnum.CERT]),
  63 + [AzureIotHubFieldsEnum.CERT_FILE_NAME]: getValueByKey(
  64 + value,
  65 + AzureIotHubFieldsEnum.CERT_FILE_NAME
  66 + ),
  67 + [AzureIotHubFieldsEnum.PRIVATE_KEY]: getFileValue(value?.[AzureIotHubFieldsEnum.PRIVATE_KEY]),
  68 + [AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME]: getValueByKey(
  69 + value,
  70 + AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME
  71 + ),
  72 + [AzureIotHubFieldsEnum.PASSWORD]: getValueByKey(value, AzureIotHubFieldsEnum.PASSWORD),
  73 + [AzureIotHubFieldsEnum.TYPE]: getValueByKey(value, AzureIotHubFieldsEnum.TYPE),
  74 + [AzureIotHubFieldsEnum.SAS_KEY]: getValueByKey(value, AzureIotHubFieldsEnum.SAS_KEY),
  75 + };
  76 + };
  77 +
  78 + const setValues = (value: Recordable) => {
  79 + const typeLabel = credentialsTypeOptions.find(
  80 + (item) => item.value === value?.[AzureIotHubFieldsEnum.TYPE]
  81 + )?.label;
  82 + type.value = typeLabel!;
  83 + setFieldsValue({
  84 + ...value,
  85 + [AzureIotHubFieldsEnum.CA_CERT]: setFileValueByKey(
  86 + value,
  87 + AzureIotHubFieldsEnum.CA_CERT,
  88 + AzureIotHubFieldsEnum.CA_CERT_FILE_NAME
  89 + ),
  90 + [AzureIotHubFieldsEnum.CERT]: setFileValueByKey(
  91 + value,
  92 + AzureIotHubFieldsEnum.CERT,
  93 + AzureIotHubFieldsEnum.CERT_FILE_NAME
  94 + ),
  95 + [AzureIotHubFieldsEnum.PRIVATE_KEY]: setFileValueByKey(
  96 + value,
  97 + AzureIotHubFieldsEnum.PRIVATE_KEY,
  98 + AzureIotHubFieldsEnum.PRIVATE_KEY_FILE_NAME
  99 + ),
  100 + });
  101 + };
  102 +
  103 + watch(
  104 + () => props.value,
  105 + (target) => {
  106 + setValues(target);
  107 + }
  108 + );
  109 +
  110 + defineExpose({
  111 + validate,
  112 + getFieldsValue: getValues,
  113 + setFieldsValue: setValues,
  114 + });
  115 +</script>
  116 +
  117 +<template>
  118 + <Collapse v-model:active-key="activeKey" class="credentials-card" expand-icon-position="right">
  119 + <Collapse.Panel :key="activeKey" class="box-shadow bg-light-50 shadow-2xl">
  120 + <template #header>
  121 + <section class="flex w-full h-full h-8 justify-between items-center">
  122 + <div class="w-1/2 text-left">Credentials</div>
  123 + <div class="w-1/2 text-left font-medium text-gray-400">
  124 + {{ type }}
  125 + </div>
  126 + </section>
  127 + </template>
  128 + <BasicForm @register="register" />
  129 + </Collapse.Panel>
  130 + </Collapse>
  131 +</template>
  132 +
  133 +<style lang="less" scoped>
  134 + .credentials-card {
  135 + :deep(.ant-collapse) {
  136 + &-header {
  137 + @apply !px-6;
  138 + }
  139 +
  140 + &-content {
  141 + &-box {
  142 + @apply px-6;
  143 + }
  144 + }
  145 + }
  146 +
  147 + :deep(.ant-form) {
  148 + > .ant-row {
  149 + > .ant-col {
  150 + > .ant-row {
  151 + > .ant-col {
  152 + min-height: fit-content;
  153 + }
  154 + }
  155 + }
  156 + }
  157 + }
  158 + }
  159 +
  160 + .box-shadow {
  161 + box-shadow: 0 3px 1px -2px #0003, 0 2px 2px 0 #00000024, 0 1px 5px 0 #0000001f;
  162 + }
  163 +</style>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { AzureIotHubFieldsEnum, AzureIotHubFieldsNameEnum } from '../../../enum/formField/external';
  2 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  3 +import { CredentialsCard } from './CredentialsCard';
  4 +
  5 +useComponentRegister('CredentialsCard', CredentialsCard);
3 6
4 7 export const formSchemas: FormSchema[] = [
5 8 {
6   - field: NodeBindDataFieldEnum.NAME,
  9 + field: AzureIotHubFieldsEnum.TOPIC_PATTERN,
  10 + label: AzureIotHubFieldsNameEnum.TOPIC_PATTERN,
7 11 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  12 + required: true,
  13 + helpMessage:
  14 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  15 + componentProps: {
  16 + placeholder: `请输入${AzureIotHubFieldsNameEnum.TOPIC_PATTERN}`,
  17 + },
  18 + },
  19 + {
  20 + field: AzureIotHubFieldsEnum.HOST,
  21 + label: AzureIotHubFieldsNameEnum.HOST,
  22 + component: 'Input',
  23 + required: true,
  24 + componentProps: {
  25 + placeholder: `请输入${AzureIotHubFieldsNameEnum.HOST}`,
  26 + },
  27 + },
  28 + {
  29 + field: AzureIotHubFieldsEnum.CLIENT_ID,
  30 + label: AzureIotHubFieldsNameEnum.CLIENT_ID,
  31 + component: 'Input',
  32 + required: true,
  33 + componentProps: {
  34 + placeholder: `请输入${AzureIotHubFieldsNameEnum.CLIENT_ID}`,
  35 + },
  36 + },
  37 + {
  38 + field: AzureIotHubFieldsEnum.CREDENTIALS,
  39 + label: '',
  40 + component: 'CredentialsCard',
  41 + slot: AzureIotHubFieldsEnum.CREDENTIALS,
9 42 },
10 43 ];
... ...
... ... @@ -3,11 +3,16 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { CredentialsCard } from './CredentialsCard';
  7 + import { ref, unref } from 'vue';
  8 + import { AzureIotHubFieldsEnum } from '../../../enum/formField/external';
6 9
7 10 defineProps<{
8 11 config: NodeData;
9 12 }>();
10 13
  14 + const credentialsCardElRef = ref<Nullable<InstanceType<typeof CredentialsCard>>>();
  15 +
11 16 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 17 schemas: formSchemas,
13 18 showActionButtonGroup: false,
... ... @@ -15,13 +20,23 @@
15 20
16 21 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 22 await validate();
  23 + await unref(credentialsCardElRef)?.validate();
18 24 const value = getFieldsValue() || {};
19   - return value;
  25 + const credentials = unref(credentialsCardElRef)?.getFieldsValue();
  26 + return {
  27 + ...value,
  28 + [AzureIotHubFieldsEnum.PORT]: 8883,
  29 + [AzureIotHubFieldsEnum.SSL]: true,
  30 + [AzureIotHubFieldsEnum.CLEAN_SESSION]: true,
  31 + [AzureIotHubFieldsEnum.CONNECT_TIMEOUT_SEC]: 10,
  32 + [AzureIotHubFieldsEnum.CREDENTIALS]: credentials,
  33 + };
20 34 };
21 35
22 36 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 37 resetFields();
24 38 setFieldsValue(value);
  39 + unref(credentialsCardElRef)?.setFieldsValue(value?.[AzureIotHubFieldsEnum.CREDENTIALS]);
25 40 };
26 41
27 42 defineExpose({
... ... @@ -31,5 +46,9 @@
31 46 </script>
32 47
33 48 <template>
34   - <BasicForm @register="register" />
  49 + <BasicForm @register="register">
  50 + <template #credentials="{ field, model }">
  51 + <CredentialsCard ref="credentialsCardElRef" v-model:value="model[field]" />
  52 + </template>
  53 + </BasicForm>
35 54 </template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { GcpPubsubFieldsEnum, GcpPubsubFieldsNameEnum } from '../../../enum/formField/external';
  2 +import { AttributeConfiguration } from '/@/views/rule/designer/src/components/AttributeConfiguration';
  3 +import { FileItemType, getFileData } from '../../../src/components/CredentialsCard/config';
  4 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  5 +
  6 +useComponentRegister('AttributeConfiguration', AttributeConfiguration);
3 7
4 8 export const formSchemas: FormSchema[] = [
5 9 {
6   - field: NodeBindDataFieldEnum.NAME,
  10 + field: GcpPubsubFieldsEnum.PROJECT_ID,
  11 + label: GcpPubsubFieldsNameEnum.PROJECT_ID,
  12 + component: 'Input',
  13 + required: true,
  14 + componentProps: {
  15 + placeholder: `请输入${GcpPubsubFieldsNameEnum.PROJECT_ID}`,
  16 + },
  17 + },
  18 + {
  19 + field: GcpPubsubFieldsEnum.TOPIC_NAME,
  20 + label: GcpPubsubFieldsNameEnum.TOPIC_NAME,
7 21 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  22 + required: true,
  23 + componentProps: {
  24 + placeholder: `请输入${GcpPubsubFieldsNameEnum.TOPIC_NAME}`,
  25 + },
  26 + },
  27 + {
  28 + field: GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY_FILE_NAME,
  29 + label: GcpPubsubFieldsNameEnum.SERVICE_ACCOUNT_KEY_FILE_NAME,
  30 + component: 'Input',
  31 + show: false,
  32 + componentProps: {
  33 + placeholder: `请输入${GcpPubsubFieldsNameEnum.TOPIC_NAME}`,
  34 + },
  35 + },
  36 + {
  37 + field: GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY,
  38 + label: GcpPubsubFieldsNameEnum.SERVICE_ACCOUNT_KEY,
  39 + component: 'ApiUpload',
  40 + valueField: 'fileList',
  41 + changeEvent: 'update:fileList',
  42 + required: true,
  43 + componentProps: ({ formActionType }) => {
  44 + const { setFieldsValue } = formActionType;
  45 + return {
  46 + overFileLimitHiddenUploadEntry: true,
  47 + api: getFileData,
  48 + 'onUpdate:fileList'(file: FileItemType[]) {
  49 + setFieldsValue({ [GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY_FILE_NAME]: file?.[0]?.name });
  50 + },
  51 + };
  52 + },
  53 + },
  54 + {
  55 + field: GcpPubsubFieldsEnum.MESSAGE_ATTRIBUTES,
  56 + label: GcpPubsubFieldsNameEnum.MESSAGE_ATTRIBUTES,
  57 + component: 'AttributeConfiguration',
  58 + helpMessage:
  59 + 'Use ${metadataKey} for value from metadata, $[messageKey] for value from message body in name/value fields',
  60 + slot: GcpPubsubFieldsEnum.MESSAGE_ATTRIBUTES,
9 61 },
10 62 ];
... ...
... ... @@ -3,6 +3,12 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { AttributeConfiguration } from '/@/views/rule/designer/src/components/AttributeConfiguration';
  7 + import { ref, unref } from 'vue';
  8 + import { GcpPubsubFieldsEnum } from '../../../enum/formField/external';
  9 + import { FileItemType } from '../../../src/components/CredentialsCard/config';
  10 +
  11 + const attributeConfigurationElRef = ref<Nullable<InstanceType<typeof AttributeConfiguration>>>();
6 12
7 13 defineProps<{
8 14 config: NodeData;
... ... @@ -15,13 +21,36 @@
15 21
16 22 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 23 await validate();
  24 + await unref(attributeConfigurationElRef)?.validate();
18 25 const value = getFieldsValue() || {};
19   - return value;
  26 + const messageAttribute = unref(attributeConfigurationElRef)?.getFieldsValue();
  27 + return {
  28 + ...value,
  29 + [GcpPubsubFieldsEnum.MESSAGE_ATTRIBUTES]: messageAttribute,
  30 + [GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY]:
  31 + value?.[GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY]?.[0]?.data || null,
  32 + };
20 33 };
21 34
22 35 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 36 resetFields();
24   - setFieldsValue(value);
  37 +
  38 + const file = value?.[GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY]
  39 + ? [
  40 + {
  41 + uid: Date.now().toString(),
  42 + data: value[GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY],
  43 + name: value[GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY_FILE_NAME],
  44 + } as FileItemType,
  45 + ]
  46 + : [];
  47 + setFieldsValue({
  48 + ...value,
  49 + [GcpPubsubFieldsEnum.SERVICE_ACCOUNT_KEY]: file,
  50 + });
  51 + unref(attributeConfigurationElRef)?.setFieldsValue(
  52 + value?.[GcpPubsubFieldsEnum.MESSAGE_ATTRIBUTES]
  53 + );
25 54 };
26 55
27 56 defineExpose({
... ... @@ -31,5 +60,15 @@
31 60 </script>
32 61
33 62 <template>
34   - <BasicForm @register="register" />
  63 + <BasicForm @register="register">
  64 + <template #messageAttributes="{ field, model }">
  65 + <AttributeConfiguration
  66 + ref="attributeConfigurationElRef"
  67 + v-model:value="model[field]"
  68 + keyLabel="Name"
  69 + valueLabel="Value"
  70 + :allowEmpty="true"
  71 + />
  72 + </template>
  73 + </BasicForm>
35 74 </template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { KafkaFieldsEnum, KafkaFieldsNameEnum } from '../../../enum/formField/external';
  2 +import { AttributeConfiguration } from '/@/views/rule/designer/src/components/AttributeConfiguration';
  3 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  4 +import { CharsetEncodingEnum, CharsetEncodingNameEnum } from '../../../enum/form';
  5 +
  6 +useComponentRegister('AttributeConfiguration', AttributeConfiguration);
3 7
4 8 export const formSchemas: FormSchema[] = [
5 9 {
6   - field: NodeBindDataFieldEnum.NAME,
  10 + field: KafkaFieldsEnum.TOPIC_PATTERN,
  11 + label: KafkaFieldsNameEnum.TOPIC_PATTERN,
  12 + component: 'Input',
  13 + helpMessage:
  14 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  15 + required: true,
  16 + componentProps: {
  17 + placeholder: `请输入${KafkaFieldsEnum.TOPIC_PATTERN}`,
  18 + },
  19 + },
  20 + {
  21 + field: KafkaFieldsEnum.BOOTSTRAP_SERVERS,
  22 + label: KafkaFieldsNameEnum.BOOTSTRAP_SERVERS,
  23 + component: 'Input',
  24 + required: true,
  25 + componentProps: {
  26 + placeholder: `请输入${KafkaFieldsEnum.BOOTSTRAP_SERVERS}`,
  27 + },
  28 + },
  29 + {
  30 + field: KafkaFieldsEnum.RETRIES,
  31 + label: KafkaFieldsNameEnum.RETRIES,
  32 + component: 'InputNumber',
  33 + componentProps: {
  34 + min: 0,
  35 + placeholder: `请输入${KafkaFieldsEnum.BOOTSTRAP_SERVERS}`,
  36 + },
  37 + },
  38 + {
  39 + field: KafkaFieldsEnum.BATCH_SIZE,
  40 + label: KafkaFieldsNameEnum.BATCH_SIZE,
  41 + component: 'InputNumber',
  42 + componentProps: {
  43 + min: 0,
  44 + placeholder: `请输入${KafkaFieldsEnum.BATCH_SIZE}`,
  45 + },
  46 + },
  47 + {
  48 + field: KafkaFieldsEnum.LINGER,
  49 + label: KafkaFieldsNameEnum.LINGER,
  50 + component: 'InputNumber',
  51 + componentProps: {
  52 + min: 0,
  53 + placeholder: `请输入${KafkaFieldsEnum.LINGER}`,
  54 + },
  55 + },
  56 + {
  57 + field: KafkaFieldsEnum.BUFFER_MEMORY,
  58 + label: KafkaFieldsNameEnum.BUFFER_MEMORY,
  59 + component: 'InputNumber',
  60 + componentProps: {
  61 + min: 0,
  62 + placeholder: `请输入${KafkaFieldsEnum.BUFFER_MEMORY}`,
  63 + },
  64 + },
  65 + {
  66 + field: KafkaFieldsEnum.ACKS,
  67 + label: KafkaFieldsEnum.ACKS,
  68 + component: 'Select',
  69 + required: true,
  70 + componentProps: {
  71 + options: [
  72 + { label: 'all', value: 'all' },
  73 + { label: '-1', value: '-1' },
  74 + { label: '0', value: '0' },
  75 + { label: '1', value: '1' },
  76 + ],
  77 + placeholder: `请选择${KafkaFieldsEnum.BUFFER_MEMORY}`,
  78 + getPopupContainer: () => document.body,
  79 + },
  80 + },
  81 + {
  82 + field: KafkaFieldsEnum.KEY_SERIALIZER,
  83 + label: KafkaFieldsNameEnum.KEY_SERIALIZER,
  84 + component: 'Input',
  85 + required: true,
  86 + componentProps: {
  87 + placeholder: `请输入${KafkaFieldsEnum.KEY_SERIALIZER}`,
  88 + },
  89 + },
  90 + {
  91 + field: KafkaFieldsEnum.VALUE_SERIALIZER,
  92 + label: KafkaFieldsNameEnum.VALUE_SERIALIZER,
7 93 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  94 + required: true,
  95 + componentProps: {
  96 + placeholder: `请输入${KafkaFieldsEnum.VALUE_SERIALIZER}`,
  97 + },
  98 + },
  99 + {
  100 + field: KafkaFieldsEnum.OTHER_PROPERTIES,
  101 + label: KafkaFieldsNameEnum.OTHER_PROPERTIES,
  102 + component: 'AttributeConfiguration',
  103 + slot: KafkaFieldsEnum.OTHER_PROPERTIES,
  104 + },
  105 + {
  106 + field: KafkaFieldsEnum.ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS,
  107 + label: KafkaFieldsNameEnum.ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS,
  108 + component: 'Checkbox',
  109 + renderComponentContent: () => ({
  110 + default: () =>
  111 + 'If selected, key-value pairs from message metadata will be added to the outgoing records headers as byte arrays with predefined charset encoding.',
  112 + }),
  113 + },
  114 + {
  115 + field: KafkaFieldsEnum.KAFKA_HEADERS_CHARSET,
  116 + label: KafkaFieldsNameEnum.KAFKA_HEADERS_CHARSET,
  117 + component: 'Select',
  118 + required: true,
  119 + show: ({ model }) => model[KafkaFieldsEnum.ADD_METADATA_KEY_VALUES_AS_KAFKA_HEADERS],
  120 + componentProps: {
  121 + options: Object.keys(CharsetEncodingEnum).map((value) => ({
  122 + label: CharsetEncodingNameEnum[value],
  123 + value,
  124 + })),
  125 + placeholder: `请选择${KafkaFieldsEnum.KAFKA_HEADERS_CHARSET}`,
  126 + getPopupContainer: () => document.body,
  127 + },
9 128 },
10 129 ];
... ...
... ... @@ -3,11 +3,16 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { AttributeConfiguration } from '/@/views/rule/designer/src/components/AttributeConfiguration';
  7 + import { ref, unref } from 'vue';
  8 + import { KafkaFieldsEnum } from '../../../enum/formField/external';
6 9
7 10 defineProps<{
8 11 config: NodeData;
9 12 }>();
10 13
  14 + const attributeConfigurationElRef = ref<Nullable<InstanceType<typeof AttributeConfiguration>>>();
  15 +
11 16 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 17 schemas: formSchemas,
13 18 showActionButtonGroup: false,
... ... @@ -15,13 +20,19 @@
15 20
16 21 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 22 await validate();
  23 + await unref(attributeConfigurationElRef)?.validate();
18 24 const value = getFieldsValue() || {};
19   - return value;
  25 + const otherProperties = unref(attributeConfigurationElRef)?.getFieldsValue();
  26 + return {
  27 + ...value,
  28 + [KafkaFieldsEnum.OTHER_PROPERTIES]: otherProperties,
  29 + };
20 30 };
21 31
22 32 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 33 resetFields();
24 34 setFieldsValue(value);
  35 + unref(attributeConfigurationElRef)?.setFieldsValue(value?.[KafkaFieldsEnum.OTHER_PROPERTIES]);
25 36 };
26 37
27 38 defineExpose({
... ... @@ -31,5 +42,15 @@
31 42 </script>
32 43
33 44 <template>
34   - <BasicForm @register="register" />
  45 + <BasicForm @register="register">
  46 + <template #otherProperties="{ field, model }">
  47 + <AttributeConfiguration
  48 + ref="attributeConfigurationElRef"
  49 + v-model:value="model[field]"
  50 + keyLabel="Key"
  51 + valueLabel="Value"
  52 + :allowEmpty="true"
  53 + />
  54 + </template>
  55 + </BasicForm>
35 56 </template>
... ...
  1 +import { MqttFieldsEnum, MqttFieldsNameEnum } from '../../../../enum/formField/external';
  2 +import { FormSchema } from '/@/components/Form';
  3 +
  4 +// Credentials type
  5 +export enum CredentialsTypeEnum {
  6 + BASIC = 'basic',
  7 + PEM = 'cert.PEM',
  8 + ANONYMOUS = 'anonymous',
  9 +}
  10 +
  11 +export enum CredentialsTypeNameEnum {
  12 + BASIC = 'Basic',
  13 + ANONYMOUS = 'Anonymous',
  14 + PEM = 'PEM',
  15 +}
  16 +
  17 +export interface FileItemType {
  18 + uid: string;
  19 + name: string;
  20 + data?: any;
  21 +}
  22 +
  23 +export const getFileData = async (file: FileItemType) => {
  24 + return new Promise((resolve) => {
  25 + const fileReader = new FileReader();
  26 + fileReader.readAsText(file as unknown as File);
  27 + fileReader.onload = () => {
  28 + if (fileReader.DONE === fileReader.readyState) {
  29 + resolve({
  30 + uid: file.uid,
  31 + name: file.name,
  32 + data: fileReader.result,
  33 + });
  34 + }
  35 + };
  36 + });
  37 +};
  38 +
  39 +export const credentialsTypeOptions = [
  40 + { label: CredentialsTypeNameEnum.BASIC, value: CredentialsTypeEnum.BASIC },
  41 + { label: CredentialsTypeNameEnum.ANONYMOUS, value: CredentialsTypeEnum.ANONYMOUS },
  42 + { label: CredentialsTypeNameEnum.PEM, value: CredentialsTypeEnum.PEM },
  43 +];
  44 +
  45 +export const formSchemas = (
  46 + setType: (
  47 + value: CredentialsTypeEnum,
  48 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  49 + ) => void
  50 +): FormSchema[] => {
  51 + return [
  52 + {
  53 + field: MqttFieldsEnum.TYPE,
  54 + label: MqttFieldsNameEnum.TYPE,
  55 + component: 'Select',
  56 + required: true,
  57 + defaultValue: CredentialsTypeEnum.ANONYMOUS,
  58 + componentProps: ({ formActionType }) => {
  59 + const { setFieldsValue } = formActionType;
  60 + return {
  61 + options: credentialsTypeOptions,
  62 + placeholder: `请选择${MqttFieldsNameEnum.TYPE}`,
  63 + getPopupContainer: () => document.body,
  64 + onChange(
  65 + value: CredentialsTypeEnum,
  66 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  67 + ) {
  68 + setType(value, option);
  69 + setFieldsValue({
  70 + [MqttFieldsEnum.CA_CERT]: [],
  71 + [MqttFieldsEnum.CA_CERT_FILE_NAME]: null,
  72 + [MqttFieldsEnum.CERT]: [],
  73 + [MqttFieldsEnum.CERT_FILE_NAME]: null,
  74 + [MqttFieldsEnum.PRIVATE_KEY]: [],
  75 + [MqttFieldsEnum.PRIVATE_KEY_FILE_NAME]: null,
  76 + [MqttFieldsEnum.PASSWORD]: null,
  77 + });
  78 + },
  79 + };
  80 + },
  81 + },
  82 + {
  83 + field: MqttFieldsEnum.USERNAME,
  84 + label: MqttFieldsNameEnum.USERNAME,
  85 + component: 'Input',
  86 + required: true,
  87 + ifShow: ({ model }) => model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.BASIC,
  88 + componentProps: {
  89 + placeholder: `请输入${MqttFieldsNameEnum.USERNAME}`,
  90 + },
  91 + },
  92 + {
  93 + field: MqttFieldsEnum.CA_CERT_FILE_NAME,
  94 + label: MqttFieldsNameEnum.CA_CERT_FILE_NAME,
  95 + component: 'InputPassword',
  96 + show: false,
  97 + },
  98 + {
  99 + field: MqttFieldsEnum.CA_CERT,
  100 + label: MqttFieldsNameEnum.CA_CERT,
  101 + component: 'ApiUpload',
  102 + valueField: 'fileList',
  103 + changeEvent: 'update:fileList',
  104 + required: true,
  105 + ifShow: ({ model }) => model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  106 + componentProps: ({ formActionType }) => {
  107 + const { setFieldsValue } = formActionType;
  108 + return {
  109 + overFileLimitHiddenUploadEntry: true,
  110 + api: getFileData,
  111 + 'onUpdate:fileList'(file: FileItemType[]) {
  112 + setFieldsValue({ [MqttFieldsEnum.CA_CERT_FILE_NAME]: file?.[0]?.name });
  113 + },
  114 + };
  115 + },
  116 + },
  117 + {
  118 + field: MqttFieldsEnum.CERT_FILE_NAME,
  119 + label: MqttFieldsNameEnum.CERT_FILE_NAME,
  120 + component: 'InputPassword',
  121 + show: false,
  122 + },
  123 + {
  124 + field: MqttFieldsEnum.CERT,
  125 + label: MqttFieldsNameEnum.CERT,
  126 + component: 'ApiUpload',
  127 + valueField: 'fileList',
  128 + changeEvent: 'update:fileList',
  129 + required: true,
  130 + ifShow: ({ model }) => model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  131 + componentProps: ({ formActionType }) => {
  132 + const { setFieldsValue } = formActionType;
  133 + return {
  134 + overFileLimitHiddenUploadEntry: true,
  135 + api: getFileData,
  136 + 'onUpdate:fileList'(file: FileItemType[]) {
  137 + setFieldsValue({ [MqttFieldsEnum.CERT_FILE_NAME]: file?.[0]?.name });
  138 + },
  139 + };
  140 + },
  141 + },
  142 + {
  143 + field: MqttFieldsEnum.PRIVATE_KEY_FILE_NAME,
  144 + label: MqttFieldsNameEnum.PRIVATE_KEY_FILE_NAME,
  145 + component: 'InputPassword',
  146 + show: false,
  147 + },
  148 + {
  149 + field: MqttFieldsEnum.PRIVATE_KEY,
  150 + label: MqttFieldsNameEnum.PRIVATE_KEY,
  151 + component: 'ApiUpload',
  152 + valueField: 'fileList',
  153 + changeEvent: 'update:fileList',
  154 + required: true,
  155 + ifShow: ({ model }) => model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.PEM,
  156 + componentProps: ({ formActionType }) => {
  157 + const { setFieldsValue } = formActionType;
  158 + return {
  159 + overFileLimitHiddenUploadEntry: true,
  160 + api: getFileData,
  161 + 'onUpdate:fileList'(file: FileItemType[]) {
  162 + setFieldsValue({ [MqttFieldsEnum.PRIVATE_KEY_FILE_NAME]: file?.[0]?.name });
  163 + },
  164 + };
  165 + },
  166 + },
  167 + {
  168 + field: MqttFieldsEnum.PASSWORD,
  169 + label: MqttFieldsNameEnum.PASSWORD,
  170 + component: 'InputPassword',
  171 + ifShow: ({ model }) =>
  172 + model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.PEM ||
  173 + model[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.BASIC,
  174 + componentProps: {
  175 + placeholder: `请输入${MqttFieldsNameEnum.PASSWORD}`,
  176 + },
  177 + },
  178 + ];
  179 +};
... ...
  1 +export { default as CredentialsCard } from './index.vue';
... ...
  1 +<script setup lang="ts">
  2 + import { Collapse } from 'ant-design-vue';
  3 + import { BasicForm, useForm } from '/@/components/Form';
  4 + import { credentialsTypeOptions, FileItemType, formSchemas } from './config';
  5 + import { ref, watch } from 'vue';
  6 + import { buildUUID } from '/@/utils/uuid';
  7 + import { CredentialsTypeEnum, CredentialsTypeNameEnum } from './config';
  8 + import { MqttFieldsEnum } from '../../../../enum/formField/external';
  9 +
  10 + const props = withDefaults(
  11 + defineProps<{
  12 + value?: Recordable;
  13 + }>(),
  14 + {
  15 + value: () => ({}),
  16 + }
  17 + );
  18 +
  19 + const activeKey = ref('credentials');
  20 +
  21 + const type = ref(CredentialsTypeNameEnum.ANONYMOUS);
  22 +
  23 + const [register, { getFieldsValue, setFieldsValue, validate }] = useForm({
  24 + schemas: formSchemas(setCredentialsType),
  25 + showActionButtonGroup: false,
  26 + layout: 'vertical',
  27 + });
  28 +
  29 + function setCredentialsType(
  30 + _value: CredentialsTypeEnum,
  31 + option: { label: CredentialsTypeNameEnum; value: CredentialsTypeEnum }
  32 + ) {
  33 + type.value = option.label;
  34 + }
  35 +
  36 + const getFileValue = (file: FileItemType[]) => {
  37 + return file?.[0]?.data || null;
  38 + };
  39 +
  40 + const setFileValueByKey = (
  41 + value: Recordable,
  42 + key: MqttFieldsEnum,
  43 + fileNameKey: MqttFieldsEnum
  44 + ) => {
  45 + return value[key]
  46 + ? [{ uid: buildUUID(), name: value[fileNameKey], data: value[key] } as FileItemType]
  47 + : [];
  48 + };
  49 +
  50 + const getValues = () => {
  51 + const value = getFieldsValue();
  52 + return {
  53 + ...value,
  54 + ...(value?.[MqttFieldsEnum.TYPE] === CredentialsTypeEnum.PEM
  55 + ? {
  56 + [MqttFieldsEnum.CA_CERT]: getFileValue(value?.[MqttFieldsEnum.CA_CERT]),
  57 + [MqttFieldsEnum.CA_CERT]: getFileValue(value?.[MqttFieldsEnum.CERT]),
  58 + [MqttFieldsEnum.PRIVATE_KEY]: getFileValue(value?.[MqttFieldsEnum.PRIVATE_KEY]),
  59 + }
  60 + : {}),
  61 + };
  62 + };
  63 +
  64 + const setValues = (value: Recordable) => {
  65 + const typeLabel = credentialsTypeOptions.find(
  66 + (item) => item.value === value?.[MqttFieldsEnum.TYPE]
  67 + )?.label;
  68 + type.value = typeLabel!;
  69 + setFieldsValue({
  70 + ...value,
  71 + [MqttFieldsEnum.CA_CERT]: setFileValueByKey(
  72 + value,
  73 + MqttFieldsEnum.CA_CERT,
  74 + MqttFieldsEnum.CA_CERT_FILE_NAME
  75 + ),
  76 + [MqttFieldsEnum.CERT]: setFileValueByKey(
  77 + value,
  78 + MqttFieldsEnum.CERT,
  79 + MqttFieldsEnum.CERT_FILE_NAME
  80 + ),
  81 + [MqttFieldsEnum.PRIVATE_KEY]: setFileValueByKey(
  82 + value,
  83 + MqttFieldsEnum.PRIVATE_KEY,
  84 + MqttFieldsEnum.PRIVATE_KEY_FILE_NAME
  85 + ),
  86 + });
  87 + };
  88 +
  89 + watch(
  90 + () => props.value,
  91 + (target) => {
  92 + setValues(target);
  93 + }
  94 + );
  95 +
  96 + defineExpose({
  97 + validate,
  98 + getFieldsValue: getValues,
  99 + setFieldsValue: setValues,
  100 + });
  101 +</script>
  102 +
  103 +<template>
  104 + <Collapse v-model:active-key="activeKey" class="credentials-card" expand-icon-position="right">
  105 + <Collapse.Panel :key="activeKey" class="box-shadow bg-light-50 shadow-2xl">
  106 + <template #header>
  107 + <section class="flex w-full h-full h-8 justify-between items-center">
  108 + <div class="w-1/2 text-left">Credentials</div>
  109 + <div class="w-1/2 text-left font-medium text-gray-400">
  110 + {{ type }}
  111 + </div>
  112 + </section>
  113 + </template>
  114 + <BasicForm @register="register" />
  115 + </Collapse.Panel>
  116 + </Collapse>
  117 +</template>
  118 +
  119 +<style lang="less" scoped>
  120 + .credentials-card {
  121 + :deep(.ant-collapse) {
  122 + &-header {
  123 + @apply !px-6;
  124 + }
  125 +
  126 + &-content {
  127 + &-box {
  128 + @apply px-6;
  129 + }
  130 + }
  131 + }
  132 +
  133 + :deep(.ant-form) {
  134 + > .ant-row {
  135 + > .ant-col {
  136 + > .ant-row {
  137 + > .ant-col {
  138 + min-height: fit-content;
  139 + }
  140 + }
  141 + }
  142 + }
  143 + }
  144 + }
  145 +
  146 + .box-shadow {
  147 + box-shadow: 0 3px 1px -2px #0003, 0 2px 2px 0 #00000024, 0 1px 5px 0 #0000001f;
  148 + }
  149 +</style>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { MqttFieldsEnum, MqttFieldsNameEnum } from '../../../enum/formField/external';
  2 +import { CredentialsCard } from './CredentialsCard';
  3 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  4 +
  5 +useComponentRegister('CredentialsCard', CredentialsCard);
3 6
4 7 export const formSchemas: FormSchema[] = [
5 8 {
6   - field: NodeBindDataFieldEnum.NAME,
  9 + field: MqttFieldsEnum.TOPIC_PATTERN,
  10 + label: MqttFieldsNameEnum.TOPIC_PATTERN,
  11 + component: 'Input',
  12 + helpMessage:
  13 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  14 + required: true,
  15 + componentProps: {
  16 + placeholder: `请输入${MqttFieldsNameEnum.TOPIC_PATTERN}`,
  17 + },
  18 + },
  19 + {
  20 + field: MqttFieldsEnum.HOST,
  21 + label: MqttFieldsNameEnum.HOST,
  22 + component: 'Input',
  23 + required: true,
  24 + colProps: { span: 8 },
  25 + componentProps: {
  26 + placeholder: `请输入${MqttFieldsNameEnum.HOST}`,
  27 + },
  28 + },
  29 + {
  30 + field: MqttFieldsEnum.PORT,
  31 + label: MqttFieldsNameEnum.PORT,
  32 + component: 'InputNumber',
  33 + required: true,
  34 + colProps: { span: 8 },
  35 + componentProps: {
  36 + placeholder: `请输入${MqttFieldsNameEnum.PORT}`,
  37 + },
  38 + },
  39 + {
  40 + field: MqttFieldsEnum.CONNECT_TIMEOUT_SEC,
  41 + label: MqttFieldsNameEnum.CONNECT_TIMEOUT_SEC,
  42 + component: 'Input',
  43 + required: true,
  44 + colProps: { span: 8 },
  45 + componentProps: {
  46 + placeholder: `请输入${MqttFieldsNameEnum.CONNECT_TIMEOUT_SEC}`,
  47 + },
  48 + },
  49 + {
  50 + field: MqttFieldsEnum.CLIENT_ID,
  51 + label: MqttFieldsNameEnum.CLIENT_ID,
7 52 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  53 + helpMessage:
  54 + 'Hint: Optional. Leave empty for auto-generated Client ID. Be careful when specifying the Client ID. Majority of the MQTT brokers will not allow multiple connections with the same Client ID. To connect to such brokers, your mqtt Client ID must be unique. When platform is running in a micro-services mode, the copy of rule node is launched in each micro-service. This will automatically lead to multiple mqtt clients with the same ID and may cause failures of the rule node. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',
  55 + componentProps: {
  56 + placeholder: `请输入${MqttFieldsNameEnum.TOPIC_PATTERN}`,
  57 + },
  58 + },
  59 + {
  60 + field: MqttFieldsEnum.APPEND_CLIENT_ID_SUFFIX,
  61 + label: MqttFieldsNameEnum.APPEND_CLIENT_ID_SUFFIX,
  62 + component: 'Checkbox',
  63 + renderComponentContent: () => ({
  64 + default: () =>
  65 + 'Hint: Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',
  66 + }),
  67 + componentProps: ({ formModel }) => {
  68 + const clientId = formModel[MqttFieldsEnum.CLIENT_ID];
  69 + return {
  70 + disabled: !clientId,
  71 + };
  72 + },
  73 + },
  74 + {
  75 + field: MqttFieldsEnum.CLEAN_SESSION,
  76 + label: '',
  77 + component: 'Checkbox',
  78 + renderComponentContent: () => ({
  79 + default: () => MqttFieldsNameEnum.CLEAN_SESSION,
  80 + }),
  81 + },
  82 + {
  83 + field: MqttFieldsEnum.SSL,
  84 + label: '',
  85 + component: 'Checkbox',
  86 + renderComponentContent: () => ({
  87 + default: () => MqttFieldsNameEnum.SSL,
  88 + }),
  89 + },
  90 + {
  91 + field: MqttFieldsEnum.CREDENTIALS,
  92 + label: MqttFieldsNameEnum.CREDENTIALS,
  93 + component: 'CredentialsCard',
  94 + slot: MqttFieldsEnum.CREDENTIALS,
9 95 },
10 96 ];
... ...
... ... @@ -3,11 +3,16 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { CredentialsCard } from './CredentialsCard';
  7 + import { ref, unref } from 'vue';
  8 + import { MqttFieldsEnum } from '../../../enum/formField/external';
6 9
7 10 defineProps<{
8 11 config: NodeData;
9 12 }>();
10 13
  14 + const credentialsCardElRef = ref<Nullable<InstanceType<typeof CredentialsCard>>>();
  15 +
11 16 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 17 schemas: formSchemas,
13 18 showActionButtonGroup: false,
... ... @@ -15,13 +20,19 @@
15 20
16 21 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 22 await validate();
  23 + await unref(credentialsCardElRef)?.validate();
18 24 const value = getFieldsValue() || {};
19   - return value;
  25 + const credentialsValue = unref(credentialsCardElRef)?.getFieldsValue();
  26 + return {
  27 + ...value,
  28 + [MqttFieldsEnum.CREDENTIALS]: credentialsValue,
  29 + };
20 30 };
21 31
22 32 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 33 resetFields();
24 34 setFieldsValue(value);
  35 + unref(credentialsCardElRef)?.setFieldsValue(value?.[MqttFieldsEnum.CREDENTIALS]);
25 36 };
26 37
27 38 defineExpose({
... ... @@ -31,5 +42,9 @@
31 42 </script>
32 43
33 44 <template>
34   - <BasicForm @register="register" />
  45 + <BasicForm @register="register">
  46 + <template #credentials="{ field, model }">
  47 + <CredentialsCard ref="credentialsCardElRef" v-model:value="model[field]" />
  48 + </template>
  49 + </BasicForm>
35 50 </template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { MessagePropertiesEnum } from '../../../enum/form';
  2 +import { RabbitmqFieldsEnum, RabbitmqFieldsNameEnum } from '../../../enum/formField/external';
2 3 import { FormSchema } from '/@/components/Form';
3 4
4 5 export const formSchemas: FormSchema[] = [
5 6 {
6   - field: NodeBindDataFieldEnum.NAME,
  7 + field: RabbitmqFieldsEnum.EXCHANGE_NAME_PATTERN,
  8 + label: RabbitmqFieldsNameEnum.EXCHANGE_NAME_PATTERN,
7 9 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  10 + componentProps: {
  11 + placeholder: `请输入${RabbitmqFieldsNameEnum.EXCHANGE_NAME_PATTERN}`,
  12 + },
  13 + },
  14 + {
  15 + field: RabbitmqFieldsEnum.ROUTING_KEY_PATTERN,
  16 + label: RabbitmqFieldsNameEnum.ROUTING_KEY_PATTERN,
  17 + component: 'Input',
  18 + componentProps: {
  19 + placeholder: `请输入${RabbitmqFieldsNameEnum.ROUTING_KEY_PATTERN}`,
  20 + },
  21 + },
  22 + {
  23 + field: RabbitmqFieldsEnum.MESSAGE_PROPERTIES,
  24 + label: RabbitmqFieldsNameEnum.MESSAGE_PROPERTIES,
  25 + component: 'Select',
  26 + componentProps: {
  27 + allowClear: true,
  28 + options: Object.keys(MessagePropertiesEnum).map((value) => ({ label: value, value })),
  29 + placeholder: `请选择${RabbitmqFieldsNameEnum.ROUTING_KEY_PATTERN}`,
  30 + },
  31 + },
  32 + {
  33 + field: RabbitmqFieldsEnum.HOST,
  34 + label: RabbitmqFieldsNameEnum.HOST,
  35 + component: 'Input',
  36 + required: true,
  37 + colProps: { span: 12 },
  38 + componentProps: {
  39 + placeholder: `请输入${RabbitmqFieldsNameEnum.HOST}`,
  40 + },
  41 + },
  42 + {
  43 + field: RabbitmqFieldsEnum.PORT,
  44 + label: RabbitmqFieldsNameEnum.PORT,
  45 + component: 'InputNumber',
  46 + required: true,
  47 + colProps: { span: 12 },
  48 + componentProps: {
  49 + placeholder: `请输入${RabbitmqFieldsNameEnum.PORT}`,
  50 + },
  51 + },
  52 + {
  53 + field: RabbitmqFieldsEnum.VIRTUAL_HOST,
  54 + label: RabbitmqFieldsNameEnum.VIRTUAL_HOST,
  55 + component: 'Input',
  56 + componentProps: {
  57 + placeholder: `请输入${RabbitmqFieldsNameEnum.VIRTUAL_HOST}`,
  58 + },
  59 + },
  60 + {
  61 + field: RabbitmqFieldsEnum.USERNAME,
  62 + label: RabbitmqFieldsNameEnum.USERNAME,
  63 + component: 'Input',
  64 + componentProps: {
  65 + placeholder: `请输入${RabbitmqFieldsNameEnum.USERNAME}`,
  66 + },
  67 + },
  68 + {
  69 + field: RabbitmqFieldsEnum.PASSWORD,
  70 + label: RabbitmqFieldsNameEnum.PASSWORD,
  71 + component: 'Input',
  72 + componentProps: {
  73 + placeholder: `请输入${RabbitmqFieldsNameEnum.PASSWORD}`,
  74 + },
  75 + },
  76 + {
  77 + field: RabbitmqFieldsEnum.AUTOMATIC_RECOVERY_ENABLED,
  78 + component: 'Checkbox',
  79 + label: '',
  80 + renderComponentContent: () => ({
  81 + default: () => RabbitmqFieldsNameEnum.AUTOMATIC_RECOVERY_ENABLED,
  82 + }),
  83 + },
  84 + {
  85 + field: RabbitmqFieldsEnum.CONNECTION_TIMEOUT,
  86 + label: RabbitmqFieldsNameEnum.CONNECTION_TIMEOUT,
  87 + component: 'InputNumber',
  88 + componentProps: {
  89 + min: 0,
  90 + placeholder: `请输入${RabbitmqFieldsNameEnum.CONNECTION_TIMEOUT}`,
  91 + },
  92 + },
  93 + {
  94 + field: RabbitmqFieldsEnum.HANDSHAKE_TIMEOUT,
  95 + label: RabbitmqFieldsNameEnum.HANDSHAKE_TIMEOUT,
  96 + component: 'InputNumber',
  97 + componentProps: {
  98 + min: 0,
  99 + placeholder: `请输入${RabbitmqFieldsNameEnum.HANDSHAKE_TIMEOUT}`,
  100 + },
  101 + },
  102 + {
  103 + field: RabbitmqFieldsEnum.CLIENT_PROPERTIES,
  104 + label: RabbitmqFieldsNameEnum.CLIENT_PROPERTIES,
  105 + component: 'Input',
  106 + slot: RabbitmqFieldsEnum.CLIENT_PROPERTIES,
9 107 },
10 108 ];
... ...
... ... @@ -3,11 +3,16 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { AttributeConfiguration } from '/@/views/rule/designer/src/components/AttributeConfiguration';
  7 + import { ref, unref } from 'vue';
  8 + import { RabbitmqFieldsEnum } from '../../../enum/formField/external';
6 9
7 10 defineProps<{
8 11 config: NodeData;
9 12 }>();
10 13
  14 + const attributeConfigurationElRef = ref<Nullable<InstanceType<typeof AttributeConfiguration>>>();
  15 +
11 16 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 17 schemas: formSchemas,
13 18 showActionButtonGroup: false,
... ... @@ -15,13 +20,21 @@
15 20
16 21 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 22 await validate();
  23 + await unref(attributeConfigurationElRef)?.validate();
18 24 const value = getFieldsValue() || {};
19   - return value;
  25 + const clientProperties = unref(attributeConfigurationElRef)?.getFieldsValue();
  26 + return {
  27 + ...value,
  28 + [RabbitmqFieldsEnum.CLIENT_PROPERTIES]: clientProperties,
  29 + };
20 30 };
21 31
22 32 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 33 resetFields();
24 34 setFieldsValue(value);
  35 + unref(attributeConfigurationElRef)?.setFieldsValue(
  36 + value?.[RabbitmqFieldsEnum.CLIENT_PROPERTIES]
  37 + );
25 38 };
26 39
27 40 defineExpose({
... ... @@ -31,5 +44,15 @@
31 44 </script>
32 45
33 46 <template>
34   - <BasicForm @register="register" />
  47 + <BasicForm @register="register">
  48 + <template #clientProperties="{ field, model }">
  49 + <AttributeConfiguration
  50 + ref="attributeConfigurationElRef"
  51 + v-model:value="model[field]"
  52 + keyLabel="Key"
  53 + valueLabel="Value"
  54 + :allowEmpty="true"
  55 + />
  56 + </template>
  57 + </BasicForm>
35 58 </template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { ProtocolEnum, ProtocolNameEnum, RequestMethodEnum } from '../../../enum/form';
  2 +import { RestApiCallFieldsEnum, RestApiCallFieldsNameEnum } from '../../../enum/formField/external';
2 3 import { FormSchema } from '/@/components/Form';
3 4
4 5 export const formSchemas: FormSchema[] = [
5 6 {
6   - field: NodeBindDataFieldEnum.NAME,
  7 + field: RestApiCallFieldsEnum.REST_ENDPOINT_URL_PATTERN,
  8 + label: RestApiCallFieldsNameEnum.REST_ENDPOINT_URL_PATTERN,
7 9 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  10 + required: true,
  11 + helpMessage:
  12 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  13 + componentProps: {
  14 + placeholder: `请输入${RestApiCallFieldsNameEnum.REST_ENDPOINT_URL_PATTERN}`,
  15 + },
  16 + },
  17 + {
  18 + field: RestApiCallFieldsEnum.REQUEST_METHOD,
  19 + label: RestApiCallFieldsNameEnum.REQUEST_METHOD,
  20 + component: 'Select',
  21 + required: true,
  22 + componentProps: {
  23 + options: Object.keys(RequestMethodEnum).map((value) => ({ label: value, value })),
  24 + getPopupContainer: () => document.body,
  25 + placeholder: `请选择${RestApiCallFieldsNameEnum.REQUEST_METHOD}`,
  26 + },
  27 + },
  28 + {
  29 + field: RestApiCallFieldsEnum.ENABLE_PROXY,
  30 + label: '',
  31 + component: 'Checkbox',
  32 + renderComponentContent: () => ({
  33 + default: () => RestApiCallFieldsNameEnum.ENABLE_PROXY,
  34 + }),
  35 + },
  36 + {
  37 + field: RestApiCallFieldsEnum.USE_SIMPLE_CLIENT_HTTP_FACTORY,
  38 + label: '',
  39 + component: 'Checkbox',
  40 + show: ({ model }) => !model[RestApiCallFieldsEnum.ENABLE_PROXY],
  41 + renderComponentContent: () => ({
  42 + default: () => RestApiCallFieldsNameEnum.USE_SIMPLE_CLIENT_HTTP_FACTORY,
  43 + }),
  44 + },
  45 + {
  46 + field: RestApiCallFieldsEnum.IGNORE_REQUEST_BODY,
  47 + label: '',
  48 + component: 'Checkbox',
  49 + renderComponentContent: () => ({
  50 + default: () => RestApiCallFieldsNameEnum.IGNORE_REQUEST_BODY,
  51 + }),
  52 + },
  53 + {
  54 + field: RestApiCallFieldsEnum.USE_SYSTEM_PROXY_PROPERTIES,
  55 + label: '',
  56 + component: 'Checkbox',
  57 + show: ({ model }) => model[RestApiCallFieldsEnum.ENABLE_PROXY],
  58 + renderComponentContent: () => ({
  59 + default: () => RestApiCallFieldsNameEnum.USE_SYSTEM_PROXY_PROPERTIES,
  60 + }),
  61 + },
  62 + {
  63 + field: RestApiCallFieldsEnum.PROXY_SCHEME,
  64 + label: RestApiCallFieldsNameEnum.PROXY_SCHEME,
  65 + component: 'Select',
  66 + required: true,
  67 + colProps: { span: 8 },
  68 + componentProps: {
  69 + options: Object.keys(ProtocolEnum).map((value) => ({
  70 + label: ProtocolNameEnum[value],
  71 + value,
  72 + })),
  73 + getPopupContainer: () => document.body,
  74 + placeholder: `请选择${RestApiCallFieldsEnum.PROXY_SCHEME}`,
  75 + },
  76 + },
  77 + {
  78 + field: RestApiCallFieldsEnum.PROXY_HOST,
  79 + label: RestApiCallFieldsNameEnum.PROXY_HOST,
  80 + component: 'Input',
  81 + required: true,
  82 + colProps: { span: 8 },
  83 + componentProps: {
  84 + placeholder: `请输入${RestApiCallFieldsNameEnum.PROXY_HOST}`,
  85 + },
  86 + },
  87 + {
  88 + field: RestApiCallFieldsEnum.PROXY_PORT,
  89 + label: RestApiCallFieldsNameEnum.PROXY_PORT,
  90 + component: 'InputNumber',
  91 + required: true,
  92 + colProps: { span: 8 },
  93 + componentProps: {
  94 + placeholder: `请输入${RestApiCallFieldsNameEnum.PROXY_HOST}`,
  95 + },
  96 + },
  97 + {
  98 + field: RestApiCallFieldsEnum.PROXY_USER,
  99 + label: RestApiCallFieldsNameEnum.PROXY_USER,
  100 + component: 'Input',
  101 + componentProps: {
  102 + placeholder: `请输入${RestApiCallFieldsNameEnum.PROXY_USER}`,
  103 + },
  104 + },
  105 + {
  106 + field: RestApiCallFieldsEnum.PROXY_PASSWORD,
  107 + label: RestApiCallFieldsNameEnum.PROXY_PASSWORD,
  108 + component: 'Input',
  109 + componentProps: {
  110 + placeholder: `请输入${RestApiCallFieldsNameEnum.PROXY_PASSWORD}`,
  111 + },
  112 + },
  113 + {
  114 + field: RestApiCallFieldsEnum.READ_TIMEOUT_MS,
  115 + label: RestApiCallFieldsNameEnum.READ_TIMEOUT_MS,
  116 + component: 'InputNumber',
  117 + componentProps: {
  118 + min: 0,
  119 + placeholder: `请输入${RestApiCallFieldsNameEnum.READ_TIMEOUT_MS}`,
  120 + },
  121 + },
  122 + {
  123 + field: RestApiCallFieldsEnum.MAX_PARALLEL_REQUESTS_COUNT,
  124 + label: RestApiCallFieldsNameEnum.MAX_PARALLEL_REQUESTS_COUNT,
  125 + component: 'InputNumber',
  126 + componentProps: {
  127 + min: 0,
  128 + placeholder: `请输入${RestApiCallFieldsNameEnum.MAX_PARALLEL_REQUESTS_COUNT}`,
  129 + },
  130 + },
  131 + {
  132 + field: RestApiCallFieldsEnum.HEADERS,
  133 + label: RestApiCallFieldsNameEnum.HEADERS,
  134 + component: 'Input',
  135 + slot: RestApiCallFieldsEnum.HEADERS,
  136 + },
  137 + {
  138 + field: RestApiCallFieldsEnum.USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE,
  139 + label: '',
  140 + component: 'Checkbox',
  141 + renderComponentContent: () => ({
  142 + default: () => RestApiCallFieldsNameEnum.USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE,
  143 + }),
  144 + },
  145 + {
  146 + field: RestApiCallFieldsEnum.TRIM_QUEUE,
  147 + label: '',
  148 + component: 'Checkbox',
  149 + ifShow: ({ model }) => model[RestApiCallFieldsEnum.USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE],
  150 + renderComponentContent: () => ({
  151 + default: () => RestApiCallFieldsNameEnum.TRIM_QUEUE,
  152 + }),
  153 + },
  154 + {
  155 + field: RestApiCallFieldsEnum.MAX_QUEUE_SIZE,
  156 + label: RestApiCallFieldsNameEnum.MAX_QUEUE_SIZE,
  157 + component: 'InputNumber',
  158 + ifShow: ({ model }) => model[RestApiCallFieldsEnum.USE_REDIS_QUEUE_FOR_MSG_PERSISTENCE],
  159 + componentProps: {
  160 + min: 0,
  161 + placeholder: `请输入${RestApiCallFieldsNameEnum.MAX_QUEUE_SIZE}`,
  162 + },
  163 + },
  164 + {
  165 + field: RestApiCallFieldsEnum.CREDENTIALS,
  166 + label: RestApiCallFieldsNameEnum.CREDENTIALS,
  167 + component: 'Input',
  168 + slot: RestApiCallFieldsEnum.CREDENTIALS,
9 169 },
10 170 ];
... ...
... ... @@ -3,11 +3,18 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { AttributeConfiguration } from '../../../src/components/AttributeConfiguration';
  7 + import { ref, unref } from 'vue';
  8 + import { CredentialsCard } from '../Mqtt/CredentialsCard';
  9 + import { RestApiCallFieldsEnum } from '../../../enum/formField/external';
6 10
7 11 defineProps<{
8 12 config: NodeData;
9 13 }>();
10 14
  15 + const attributeConfigurationElRef = ref<Nullable<InstanceType<typeof AttributeConfiguration>>>();
  16 + const credentialsCardElRef = ref<Nullable<InstanceType<typeof CredentialsCard>>>();
  17 +
11 18 const [register, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({
12 19 schemas: formSchemas,
13 20 showActionButtonGroup: false,
... ... @@ -15,13 +22,25 @@
15 22
16 23 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 24 await validate();
  25 + await unref(attributeConfigurationElRef)?.validate();
  26 + await unref(credentialsCardElRef)?.validate();
18 27 const value = getFieldsValue() || {};
19   - return value;
  28 +
  29 + const headers = unref(attributeConfigurationElRef)?.getFieldsValue();
  30 + const credentials = unref(credentialsCardElRef)?.getFieldsValue();
  31 +
  32 + return {
  33 + ...value,
  34 + [RestApiCallFieldsEnum.HEADERS]: headers,
  35 + [RestApiCallFieldsEnum.CREDENTIALS]: credentials,
  36 + };
20 37 };
21 38
22 39 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
23 40 resetFields();
24 41 setFieldsValue(value);
  42 + unref(attributeConfigurationElRef)?.setFieldsValue(value?.[RestApiCallFieldsEnum.HEADERS]);
  43 + unref(credentialsCardElRef)?.setFieldsValue(value?.[RestApiCallFieldsEnum.CREDENTIALS]);
25 44 };
26 45
27 46 defineExpose({
... ... @@ -31,5 +50,18 @@
31 50 </script>
32 51
33 52 <template>
34   - <BasicForm @register="register" />
  53 + <BasicForm @register="register">
  54 + <template #headers="{ field, model }">
  55 + <AttributeConfiguration
  56 + ref="attributeConfigurationElRef"
  57 + v-model:value="model[field]"
  58 + :allowEmpty="true"
  59 + keyLabel="Header"
  60 + valueLabel="Value"
  61 + />
  62 + </template>
  63 + <template #credentials="{ field, model }">
  64 + <CredentialsCard ref="credentialsCardElRef" v-model:value="model[field]" />
  65 + </template>
  66 + </BasicForm>
35 67 </template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import {
  2 + EmailProtocolEnum,
  3 + EmailProtocolNameEnum,
  4 + TSLVersionEnum,
  5 + TSLVersionNameEnum,
  6 +} from '../../../enum/form';
  7 +import { SendEmailFieldsEnum, SendEmailFieldsNameEnum } from '../../../enum/formField/external';
2 8 import { FormSchema } from '/@/components/Form';
3 9
4 10 export const formSchemas: FormSchema[] = [
5 11 {
6   - field: NodeBindDataFieldEnum.NAME,
  12 + field: SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS,
  13 + label: '',
  14 + component: 'Checkbox',
  15 + renderComponentContent: () => ({
  16 + default: () => SendEmailFieldsNameEnum.USE_SYSTEM_SMTP_SETTINGS,
  17 + }),
  18 + },
  19 + {
  20 + field: SendEmailFieldsEnum.SMTP_PROTOCOL,
  21 + label: SendEmailFieldsNameEnum.SMTP_PROTOCOL,
  22 + component: 'Select',
  23 + required: true,
  24 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  25 + componentProps: {
  26 + options: Object.keys(EmailProtocolEnum).map((value) => ({
  27 + label: EmailProtocolNameEnum[value],
  28 + value,
  29 + })),
  30 + placeholder: `请选择${SendEmailFieldsNameEnum.SMTP_PROTOCOL}`,
  31 + getPopupContainer: () => document.body,
  32 + },
  33 + },
  34 + {
  35 + field: SendEmailFieldsEnum.SMTP_HOST,
  36 + label: SendEmailFieldsNameEnum.SMTP_HOST,
7 37 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  38 + required: true,
  39 + colProps: { span: 12 },
  40 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  41 + componentProps: {
  42 + placeholder: `请输入${SendEmailFieldsNameEnum.SMTP_HOST}`,
  43 + },
  44 + },
  45 + {
  46 + field: SendEmailFieldsEnum.SMTP_PORT,
  47 + label: SendEmailFieldsNameEnum.SMTP_PORT,
  48 + component: 'InputNumber',
  49 + required: true,
  50 + colProps: { span: 12 },
  51 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  52 + componentProps: {
  53 + min: 0,
  54 + placeholder: `请输入${SendEmailFieldsNameEnum.SMTP_PORT}`,
  55 + },
  56 + },
  57 + {
  58 + field: SendEmailFieldsEnum.TIMEOUT,
  59 + label: SendEmailFieldsNameEnum.TIMEOUT,
  60 + component: 'InputNumber',
  61 + required: true,
  62 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  63 + componentProps: {
  64 + min: 0,
  65 + placeholder: `请输入${SendEmailFieldsNameEnum.TIMEOUT}`,
  66 + },
  67 + },
  68 + {
  69 + field: SendEmailFieldsEnum.ENABLE_TLS,
  70 + label: '',
  71 + component: 'Checkbox',
  72 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  73 + renderComponentContent: () => ({
  74 + default: () => SendEmailFieldsNameEnum.ENABLE_TLS,
  75 + }),
  76 + },
  77 + {
  78 + field: SendEmailFieldsEnum.TLS_VERSION,
  79 + label: SendEmailFieldsNameEnum.TLS_VERSION,
  80 + component: 'Select',
  81 + required: true,
  82 + ifShow: ({ model }) =>
  83 + model[SendEmailFieldsEnum.TLS_VERSION] &&
  84 + !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  85 + componentProps: {
  86 + options: Object.keys(TSLVersionEnum).map((value) => ({
  87 + label: TSLVersionNameEnum[value],
  88 + value,
  89 + })),
  90 + placeholder: `请选择${SendEmailFieldsNameEnum.TLS_VERSION}`,
  91 + getPopupContainer: () => document.body,
  92 + },
  93 + },
  94 + {
  95 + field: SendEmailFieldsEnum.ENABLE_PROXY,
  96 + label: '',
  97 + component: 'Checkbox',
  98 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  99 + renderComponentContent: () => ({
  100 + default: () => SendEmailFieldsNameEnum.ENABLE_PROXY,
  101 + }),
  102 + },
  103 + {
  104 + field: SendEmailFieldsEnum.PROXY_HOST,
  105 + label: SendEmailFieldsNameEnum.PROXY_HOST,
  106 + component: 'Input',
  107 + required: true,
  108 + colProps: { span: 12 },
  109 + ifShow: ({ model }) =>
  110 + !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS] && model[SendEmailFieldsEnum.PROXY_HOST],
  111 + componentProps: {
  112 + placeholder: `请输入${SendEmailFieldsNameEnum.PROXY_HOST}`,
  113 + },
  114 + },
  115 + {
  116 + field: SendEmailFieldsEnum.PROXY_PORT,
  117 + label: SendEmailFieldsNameEnum.PROXY_PORT,
  118 + component: 'Input',
  119 + required: true,
  120 + colProps: { span: 12 },
  121 + ifShow: ({ model }) =>
  122 + !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS] && model[SendEmailFieldsEnum.PROXY_PORT],
  123 + componentProps: {
  124 + placeholder: `请输入${SendEmailFieldsNameEnum.PROXY_PORT}`,
  125 + },
  126 + },
  127 + {
  128 + field: SendEmailFieldsEnum.PROXY_USER,
  129 + label: SendEmailFieldsNameEnum.PROXY_USER,
  130 + component: 'Input',
  131 + ifShow: ({ model }) =>
  132 + !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS] && model[SendEmailFieldsEnum.PROXY_USER],
  133 + componentProps: {
  134 + placeholder: `请输入${SendEmailFieldsNameEnum.PROXY_USER}`,
  135 + },
  136 + },
  137 + {
  138 + field: SendEmailFieldsEnum.PROXY_PASSWORD,
  139 + label: SendEmailFieldsNameEnum.PROXY_PASSWORD,
  140 + component: 'Input',
  141 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  142 + componentProps: {
  143 + placeholder: `请输入${SendEmailFieldsNameEnum.PROXY_PASSWORD}`,
  144 + },
  145 + },
  146 + {
  147 + field: SendEmailFieldsEnum.USERNAME,
  148 + label: SendEmailFieldsNameEnum.USERNAME,
  149 + component: 'Input',
  150 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  151 + componentProps: {
  152 + placeholder: `请输入${SendEmailFieldsNameEnum.USERNAME}`,
  153 + },
  154 + },
  155 + {
  156 + field: SendEmailFieldsEnum.PASSWORD,
  157 + label: SendEmailFieldsNameEnum.PASSWORD,
  158 + component: 'InputPassword',
  159 + ifShow: ({ model }) => !model[SendEmailFieldsEnum.USE_SYSTEM_SMTP_SETTINGS],
  160 + componentProps: {
  161 + placeholder: `请输入${SendEmailFieldsNameEnum.PASSWORD}`,
  162 + },
9 163 },
10 164 ];
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { SMSServiceProviderEnum, SMSServiceProviderNameEnum } from '../../../enum/form';
  2 +import { SendSMSFieldsEnum, SendSMSFieldsNameEnum } from '../../../enum/formField/external';
2 3 import { FormSchema } from '/@/components/Form';
3 4
4 5 export const formSchemas: FormSchema[] = [
5 6 {
6   - field: NodeBindDataFieldEnum.NAME,
  7 + field: SendSMSFieldsEnum.NUMBERS_TO_TEMPLATE,
  8 + label: SendSMSFieldsNameEnum.NUMBERS_TO_TEMPLATE,
7 9 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  10 + required: true,
  11 + helpMessage:
  12 + 'Comma separated Phone Numbers, use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  13 + componentProps: {
  14 + placeholder: `请输入${SendSMSFieldsNameEnum.NUMBERS_TO_TEMPLATE}`,
  15 + },
  16 + },
  17 + {
  18 + field: SendSMSFieldsEnum.SMS_MESSAGE_TEMPLATE,
  19 + label: SendSMSFieldsNameEnum.SMS_MESSAGE_TEMPLATE,
  20 + component: 'InputTextArea',
  21 + required: true,
  22 + helpMessage:
  23 + 'Hint: use ${metadataKey} for value from metadata, $[messageKey] for value from message body',
  24 + componentProps: {
  25 + placeholder: `请输入${SendSMSFieldsNameEnum.SMS_MESSAGE_TEMPLATE}`,
  26 + },
  27 + },
  28 + {
  29 + field: SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS,
  30 + label: '',
  31 + component: 'Checkbox',
  32 + renderComponentContent: () => ({
  33 + default: () => SendSMSFieldsNameEnum.USE_SYSTEM_SMS_SETTINGS,
  34 + }),
  35 + },
  36 + {
  37 + field: SendSMSFieldsEnum.TYPE,
  38 + label: SendSMSFieldsNameEnum.TYPE,
  39 + component: 'Select',
  40 + required: true,
  41 + ifShow: ({ model }) => !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS],
  42 + componentProps: {
  43 + options: Object.keys(SMSServiceProviderEnum).map((value) => ({
  44 + label: SMSServiceProviderNameEnum[value],
  45 + value,
  46 + })),
  47 + getPopupContainer: () => document.body,
  48 + placeholder: `请选择${SendSMSFieldsNameEnum.TYPE}`,
  49 + },
  50 + },
  51 + {
  52 + field: SendSMSFieldsEnum.NUMBER_FROM,
  53 + label: SendSMSFieldsNameEnum.NUMBER_FROM,
  54 + component: 'Input',
  55 + required: true,
  56 + helpMessage: `Phone Number in E.164 format/Phone Number's SID/Messaging Service SID, ex. +19995550123/PNXXX/MGXXX`,
  57 + ifShow: ({ model }) =>
  58 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  59 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.TWILIO,
  60 + componentProps: {
  61 + placeholder: `请输入${SendSMSFieldsEnum.NUMBER_FROM}`,
  62 + },
  63 + },
  64 + {
  65 + field: SendSMSFieldsEnum.ACCOUNT_SID,
  66 + label: SendSMSFieldsNameEnum.ACCOUNT_SID,
  67 + component: 'Input',
  68 + required: true,
  69 + ifShow: ({ model }) =>
  70 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  71 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.TWILIO,
  72 + componentProps: {
  73 + placeholder: `请选择${SendSMSFieldsNameEnum.ACCOUNT_SID}`,
  74 + },
  75 + },
  76 + {
  77 + field: SendSMSFieldsEnum.ACCOUNT_TOKEN,
  78 + label: SendSMSFieldsNameEnum.ACCOUNT_TOKEN,
  79 + component: 'Input',
  80 + required: true,
  81 + ifShow: ({ model }) =>
  82 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  83 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.TWILIO,
  84 + componentProps: {
  85 + placeholder: `请选择${SendSMSFieldsNameEnum.ACCOUNT_TOKEN}`,
  86 + },
  87 + },
  88 + {
  89 + field: SendSMSFieldsEnum.ACCESS_KEY_ID,
  90 + label: SendSMSFieldsNameEnum.ACCESS_KEY_ID,
  91 + component: 'Input',
  92 + required: true,
  93 + ifShow: ({ model }) =>
  94 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  95 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.AWS_SNS,
  96 + componentProps: {
  97 + placeholder: `请选择${SendSMSFieldsNameEnum.ACCESS_KEY_ID}`,
  98 + },
  99 + },
  100 + {
  101 + field: SendSMSFieldsEnum.SECRET_ACCESS_KEY,
  102 + label: SendSMSFieldsNameEnum.SECRET_ACCESS_KEY,
  103 + component: 'InputPassword',
  104 + required: true,
  105 + ifShow: ({ model }) =>
  106 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  107 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.AWS_SNS,
  108 + componentProps: {
  109 + placeholder: `请选择${SendSMSFieldsNameEnum.SECRET_ACCESS_KEY}`,
  110 + },
  111 + },
  112 + {
  113 + field: SendSMSFieldsEnum.REGION,
  114 + label: SendSMSFieldsNameEnum.REGION,
  115 + component: 'InputPassword',
  116 + required: true,
  117 + ifShow: ({ model }) =>
  118 + !model[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS] &&
  119 + model[SendSMSFieldsEnum.TYPE] === SMSServiceProviderEnum.AWS_SNS,
  120 + componentProps: {
  121 + placeholder: `请选择${SendSMSFieldsNameEnum.REGION}`,
  122 + },
9 123 },
10 124 ];
... ...
... ... @@ -3,6 +3,7 @@
3 3 import { BasicForm, useForm } from '/@/components/Form';
4 4 import { formSchemas } from './create.config';
5 5 import { NodeData } from '../../../types/node';
  6 + import { SendSMSFieldsEnum } from '../../../enum/formField/external';
6 7
7 8 defineProps<{
8 9 config: NodeData;
... ... @@ -16,7 +17,20 @@
16 17 const getValue: CreateModalDefineExposeType['getFieldsValue'] = async () => {
17 18 await validate();
18 19 const value = getFieldsValue() || {};
19   - return value;
  20 + return {
  21 + [SendSMSFieldsEnum.NUMBERS_TO_TEMPLATE]: value[SendSMSFieldsEnum.NUMBERS_TO_TEMPLATE],
  22 + [SendSMSFieldsEnum.SMS_MESSAGE_TEMPLATE]: value[SendSMSFieldsEnum.SMS_MESSAGE_TEMPLATE],
  23 + [SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS]: value[SendSMSFieldsEnum.USE_SYSTEM_SMS_SETTINGS],
  24 + [SendSMSFieldsEnum.SMS_PROVIDER_CONFIGURATION]: {
  25 + [SendSMSFieldsEnum.ACCESS_KEY_ID]: value[SendSMSFieldsEnum.ACCESS_KEY_ID],
  26 + [SendSMSFieldsEnum.REGION]: value[SendSMSFieldsEnum.REGION],
  27 + [SendSMSFieldsEnum.SECRET_ACCESS_KEY]: value[SendSMSFieldsEnum.SECRET_ACCESS_KEY],
  28 + [SendSMSFieldsEnum.TYPE]: value[SendSMSFieldsEnum.TYPE],
  29 + [SendSMSFieldsEnum.ACCOUNT_SID]: value[SendSMSFieldsEnum.ACCOUNT_SID],
  30 + [SendSMSFieldsEnum.ACCOUNT_TOKEN]: value[SendSMSFieldsEnum.ACCOUNT_TOKEN],
  31 + [SendSMSFieldsEnum.NUMBER_FROM]: value[SendSMSFieldsEnum.NUMBER_FROM],
  32 + },
  33 + };
20 34 };
21 35
22 36 const setValue: CreateModalDefineExposeType['setFieldsValue'] = (value) => {
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2 1 import { FormSchema } from '/@/components/Form';
3 2
4   -export const formSchemas: FormSchema[] = [
5   - {
6   - field: NodeBindDataFieldEnum.NAME,
7   - component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
9   - },
10   -];
  3 +export const formSchemas: FormSchema[] = [];
... ...
  1 +<script setup lang="ts">
  2 + import { AutoComplete } from 'ant-design-vue';
  3 + import get from 'lodash-es/get';
  4 + import omit from 'lodash-es/omit';
  5 + import { computed, ref, unref, watch, watchEffect } from 'vue';
  6 + import { isFunction } from '/@/utils/is';
  7 + type OptionsItem = { text: string; value: string };
  8 +
  9 + const props = withDefaults(
  10 + defineProps<{
  11 + value?: string;
  12 + api?: (arg?: Recordable) => Promise<OptionsItem[]>;
  13 + onSearchQuery?: boolean;
  14 + params?: Recordable;
  15 + resultField?: string;
  16 + valueField?: string;
  17 + labelField?: string;
  18 + immediate?: boolean;
  19 + }>(),
  20 + {
  21 + valueField: 'value',
  22 + labelField: 'label',
  23 + immediate: true,
  24 + }
  25 + );
  26 +
  27 + const emit = defineEmits(['update:value', 'options-change']);
  28 +
  29 + const loading = ref(false);
  30 +
  31 + const isFirstLoad = ref(true);
  32 +
  33 + const options = ref<OptionsItem[]>([]);
  34 +
  35 + const getOptions = computed(() => {
  36 + const { labelField, valueField } = props;
  37 +
  38 + return unref(options).reduce((prev, next: Recordable) => {
  39 + if (next) {
  40 + const value = next[valueField];
  41 + prev.push({
  42 + ...omit(next, [labelField, valueField]),
  43 + text: next[labelField],
  44 + value,
  45 + });
  46 + }
  47 + return prev;
  48 + }, [] as OptionsItem[]);
  49 + });
  50 +
  51 + const fetch = async () => {
  52 + const api = props.api;
  53 + if (!api || !isFunction(api)) return;
  54 + options.value = [];
  55 + try {
  56 + loading.value = true;
  57 + const res = await api(props.params);
  58 + if (Array.isArray(res)) {
  59 + options.value = res;
  60 + emitChange();
  61 + return;
  62 + }
  63 + if (props.resultField) {
  64 + options.value = get(res, props.resultField) || [];
  65 + }
  66 + emitChange();
  67 + } catch (error) {
  68 + console.warn(error);
  69 + } finally {
  70 + loading.value = false;
  71 + }
  72 + };
  73 +
  74 + function emitChange() {
  75 + emit('options-change', unref(getOptions));
  76 + }
  77 +
  78 + const handleChange = (value: any) => {
  79 + emit('update:value', value);
  80 + };
  81 +
  82 + watchEffect(() => {
  83 + props.immediate && fetch();
  84 + });
  85 +
  86 + watch(
  87 + () => props.params,
  88 + () => {
  89 + !unref(isFirstLoad) && fetch();
  90 + },
  91 + { deep: true }
  92 + );
  93 +</script>
  94 +
  95 +<template>
  96 + <AutoComplete :value="value" @change="handleChange" :options="getOptions" />
  97 +</template>
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
2   -import { FormSchema } from '/@/components/Form';
  1 +import { CheckPointFieldsEnum, CheckPointFieldsNameEnum } from '../../../enum/formField/flow';
  2 +import { FormSchema, useComponentRegister } from '/@/components/Form';
  3 +import ApiComplete from './ApiComplete.vue';
  4 +import { getTenantQueue } from '/@/api/ruleChainDesigner';
  5 +
  6 +useComponentRegister('ApiComplete', ApiComplete);
3 7
4 8 export const formSchemas: FormSchema[] = [
5 9 {
6   - field: NodeBindDataFieldEnum.NAME,
7   - component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  10 + field: CheckPointFieldsEnum.QUEUE_NAME,
  11 + label: CheckPointFieldsNameEnum.QUEUE_NAME,
  12 + component: 'ApiComplete',
  13 + required: true,
  14 + helpMessage: ['从下拉列表中选择或自定义名称'],
  15 + valueField: 'value',
  16 + changeEvent: 'update:value',
  17 + componentProps: () => {
  18 + return {
  19 + placeholder: `请选择${CheckPointFieldsNameEnum.QUEUE_NAME}`,
  20 + getPopupContainer: () => document.body,
  21 + api: async (params: Recordable) => {
  22 + const options = await getTenantQueue(params);
  23 + return options.map((value) => ({ label: value, value }));
  24 + },
  25 + params: { serviceType: 'TB_RULE_ENGINE' },
  26 + };
  27 + },
9 28 },
10 29 ];
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { h } from 'vue';
2 2 import { FormSchema } from '/@/components/Form';
3 3
4 4 export const formSchemas: FormSchema[] = [
5 5 {
6   - field: NodeBindDataFieldEnum.NAME,
  6 + field: 'desc',
  7 + label: '',
7 8 component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  9 + renderColContent: () =>
  10 + h(
  11 + 'div',
  12 + 'The rule node name corresponds to the relation type of the output message, and it is used to forward messages to other rule nodes in the caller rule chain.'
  13 + ),
9 14 },
10 15 ];
... ...
1   -import { NodeBindDataFieldEnum, NodeBindDataFieldNameEnum } from '../../../enum/node';
  1 +import { RuleChainFieldsEnum, RuleChainFieldsNameEnum } from '../../../enum/formField/flow';
  2 +import { getRuleChains } from '/@/api/ruleDesigner';
2 3 import { FormSchema } from '/@/components/Form';
3 4
4 5 export const formSchemas: FormSchema[] = [
5 6 {
6   - field: NodeBindDataFieldEnum.NAME,
7   - component: 'Input',
8   - label: NodeBindDataFieldNameEnum.NAME,
  7 + field: RuleChainFieldsEnum.RULE_CHAIN_ID,
  8 + label: RuleChainFieldsNameEnum.RULE_CHAIN_ID,
  9 + component: 'ApiSearchSelect',
  10 + componentProps: () => {
  11 + return {
  12 + placeholder: '请选择所属产品',
  13 + showSearch: true,
  14 + resultField: 'data',
  15 + labelField: 'name',
  16 + valueField: 'id.id',
  17 + params: {
  18 + pageSize: 50,
  19 + page: 0,
  20 + type: 'CORE',
  21 + },
  22 + api: getRuleChains,
  23 + searchApi: getRuleChains,
  24 + getPopupContainer: () => document.body,
  25 + };
  26 + },
9 27 },
10 28 ];
... ...
1 1 export enum RuleNodeTypeEnum {
  2 + ENTRY = 'ENTRY',
2 3 FLOW = 'FLOW',
3 4 ENRICHMENT = 'ENRICHMENT',
4 5 EXTERNAL = 'EXTERNAL',
... ...
... ... @@ -28,6 +28,7 @@
28 28 valueLabel?: string;
29 29 keyComponent?: ComponentType;
30 30 valueComponent?: ComponentType;
  31 + allowEmpty?: boolean;
31 32 }>(),
32 33 {
33 34 keyComponent: 'Input',
... ... @@ -132,7 +133,7 @@
132 133
133 134 list.value = valueList;
134 135
135   - if (!list.value.length) list.value = [{ uuid: buildShortUUID() }];
  136 + if (!list.value.length && !props.allowEmpty) list.value = [{ uuid: buildShortUUID() }];
136 137 };
137 138
138 139 watch(
... ...
... ... @@ -37,8 +37,6 @@
37 37 const currentEdge = flowActionType.findEdge(props.id);
38 38
39 39 (currentEdge!.data as EdgeData).data = data;
40   -
41   - console.log(props);
42 40 };
43 41
44 42 const handleDelete = () => {
... ...
... ... @@ -68,7 +68,7 @@
68 68 <div>
69 69 <Icon class="text-2xl dark:text-light-50" :icon="getIcon" />
70 70 </div>
71   - <BasicToolbar v-bind="$props" />
  71 + <BasicToolbar v-if="!getData.config?.disableAction" v-bind="$props" />
72 72 <div class="flex text-xs flex-col ml-2 text-left truncate">
73 73 <span class="text-gray-700 w-full truncate dark:text-light-50">{{ getLabel }}</span>
74 74 <span class="w-full truncate dark:text-neutral-50">{{ getName }}</span>
... ...
... ... @@ -3,7 +3,7 @@
3 3 </script>
4 4
5 5 <template>
6   - <section class="p-2 bg-gray-100 dark:bg-dark-200">
  6 + <section class="bg-gray-100 dark:bg-dark-200">
7 7 <DebugEvent />
8 8 </section>
9 9 </template>
... ...
... ... @@ -97,7 +97,7 @@
97 97 <Tabs>
98 98 <Tabs.TabPane :tab="TabsPanelNameEnum[TabsPanelEnum.DETAIL]" :key="TabsPanelEnum.DETAIL">
99 99 <Spin :spinning="spinning">
100   - <section v-if="shadowComponent" class="w-full h-full overflow-y-auto">
  100 + <section v-if="shadowComponent" class="w-full h-full overflow-y-auto pr-4">
101 101 <BasicForm @register="topFormRegister" @vue:mounted="handleTopFormMounted" />
102 102 <component
103 103 class="rule-node-form"
... ... @@ -152,7 +152,12 @@
152 152 @apply h-full flex flex-col;
153 153
154 154 .ant-tabs-content {
155   - @apply flex-auto overflow-x-hidden overflow-y-auto pr-4;
  155 + height: calc(100% - 61px);
  156 + }
  157 +
  158 + .ant-spin-nested-loading,
  159 + .ant-spin-container {
  160 + @apply h-full;
156 161 }
157 162 }
158 163 }
... ...
... ... @@ -55,6 +55,11 @@ export interface NodeItemConfigType {
55 55 * @description 配置描述
56 56 */
57 57 configurationDescriptor: ConfigurationDescriptor;
  58 +
  59 + /**
  60 + * @description 禁用所有动作
  61 + */
  62 + disableAction?: boolean;
58 63 }
59 64
60 65 export interface CategoryConfigType {
... ...