diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index 53dd41008e..274b2ef6b7 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -773,7 +773,24 @@ const project = { switch_condition: 'Condition', switch_branch_flow: 'Branch Flow', and: 'and', - or: 'or' + or: 'or', + datax_custom_template: 'Custom Template Switch', + datax_json_template: 'JSON', + datax_target_datasource_type: 'Target Datasource Type', + datax_target_database: 'Target Database', + datax_target_table: 'Target Table', + datax_target_table_tips: 'Please enter the name of the target table', + datax_target_database_pre_sql: 'Pre SQL Statement', + datax_target_database_post_sql: 'Post SQL Statement', + datax_non_query_sql_tips: 'Please enter the non-query sql statement', + datax_job_speed_byte: 'Speed(Byte count)', + datax_job_speed_byte_info: '(0 means unlimited)', + datax_job_speed_record: 'Speed(Record count)', + datax_job_speed_record_info: '(0 means unlimited)', + datax_job_runtime_memory: 'Runtime Memory Limits', + datax_job_runtime_memory_xms: 'Low Limit Value', + datax_job_runtime_memory_xmx: 'High Limit Value', + datax_job_runtime_memory_unit: 'G' } } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 678bfadad9..0b0765b377 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -764,7 +764,24 @@ const project = { switch_condition: '条件', switch_branch_flow: '分支流转', and: '且', - or: '或' + or: '或', + datax_custom_template: '自定义模板', + datax_json_template: 'JSON', + datax_target_datasource_type: '目标源类型', + datax_target_database: '目标源实例', + datax_target_table: '目标表', + datax_target_table_tips: '请输入目标表名', + datax_target_database_pre_sql: '目标库前置SQL', + datax_target_database_post_sql: '目标库后置SQL', + datax_non_query_sql_tips: '请输入非查询SQL语句', + datax_job_speed_byte: '限流(字节数)', + datax_job_speed_byte_info: '(KB,0代表不限制)', + datax_job_speed_record: '限流(记录数)', + datax_job_speed_record_info: '(0代表不限制)', + datax_job_runtime_memory: '运行内存', + datax_job_runtime_memory_xms: '最小内存', + datax_job_runtime_memory_xmx: '最大内存', + datax_job_runtime_memory_unit: 'G' } } diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts index 95f4886715..e3d5c7d15c 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/index.ts @@ -48,3 +48,4 @@ export { useSql } from './use-sql' export { useSqoop } from './use-sqoop' export { useSeaTunnel } from './use-sea-tunnel' export { useSwitch } from './use-switch' +export { useDataX } from './use-datax' diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource-type.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource-type.ts index 7e816ec5d8..c0827845d6 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource-type.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource-type.ts @@ -18,8 +18,13 @@ import { ref, onMounted } from 'vue' import { useI18n } from 'vue-i18n' import type { IJsonItem } from '../types' +import { indexOf } from 'lodash' -export function useDatasourceType(model: { [field: string]: any }): IJsonItem { +export function useDatasourceType( + model: { [field: string]: any }, + supportedDatasourceType?: string[], + field?: string +): IJsonItem { const { t } = useI18n() const options = ref([] as { label: string; value: string }[]) @@ -78,7 +83,15 @@ export function useDatasourceType(model: { [field: string]: any }): IJsonItem { loading.value = true try { options.value = datasourceTypes - .filter((item) => !item.disabled) + .filter((item) => { + if (item.disabled) { + return false + } + if (supportedDatasourceType) { + return indexOf(supportedDatasourceType, item.code) !== -1 + } + return true + }) .map((item) => ({ label: item.code, value: item.code })) loading.value = false } catch (err) { @@ -87,7 +100,11 @@ export function useDatasourceType(model: { [field: string]: any }): IJsonItem { } const onChange = (type: string) => { - model.type = type + if (field) { + model[field] = type + } else { + model.type = type + } } onMounted(() => { @@ -95,7 +112,7 @@ export function useDatasourceType(model: { [field: string]: any }): IJsonItem { }) return { type: 'select', - field: 'datasourceType', + field: field ? field : 'datasourceType', span: 12, name: t('project.node.datasource_type'), props: { @@ -105,8 +122,7 @@ export function useDatasourceType(model: { [field: string]: any }): IJsonItem { options: options, validate: { trigger: ['input', 'blur'], - required: true, - message: t('project.node.worker_group_tips') + required: true }, value: model.type } diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource.ts index b49df646b1..de1131886b 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datasource.ts @@ -22,7 +22,10 @@ import type { IJsonItem } from '../types' import { TypeReq } from '@/service/modules/data-source/types' import { find } from 'lodash' -export function useDatasource(model: { [field: string]: any }): IJsonItem { +export function useDatasource( + model: { [field: string]: any }, + field?: string +): IJsonItem { const { t } = useI18n() const options = ref([] as { label: string; value: string }[]) @@ -71,7 +74,7 @@ export function useDatasource(model: { [field: string]: any }): IJsonItem { }) return { type: 'select', - field: 'datasource', + field: field ? field : 'datasource', span: 12, name: t('project.node.datasource_instances'), props: { diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datax.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datax.ts new file mode 100644 index 0000000000..6ceaa7a7b7 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-datax.ts @@ -0,0 +1,454 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ref, onMounted, watch } from 'vue' +import { useI18n } from 'vue-i18n' +import type { IJsonItem } from '../types' +import { find, indexOf } from 'lodash' +import { TypeReq } from '@/service/modules/data-source/types' +import { queryDataSourceList } from '@/service/modules/data-source' + +export function useDataX(model: { [field: string]: any }): IJsonItem[] { + const { t } = useI18n() + + const datasourceTypes = [ + { + id: 0, + code: 'MYSQL', + disabled: false + }, + { + id: 1, + code: 'POSTGRESQL', + disabled: false + }, + { + id: 2, + code: 'HIVE', + disabled: true + }, + { + id: 3, + code: 'SPARK', + disabled: true + }, + { + id: 4, + code: 'CLICKHOUSE', + disabled: false + }, + { + id: 5, + code: 'ORACLE', + disabled: false + }, + { + id: 6, + code: 'SQLSERVER', + disabled: false + }, + { + id: 7, + code: 'DB2', + disabled: true + }, + { + id: 8, + code: 'PRESTO', + disabled: true + } + ] + const datasourceTypeOptions = ref([] as any) + const datasourceOptions = ref([] as any) + const destinationDatasourceOptions = ref([] as any) + const jobSpeedByteOptions: any[] = [ + { + label: '不限制', + value: 0 + }, + { + label: '1KB', + value: 1024 + }, + { + label: '10KB', + value: 10240 + }, + { + label: '50KB', + value: 51200 + }, + { + label: '100KB', + value: 102400 + }, + { + label: '512KB', + value: 524288 + } + ] + const jobSpeedRecordOptions: any[] = [ + { + label: '不限制', + value: 0 + }, + { + label: '500', + value: 500 + }, + { + label: '1000', + value: 1000 + }, + { + label: '1500', + value: 1500 + }, + { + label: '2000', + value: 2000 + }, + { + label: '2500', + value: 2500 + }, + { + label: '3000', + value: 3000 + } + ] + const memoryLimitOptions = [ + { + label: '1G', + value: 1 + }, + { + label: '2G', + value: 2 + }, + { + label: '3G', + value: 3 + }, + { + label: '4G', + value: 4 + } + ] + const loading = ref(false) + + const getDatasourceTypes = async () => { + if (loading.value) return + loading.value = true + try { + datasourceTypeOptions.value = datasourceTypes + .filter((item) => !item.disabled) + .map((item) => ({ label: item.code, value: item.code })) + loading.value = false + } catch (err) { + loading.value = false + } + } + + const getDatasourceInstances = async () => { + const params = { type: model.dsType } as TypeReq + const res = await queryDataSourceList(params) + datasourceOptions.value = [] + res.map((item: any) => { + datasourceOptions.value.push({ label: item.name, value: String(item.id) }) + }) + if (datasourceOptions.value && model.dataSource) { + let item = find(datasourceOptions.value, { + value: String(model.dataSource) + }) + if (!item) { + model.dataSource = null + } + } + } + + const getDestinationDatasourceInstances = async () => { + const params = { type: model.dtType } as TypeReq + const res = await queryDataSourceList(params) + destinationDatasourceOptions.value = [] + res.map((item: any) => { + destinationDatasourceOptions.value.push({ + label: item.name, + value: String(item.id) + }) + }) + if (destinationDatasourceOptions.value && model.dataTarget) { + let item = find(destinationDatasourceOptions.value, { + value: String(model.dataTarget) + }) + if (!item) { + model.dataTarget = null + } + } + } + + const sqlEditorSpan = ref(24) + const jsonEditorSpan = ref(0) + const datasourceSpan = ref(12) + const destinationDatasourceSpan = ref(8) + const otherStatementSpan = ref(22) + const jobSpeedSpan = ref(12) + const customParameterSpan = ref(0) + + const initConstants = () => { + if (model.customConfigSwitch) { + model.customConfig = 1 + sqlEditorSpan.value = 0 + jsonEditorSpan.value = 24 + datasourceSpan.value = 0 + destinationDatasourceSpan.value = 0 + otherStatementSpan.value = 0 + jobSpeedSpan.value = 0 + customParameterSpan.value = 24 + } else { + model.customConfig = 0 + sqlEditorSpan.value = 24 + jsonEditorSpan.value = 0 + datasourceSpan.value = 12 + destinationDatasourceSpan.value = 8 + otherStatementSpan.value = 22 + jobSpeedSpan.value = 12 + customParameterSpan.value = 0 + } + } + + onMounted(() => { + getDatasourceTypes() + getDatasourceInstances() + getDestinationDatasourceInstances() + initConstants() + }) + + const onSourceTypeChange = (type: string) => { + model.dsType = type + getDatasourceInstances() + } + + const onDestinationTypeChange = (type: string) => { + model.dtType = type + getDestinationDatasourceInstances() + } + + watch( + () => model.customConfigSwitch, + () => { + initConstants() + } + ) + + return [ + { + type: 'switch', + field: 'customConfigSwitch', + name: t('project.node.datax_custom_template') + }, + { + type: 'select', + field: 'dsType', + span: datasourceSpan, + name: t('project.node.datasource_type'), + props: { + loading: loading, + 'on-update:value': onSourceTypeChange + }, + options: datasourceTypeOptions, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'select', + field: 'dataSource', + span: datasourceSpan, + name: t('project.node.datasource_instances'), + props: { + loading: loading + }, + options: datasourceOptions, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'editor', + field: 'sql', + name: t('project.node.sql_statement'), + span: sqlEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + { + type: 'editor', + field: 'json', + name: t('project.node.datax_json_template'), + span: jsonEditorSpan, + validate: { + trigger: ['input', 'trigger'], + required: true, + message: t('project.node.sql_empty_tips') + } + }, + { + type: 'select', + field: 'dtType', + name: t('project.node.datax_target_datasource_type'), + span: destinationDatasourceSpan, + props: { + loading: loading, + 'on-update:value': onDestinationTypeChange + }, + options: datasourceTypeOptions, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'select', + field: 'dataTarget', + name: t('project.node.datax_target_database'), + span: destinationDatasourceSpan, + props: { + loading: loading + }, + options: destinationDatasourceOptions, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'input', + field: 'targetTable', + name: t('project.node.datax_target_table'), + span: destinationDatasourceSpan, + props: { + placeholder: t('project.node.datax_target_table_tips') + }, + validate: { + trigger: ['input', 'blur'], + required: true + } + }, + { + type: 'multi-input', + field: 'preStatements', + name: t('project.node.datax_target_database_pre_sql'), + span: otherStatementSpan, + props: { + placeholder: t('project.node.datax_non_query_sql_tips'), + type: 'textarea', + autosize: { minRows: 1 } + } + }, + { + type: 'multi-input', + field: 'postStatements', + name: t('project.node.datax_target_database_post_sql'), + span: otherStatementSpan, + props: { + placeholder: t('project.node.datax_non_query_sql_tips'), + type: 'textarea', + autosize: { minRows: 1 } + } + }, + { + type: 'select', + field: 'jobSpeedByte', + name: t('project.node.datax_job_speed_byte'), + span: jobSpeedSpan, + options: jobSpeedByteOptions, + value: 0 + }, + { + type: 'select', + field: 'jobSpeedRecord', + name: t('project.node.datax_job_speed_record'), + span: jobSpeedSpan, + options: jobSpeedRecordOptions, + value: 1000 + }, + { + type: 'custom-parameters', + field: 'localParams', + name: t('project.node.custom_parameters'), + span: customParameterSpan, + children: [ + { + type: 'input', + field: 'prop', + span: 10, + props: { + placeholder: t('project.node.prop_tips'), + maxLength: 256 + }, + validate: { + trigger: ['input', 'blur'], + required: true, + validator(validate: any, value: string) { + if (!value) { + return new Error(t('project.node.prop_tips')) + } + + const sameItems = model.localParams.filter( + (item: { prop: string }) => item.prop === value + ) + + if (sameItems.length > 1) { + return new Error(t('project.node.prop_repeat')) + } + } + } + }, + { + type: 'input', + field: 'value', + span: 10, + props: { + placeholder: t('project.node.value_tips'), + maxLength: 256 + } + } + ] + }, + { + type: 'select', + field: 'xms', + name: t('project.node.datax_job_runtime_memory_xms'), + span: 12, + options: memoryLimitOptions, + value: 1 + }, + { + type: 'select', + field: 'xmx', + name: t('project.node.datax_job_runtime_memory_xmx'), + span: 12, + options: memoryLimitOptions, + value: 1 + } + ] +} diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-environment-name.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-environment-name.ts index 5a2c2a0ddd..3cb6523ed0 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-environment-name.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/fields/use-environment-name.ts @@ -36,11 +36,13 @@ export function useEnvironmentName( loading.value = true try { const res = await queryAllEnvironmentList() - environmentList = res.map((item: { code: string; name: string; workerGroups: string[] }) => ({ - label: item.name, - value: item.code, - workerGroups: item.workerGroups - })) + environmentList = res.map( + (item: { code: string; name: string; workerGroups: string[] }) => ({ + label: item.name, + value: item.code, + workerGroups: item.workerGroups + }) + ) options.value = environmentList.filter((option: IEnvironmentNameOption) => filterByWorkerGroup(option) ) diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts index 331eea90e6..a270c94ffd 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/format-data.ts @@ -21,7 +21,8 @@ import type { ITaskData, ITaskParams, ISqoopTargetParams, - ISqoopSourceParams + ISqoopSourceParams, + ILocalParam } from './types' export function formatParams(data: INodeData): { @@ -204,6 +205,30 @@ export function formatParams(data: INodeData): { } } + if (data.taskType === 'DATAX') { + taskParams.customConfig = data.customConfig + if (taskParams.customConfig === 0) { + taskParams.dsType = data.dsType + taskParams.dataSource = data.dataSource + taskParams.dtType = data.dtType + taskParams.dataTarget = data.dataTarget + taskParams.sql = data.sql + taskParams.targetTable = data.targetTable + taskParams.jobSpeedByte = data.jobSpeedByte + taskParams.jobSpeedRecord = data.jobSpeedRecord + taskParams.preStatements = data.preStatements + taskParams.postStatements = data.postStatements + } else { + taskParams.json = data.json + data?.localParams?.map((param: ILocalParam) => { + param.direct = 'IN' + param.type = 'VARCHAR' + }) + } + taskParams.xms = data.xms + taskParams.xmx = data.xmx + } + const params = { processDefinitionCode: data.processName ? String(data.processName) : '', upstreamCodes: data?.preTasks?.join(','), diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-datax.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-datax.ts new file mode 100644 index 0000000000..3d0f59a2c6 --- /dev/null +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/tasks/use-datax.ts @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { reactive } from 'vue' +import * as Fields from '../fields/index' +import type { IJsonItem, INodeData } from '../types' +import { ITaskData } from '../types' + +export function useDataX({ + projectCode, + from = 0, + readonly, + data +}: { + projectCode: number + from?: number + readonly?: boolean + data?: ITaskData +}) { + const model = reactive({ + name: '', + taskType: 'DATAX', + flag: 'YES', + description: '', + timeoutFlag: false, + localParams: [], + environmentCode: null, + failRetryInterval: 1, + failRetryTimes: 0, + workerGroup: 'default', + delayTime: 0, + timeout: 30, + customConfig: data?.taskParams?.customConfig + ? data?.taskParams?.customConfig + : 0, + customConfigSwitch: data?.taskParams?.customConfig !== 0, + dsType: data?.taskParams?.dsType ? data?.taskParams?.dsType : 'MYSQL', + dataSource: data?.taskParams?.dataSource, + dtType: data?.taskParams?.dtType ? data?.taskParams?.dtType : 'MYSQL', + dataTarget: data?.taskParams?.dataTarget, + sql: data?.taskParams?.sql, + targetTable: data?.taskParams?.targetTable, + preStatements: data?.taskParams?.preStatements + ? data?.taskParams?.preStatements + : [], + postStatements: data?.taskParams?.postStatements + ? data?.taskParams?.postStatements + : [], + jobSpeedByte: data?.taskParams?.jobSpeedByte, + jobSpeedRecord: data?.taskParams?.jobSpeedRecord, + xms: data?.taskParams?.xms, + xmx: data?.taskParams?.xmx + } as INodeData) + + let extra: IJsonItem[] = [] + if (from === 1) { + extra = [ + Fields.useTaskType(model, readonly), + Fields.useProcessName({ + model, + projectCode, + isCreate: !data?.id, + from, + processName: data?.processName, + code: data?.code + }) + ] + } + + return { + json: [ + Fields.useName(), + ...extra, + Fields.useRunFlag(), + Fields.useDescription(), + Fields.useTaskPriority(), + Fields.useWorkerGroup(), + Fields.useEnvironmentName(model, !model.id), + ...Fields.useTaskGroup(model, projectCode), + ...Fields.useFailed(), + Fields.useDelayTime(model), + ...Fields.useTimeoutAlarm(model), + ...Fields.useDataX(model), + Fields.usePreTasks(model) + ] as IJsonItem[], + model + } +} diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts index 5e5fffed00..d508c518eb 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/types.ts @@ -206,6 +206,17 @@ interface ITaskParams { relation?: RelationType dependTaskList?: IDependTask[] } + customConfig?: number + json?: string + dsType?: string + dataSource?: number + dtType?: string + dataTarget?: number + targetTable?: string + jobSpeedByte?: number + jobSpeedRecord?: number + xms?: number + xmx?: number } interface INodeData diff --git a/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts b/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts index 95d6f1f914..3531ea8dad 100644 --- a/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts +++ b/dolphinscheduler-ui-next/src/views/projects/task/components/node/use-task.ts @@ -29,6 +29,7 @@ import { useSqoop } from './tasks/use-sqoop' import { useSeaTunnel } from './tasks/use-sea-tunnel' import { useSwitch } from './tasks/use-switch' import { useConditions } from './tasks/use-conditions' +import { useDataX } from './tasks/use-datax' import { IJsonItem, INodeData, ITaskData } from './types' export function useTask({ @@ -159,5 +160,14 @@ export function useTask({ }) } + if (taskType === 'DATAX') { + node = useDataX({ + projectCode, + from, + readonly, + data + }) + } + return node } diff --git a/dolphinscheduler-ui-next/src/views/resource/file/edit/index.tsx b/dolphinscheduler-ui-next/src/views/resource/file/edit/index.tsx index a6317d7bd8..6b4d5efd3e 100644 --- a/dolphinscheduler-ui-next/src/views/resource/file/edit/index.tsx +++ b/dolphinscheduler-ui-next/src/views/resource/file/edit/index.tsx @@ -75,10 +75,10 @@ export default defineComponent({ class={styles['form-content']} > -
- +
+
{this.routeNameRef === 'resource-file-edit' && (