From a7609c832f5b88df3065e24a25451af6925fb53f Mon Sep 17 00:00:00 2001 From: Austin <1344583166@qq.com> Date: Fri, 6 Sep 2024 17:25:33 +0800 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20mysql=E3=80=81spider=E5=BA=93?= =?UTF-8?q?=E8=A1=A8=E6=A0=A1=E9=AA=8C=E8=A7=84=E5=88=99=E8=B0=83=E6=95=B4?= =?UTF-8?q?=20#6595=20#=20Reviewed,=20transaction=20id:=2017612?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/batch-edit-column/Index.vue | 13 +- .../columns/db-table-name/Index.vue | 51 ++- dbm-ui/frontend/src/locales/zh-cn.json | 5 + dbm-ui/frontend/src/services/source/user.ts | 1 + .../list/components/hooks/useBaseDetails.ts | 2 +- .../RenderData/RenderDbName.vue | 57 ++- .../RenderData/RenderIgnoreDbName.vue | 59 --- .../execute-objects/RenderData/Row.vue | 6 +- .../pages/page1/components/RenderData/Row.vue | 7 +- .../views/mysql/common/edit-field/DbName.vue | 33 +- .../mysql/common/edit-field/TableName.vue | 23 +- .../page1/components/RenderData/Index.vue | 6 +- .../pages/page1/components/RenderData/Row.vue | 16 +- .../page1/components/RenderData/Index.vue | 6 +- .../pages/page1/components/RenderData/Row.vue | 14 +- .../components/batch-edit-common/Index.vue | 24 +- .../batch-edit-common/MultipleInput.vue | 6 + .../page1/components/RenderData/Index.vue | 6 +- .../pages/page1/components/RenderData/Row.vue | 14 +- .../render-data/exist-cluster/Row.vue | 2 + .../render-data/new-cluster/Row.vue | 2 + .../pages/page1/components/RenderData/Row.vue | 7 +- .../page1/components/RenderData/Index.vue | 6 +- .../pages/page1/components/RenderData/Row.vue | 16 +- .../page1/components/RenderData/Index.vue | 12 +- .../pages/page1/components/RenderData/Row.vue | 14 +- .../page1/components/RenderData/Index.vue | 10 +- .../pages/page1/components/RenderData/Row.vue | 16 +- .../render-data/exist-cluster/Row.vue | 2 + .../render-data/new-cluster/Row.vue | 2 + .../steps/step1/components/ExecuteMode.vue | 193 --------- .../steps/step1/components/TargetCluster.vue | 215 --------- .../steps/step1/components/TaskTips.vue | 150 ------- .../steps/step1/components/backup/Index.vue | 108 ----- .../components/backup/RenderData/Index.vue | 42 -- .../backup/RenderData/RenderBackupSource.vue | 74 ---- .../components/backup/RenderData/Row.vue | 137 ------ .../steps/step1/components/sql-file/Index.vue | 111 ----- .../components/sql-file/editor/Index.vue | 235 ---------- .../sql-file/editor/MessageList.vue | 181 -------- .../components/sql-file/local-file/Index.vue | 410 ------------------ .../sql-file/local-file/SqlFileList.vue | 164 ------- .../local-file/components/CheckError.vue | 51 --- .../local-file/components/CheckSuccess.vue | 40 -- .../local-file/components/FileList.vue | 288 ------------ .../sql-file/manual-input/Index.vue | 227 ---------- .../components/SyntaxChecking.vue | 38 -- .../manual-input/components/SyntaxError.vue | 36 -- .../manual-input/components/SyntaxSuccess.vue | 36 -- .../steps/step1/components/sql-file/utils.ts | 14 - .../step1/components/target-db/Index.vue | 96 ---- .../components/target-db/RenderData/Index.vue | 42 -- .../target-db/RenderData/RenderDbName.vue | 77 ---- .../components/target-db/RenderData/Row.vue | 118 ----- .../components/MemberSelector.vue | 2 +- .../demand-factory/mysql/Flashback.vue | 56 +-- .../demand-factory/mysql/HATruncate.vue | 56 +-- .../demand-factory/mysql/TableBackup.vue | 80 ++-- .../demand-factory/spider/Flashback.vue | 8 +- .../demand-factory/spider/TableBackup.vue | 8 +- 60 files changed, 378 insertions(+), 3353 deletions(-) delete mode 100644 dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderIgnoreDbName.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/ExecuteMode.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/TargetCluster.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/TaskTips.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/backup/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/backup/RenderData/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/backup/RenderData/RenderBackupSource.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/backup/RenderData/Row.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/editor/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/editor/MessageList.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/local-file/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/local-file/SqlFileList.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/local-file/components/CheckError.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/local-file/components/CheckSuccess.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/local-file/components/FileList.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/manual-input/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/manual-input/components/SyntaxChecking.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/manual-input/components/SyntaxError.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/manual-input/components/SyntaxSuccess.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/sql-file/utils.ts delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/target-db/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/target-db/RenderData/Index.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/target-db/RenderData/RenderDbName.vue delete mode 100644 dbm-ui/frontend/src/views/spider-manage/sql-execute/steps/step1/components/target-db/RenderData/Row.vue diff --git a/dbm-ui/frontend/src/components/batch-edit-column/Index.vue b/dbm-ui/frontend/src/components/batch-edit-column/Index.vue index 8be2d36bf2..39b6630cd9 100644 --- a/dbm-ui/frontend/src/components/batch-edit-column/Index.vue +++ b/dbm-ui/frontend/src/components/batch-edit-column/Index.vue @@ -3,6 +3,7 @@ :is-show="isShow" trigger="manual" width="395" + @after-show="handleAfterShow" @cancel="() => (isShow = false)" @confirm="handleConfirm"> @@ -26,6 +27,7 @@ :list="dataList" /> (), { + const props = withDefaults(defineProps(), { dataList: () => [], type: 'select', placeholder: '', @@ -68,12 +70,21 @@ const { t } = useI18n(); + const inputRef = ref(); const localValue = ref(''); const handleConfirm = () => { emits('change', localValue.value); isShow.value = false; }; + + const handleAfterShow = () => { + if (props.type === 'textarea') { + nextTick(() => { + inputRef.value?.focus(); + }); + } + }; diff --git a/dbm-ui/frontend/src/locales/zh-cn.json b/dbm-ui/frontend/src/locales/zh-cn.json index 52381a4115..127688d41c 100644 --- a/dbm-ui/frontend/src/locales/zh-cn.json +++ b/dbm-ui/frontend/src/locales/zh-cn.json @@ -3298,5 +3298,10 @@ "按Enter或失焦可完成内容输入": "按 Enter 或失焦可完成内容输入", "粘贴多个对象可用换行,空格或;,|分隔": "粘贴多个对象可用换行,空格或;,|分隔", "RedisCluster集群": "RedisCluster 集群", + "% 或 ? 不允许单独使用": "% 或 ? 不允许单独使用", + "不允许为 *": "不允许为 *", + "库表名支持数字、字母、中划线、下划线,最大35字符": "库表名支持数字、字母、中划线、下划线,最大35字符", + "不允许输入系统库和特殊库": "不允许输入系统库和特殊库", + "不能以stage_truncate开头或dba_rollback结尾": "不能以 stage_truncate 开头或 dba_rollback 结尾", "这行勿动!新增翻译请在上一行添加!": "" } diff --git a/dbm-ui/frontend/src/services/source/user.ts b/dbm-ui/frontend/src/services/source/user.ts index dd7c86f3b1..5930d6a5e8 100644 --- a/dbm-ui/frontend/src/services/source/user.ts +++ b/dbm-ui/frontend/src/services/source/user.ts @@ -24,6 +24,7 @@ export function getUserList( limit?: number; offset?: number; fuzzy_lookups?: string; + exact_lookups?: string; } = {}, ) { return http.get< diff --git a/dbm-ui/frontend/src/views/db-configure/business/list/components/hooks/useBaseDetails.ts b/dbm-ui/frontend/src/views/db-configure/business/list/components/hooks/useBaseDetails.ts index d05d2b3f1e..851d06f649 100644 --- a/dbm-ui/frontend/src/views/db-configure/business/list/components/hooks/useBaseDetails.ts +++ b/dbm-ui/frontend/src/views/db-configure/business/list/components/hooks/useBaseDetails.ts @@ -63,7 +63,7 @@ export const useBaseDetails = (immediateFetch = true) => { const treeNode = inject>('treeNode'); const route = useRoute(); - const clusterType = computed(() => route.params.clusterType as ClusterTypes); + const clusterType = computed(() => (route.params.clusterType as ClusterTypes) || ClusterTypes.TENDBSINGLE); const dbType = computed(() => clusterTypeInfos[clusterType.value].dbType); const state = reactive({ loading: false, diff --git a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderDbName.vue b/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderDbName.vue index 1759be213f..6c71446a04 100644 --- a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderDbName.vue +++ b/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderDbName.vue @@ -30,10 +30,18 @@ import { makeMap, random } from '@utils'; + interface Props { + checkDuplicate?: boolean; + } + interface Exposes { getValue: () => Promise; } + const props = withDefaults(defineProps(), { + checkDuplicate: false, + }); + const modelValue = defineModel({ default: () => [], }); @@ -45,20 +53,24 @@ const editTagRef = ref>(); + const systemDbNames = ['mysql', 'db_infobase', 'information_schema', 'performance_schema', 'sys', 'infodba_schema']; + const rules = [ { - validator: (value: string[]) => { - tagMemo[instanceKey] = value; - return value && value.length > 0; - }, - message: t('DB名不能为空'), + validator: (value: string[]) => value && value.length > 0, + message: t('DB 名不能为空'), }, { - validator: (value: string[]) => { - const hasAllMatch = _.find(value, (item) => /%$/.test(item)); - return !(value.length > 1 && hasAllMatch); - }, - message: t('一格仅支持单个_对象'), + validator: (value: string[]) => _.every(value, (item) => /^(?!stage_truncate)(?!.*dba_rollback$).*/.test(item)), + message: t('不能以stage_truncate开头或dba_rollback结尾'), + }, + { + validator: (value: string[]) => _.every(value, (item) => /^[-_a-zA-Z0-9*?%]{0,35}$/.test(item)), + message: t('库表名支持数字、字母、中划线、下划线,最大35字符'), + }, + { + validator: (value: string[]) => _.every(value, (item) => !systemDbNames.includes(item)), + message: t('不允许输入系统库和特殊库'), }, { validator: (value: string[]) => @@ -66,11 +78,24 @@ message: t('* 只能独立使用'), }, { - validator: (value: string[]) => _.every(value, (item) => !/^%$/.test(item)), - message: t('% 不允许单独使用'), + validator: (value: string[]) => _.every(value, (item) => !/^[%?]$/.test(item)), + message: t('% 或 ? 不允许单独使用'), }, { validator: (value: string[]) => { + if (_.some(value, (item) => /[*%?]/.test(item))) { + return value.length < 2; + } + return true; + }, + message: t('含通配符的单元格仅支持输入单个对象'), + }, + { + validator: (value: string[]) => { + if (!props.checkDuplicate) { + return true; + } + const otherTagMap = { ...tagMemo }; delete otherTagMap[instanceKey]; @@ -84,7 +109,9 @@ watch( modelValue, () => { - tagMemo[instanceKey] = modelValue.value; + if (props.checkDuplicate) { + tagMemo[instanceKey] = modelValue.value; + } }, { immediate: true, @@ -93,7 +120,9 @@ const handleChange = (value: string[]) => { modelValue.value = value; - tagMemo[instanceKey] = value; + if (props.checkDuplicate) { + tagMemo[instanceKey] = value; + } }; onBeforeUnmount(() => { diff --git a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderIgnoreDbName.vue b/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderIgnoreDbName.vue deleted file mode 100644 index 5fb608e131..0000000000 --- a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/RenderIgnoreDbName.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - - diff --git a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/Row.vue b/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/Row.vue index ea46f991ac..6936ec1317 100644 --- a/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/Row.vue +++ b/dbm-ui/frontend/src/views/db-manage/common/sql-execute/execute-objects/RenderData/Row.vue @@ -17,10 +17,11 @@ + v-model="localDbnames" + check-duplicate /> - @@ -51,7 +52,6 @@ import { random } from '@utils'; import RenderDbName from './RenderDbName.vue'; - import RenderIgnoreDbName from './RenderIgnoreDbName.vue'; import RenderSql from './RenderSql/Index.vue'; export interface IDataRow { diff --git a/dbm-ui/frontend/src/views/mysql/checksum/pages/page1/components/RenderData/Row.vue b/dbm-ui/frontend/src/views/mysql/checksum/pages/page1/components/RenderData/Row.vue index 8a28fa2044..2e56f919c6 100644 --- a/dbm-ui/frontend/src/views/mysql/checksum/pages/page1/components/RenderData/Row.vue +++ b/dbm-ui/frontend/src/views/mysql/checksum/pages/page1/components/RenderData/Row.vue @@ -40,6 +40,7 @@ - boolean; message: string; @@ -59,6 +60,7 @@ remoteExist: false, checkExist: false, rules: undefined, + allowAsterisk: true, }); const emits = defineEmits(); @@ -73,6 +75,8 @@ return props.rules; } + const systemDbNames = ['mysql', 'db_infobase', 'information_schema', 'performance_schema', 'sys', 'infodba_schema']; + return [ { validator: (value: string[]) => { @@ -83,16 +87,36 @@ }, message: t('DB 名不能为空'), }, + { + validator: (value: string[]) => _.every(value, (item) => /^(?!stage_truncate)(?!.*dba_rollback$).*/.test(item)), + message: t('不能以stage_truncate开头或dba_rollback结尾'), + }, + { + validator: (value: string[]) => _.every(value, (item) => /^[-_a-zA-Z0-9*?%]{0,35}$/.test(item)), + message: t('库表名支持数字、字母、中划线、下划线,最大35字符'), + }, + { + validator: (value: string[]) => _.every(value, (item) => !systemDbNames.includes(item)), + message: t('不允许输入系统库和特殊库'), + }, + { + validator: (value: string[]) => { + if (props.allowAsterisk) { + return true; + } + + return _.every(value, (item) => item !== '*'); + }, + message: t('不允许为 *'), + }, { validator: (value: string[]) => !_.some(value, (item) => (/\*/.test(item) && item.length > 1) || (value.length > 1 && item === '*')), message: t('* 只能独立使用'), - trigger: 'change', }, { - validator: (value: string[]) => _.every(value, (item) => !/^%$/.test(item)), - message: t('% 不允许单独使用'), - trigger: 'change', + validator: (value: string[]) => _.every(value, (item) => !/^[%?]$/.test(item)), + message: t('% 或 ? 不允许单独使用'), }, { validator: (value: string[]) => { @@ -102,7 +126,6 @@ return true; }, message: t('含通配符的单元格仅支持输入单个对象'), - trigger: 'change', }, { validator: (value: string[]) => { diff --git a/dbm-ui/frontend/src/views/mysql/common/edit-field/TableName.vue b/dbm-ui/frontend/src/views/mysql/common/edit-field/TableName.vue index 5589d6a83b..d5f68eb153 100644 --- a/dbm-ui/frontend/src/views/mysql/common/edit-field/TableName.vue +++ b/dbm-ui/frontend/src/views/mysql/common/edit-field/TableName.vue @@ -36,6 +36,7 @@ disabled?: boolean; required?: boolean; single?: boolean; + allowAsterisk?: boolean; // 是否允许单个 * rules?: { validator: (value: string[]) => boolean; message: string; @@ -59,6 +60,7 @@ single: false, rules: undefined, disabled: false, + allowAsterisk: true, }); const emits = defineEmits(); @@ -83,16 +85,28 @@ }, message: t('表名不能为空'), }, + { + validator: (value: string[]) => _.every(value, (item) => /^[-_a-zA-Z0-9*?%]{0,35}$/.test(item)), + message: t('库表名支持数字、字母、中划线、下划线,最大35字符'), + }, + { + validator: (value: string[]) => { + if (props.allowAsterisk) { + return true; + } + + return _.every(value, (item) => item !== '*'); + }, + message: t('不允许为 *'), + }, { validator: (value: string[]) => !_.some(value, (item) => (/\*/.test(item) && item.length > 1) || (value.length > 1 && item === '*')), message: t('* 只能独立使用'), - trigger: 'change', }, { - validator: (value: string[]) => _.every(value, (item) => !/^%$/.test(item)), - message: t('% 不允许单独使用'), - trigger: 'change', + validator: (value: string[]) => _.every(value, (item) => !/^[%?]$/.test(item)), + message: t('% 或 ? 不允许单独使用'), }, { validator: (value: string[]) => { @@ -102,7 +116,6 @@ return true; }, message: t('含通配符的单元格仅支持输入单个对象'), - trigger: 'change', }, // TODO: 表不存在 ]; diff --git a/dbm-ui/frontend/src/views/mysql/db-clear/pages/page1/components/RenderData/Index.vue b/dbm-ui/frontend/src/views/mysql/db-clear/pages/page1/components/RenderData/Index.vue index 0acad4fdaf..ad4c4e66ca 100644 --- a/dbm-ui/frontend/src/views/mysql/db-clear/pages/page1/components/RenderData/Index.vue +++ b/dbm-ui/frontend/src/views/mysql/db-clear/pages/page1/components/RenderData/Index.vue @@ -49,14 +49,14 @@ - {{ t('目标表名') }} + {{ t('忽略DB名') }} - {{ t('忽略DB名') }} + {{ t('目标表名') }} - - - + + + - {{ t('备份表名') }} + {{ t('忽略DB名') }} - {{ t('忽略DB名') }} + {{ t('备份表名') }} - - - + + + diff --git a/dbm-ui/frontend/src/views/mysql/dumper/components/create-rule/components/receiver-data/components/batch-edit-common/Index.vue b/dbm-ui/frontend/src/views/mysql/dumper/components/create-rule/components/receiver-data/components/batch-edit-common/Index.vue index fd84479e13..ed50ebcba4 100644 --- a/dbm-ui/frontend/src/views/mysql/dumper/components/create-rule/components/receiver-data/components/batch-edit-common/Index.vue +++ b/dbm-ui/frontend/src/views/mysql/dumper/components/create-rule/components/receiver-data/components/batch-edit-common/Index.vue @@ -2,6 +2,7 @@