mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-12-28 10:26:35 +08:00
feat: 数据库迁移至文件支持文件保存天数等
This commit is contained in:
@@ -15,7 +15,7 @@ const config = {
|
||||
baseWsUrl: `${(window as any).globalConfig.BaseWsUrl || `${location.protocol == 'https:' ? 'wss:' : 'ws:'}//${getBaseApiUrl()}`}/api`,
|
||||
|
||||
// 系统版本
|
||||
version: 'v1.8.9',
|
||||
version: 'v1.9.0',
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -1,152 +1,137 @@
|
||||
<template>
|
||||
<div class="db-transfer-edit">
|
||||
<el-dialog
|
||||
:title="title"
|
||||
v-model="dialogVisible"
|
||||
:before-close="cancel"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
width="850px"
|
||||
>
|
||||
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title" :back="cancel" />
|
||||
</template>
|
||||
|
||||
<el-form :model="form" ref="dbForm" :rules="rules" label-width="auto">
|
||||
<el-tabs v-model="tabActiveName">
|
||||
<el-tab-pane label="基本信息" :name="basicTab">
|
||||
<el-form-item>
|
||||
<el-row class="w100" style="padding-bottom: 20px">
|
||||
<el-col :span="18">
|
||||
<el-form-item prop="taskName" label="任务名" required>
|
||||
<el-input v-model.trim="form.taskName" placeholder="请输入任务名" auto-complete="off" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item prop="status" label="启用状态">
|
||||
<el-switch
|
||||
v-model="form.status"
|
||||
inline-prompt
|
||||
active-text="启用"
|
||||
inactive-text="禁用"
|
||||
:active-value="1"
|
||||
:inactive-value="-1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-divider content-position="left">基本信息</el-divider>
|
||||
|
||||
<el-form-item>
|
||||
<el-row class="w100" style="padding-bottom: 20px">
|
||||
<el-col :span="8">
|
||||
<el-form-item prop="cronAble" label="定时迁移" required>
|
||||
<el-radio-group v-model="form.cronAble">
|
||||
<el-radio label="是" :value="1" />
|
||||
<el-radio label="否" :value="-1" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="cron" label="cron" :required="form.cronAble == 1">
|
||||
<CrontabInput v-model="form.cron" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-form-item prop="taskName" label="任务名" required>
|
||||
<el-input v-model.trim="form.taskName" placeholder="请输入任务名" auto-complete="off" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="srcDbId" label="源数据库" required>
|
||||
<db-select-tree
|
||||
placeholder="请选择源数据库"
|
||||
v-model:db-id="form.srcDbId"
|
||||
v-model:inst-name="form.srcInstName"
|
||||
v-model:db-name="form.srcDbName"
|
||||
v-model:tag-path="form.srcTagPath"
|
||||
v-model:db-type="form.srcDbType"
|
||||
@select-db="onSelectSrcDb"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-row class="w100">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="status" label="启用状态">
|
||||
<el-switch v-model="form.status" inline-prompt active-text="启用" inactive-text="禁用" :active-value="1" :inactive-value="-1" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-form-item>
|
||||
<el-row class="w100">
|
||||
<el-col :span="13">
|
||||
<el-form-item prop="mode" label="迁移方式" required>
|
||||
<el-radio-group v-model="form.mode">
|
||||
<el-radio label="迁移到数据库" :value="1" />
|
||||
<el-radio label="迁移到文件(自动命名)" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="11">
|
||||
<el-form-item prop="strategy" label="迁移策略" required>
|
||||
<el-radio-group v-model="form.strategy">
|
||||
<el-radio label="全量" :value="1" />
|
||||
<el-radio label="增量(暂不可用)" :value="2" disabled />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="cronAble" label="定时迁移" required>
|
||||
<el-radio-group v-model="form.cronAble">
|
||||
<el-radio label="是" :value="1" />
|
||||
<el-radio label="否" :value="-1" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode === 2" prop="targetFileDbType" label="文件数据库类型" :required="form.mode === 2">
|
||||
<el-select style="width: 100%" v-model="form.targetFileDbType" placeholder="请选择数据库类型" clearable filterable>
|
||||
<el-option
|
||||
v-for="(dbTypeAndDialect, key) in getDbDialectMap()"
|
||||
:key="key"
|
||||
:value="dbTypeAndDialect[0]"
|
||||
:label="dbTypeAndDialect[1].getInfo().name"
|
||||
>
|
||||
<SvgIcon :name="dbTypeAndDialect[1].getInfo().icon" :size="20" />
|
||||
{{ dbTypeAndDialect[1].getInfo().name }}
|
||||
</el-option>
|
||||
<template #prefix>
|
||||
<SvgIcon :name="getDbDialect(form.targetFileDbType!).getInfo().icon" :size="20" />
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item prop="cron" label="cron" :required="form.cronAble == 1">
|
||||
<CrontabInput v-model="form.cron" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode == 1" prop="targetDbId" label="目标数据库" :required="form.mode === 1">
|
||||
<db-select-tree
|
||||
placeholder="请选择目标数据库"
|
||||
v-model:db-id="form.targetDbId"
|
||||
v-model:inst-name="form.targetInstName"
|
||||
v-model:db-name="form.targetDbName"
|
||||
v-model:tag-path="form.targetTagPath"
|
||||
v-model:db-type="form.targetDbType"
|
||||
@select-db="onSelectTargetDb"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="srcDbId" label="源数据库" class="w100" required>
|
||||
<db-select-tree
|
||||
placeholder="请选择源数据库"
|
||||
v-model:db-id="form.srcDbId"
|
||||
v-model:inst-name="form.srcInstName"
|
||||
v-model:db-name="form.srcDbName"
|
||||
v-model:tag-path="form.srcTagPath"
|
||||
v-model:db-type="form.srcDbType"
|
||||
@select-db="onSelectSrcDb"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="nameCase" label="转换表、字段名" required>
|
||||
<el-radio-group v-model="form.nameCase">
|
||||
<el-radio label="无" :value="1" />
|
||||
<el-radio label="大写" :value="2" />
|
||||
<el-radio label="小写" :value="3" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!--<el-form-item prop="deleteTable" label="创建前删除表" required>-->
|
||||
<!-- <el-radio-group v-model="form.deleteTable">-->
|
||||
<!-- <el-radio label="是" :value="1" />-->
|
||||
<!-- <el-radio label="否" :value="2" />-->
|
||||
<!-- </el-radio-group>-->
|
||||
<!--</el-form-item>-->
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="数据库对象" :name="tableTab" :disabled="!baseFieldCompleted">
|
||||
<el-form-item>
|
||||
<el-input v-model="state.filterSrcTableText" style="width: 240px" placeholder="过滤表" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-tree
|
||||
ref="srcTreeRef"
|
||||
style="width: 760px; max-height: 400px; overflow-y: auto"
|
||||
default-expand-all
|
||||
:expand-on-click-node="false"
|
||||
:data="state.srcTableTree"
|
||||
node-key="id"
|
||||
show-checkbox
|
||||
@check-change="handleSrcTableCheckChange"
|
||||
:filter-node-method="filterSrcTableTreeNode"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form-item prop="mode" label="迁移方式" required>
|
||||
<el-radio-group v-model="form.mode">
|
||||
<el-radio label="迁移到数据库" :value="1" />
|
||||
<el-radio label="迁移到文件(自动命名)" :value="2" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode === 2">
|
||||
<el-row class="w100">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="targetFileDbType" label="文件数据库类型" :required="form.mode === 2">
|
||||
<el-select v-model="form.targetFileDbType" placeholder="数据库类型" clearable filterable>
|
||||
<el-option
|
||||
v-for="(dbTypeAndDialect, key) in getDbDialectMap()"
|
||||
:key="key"
|
||||
:value="dbTypeAndDialect[0]"
|
||||
:label="dbTypeAndDialect[1].getInfo().name"
|
||||
>
|
||||
<SvgIcon :name="dbTypeAndDialect[1].getInfo().icon" :size="20" />
|
||||
{{ dbTypeAndDialect[1].getInfo().name }}
|
||||
</el-option>
|
||||
<template #prefix>
|
||||
<SvgIcon :name="getDbDialect(form.targetFileDbType!).getInfo().icon" :size="20" />
|
||||
</template>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="12">
|
||||
<el-form-item label="文件保留天数">
|
||||
<el-input-number v-model="form.fileSaveDays" :min="-1" :max="1000">
|
||||
<template #suffix>
|
||||
<span>天</span>
|
||||
</template>
|
||||
</el-input-number>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="strategy" label="迁移策略" required>
|
||||
<el-radio-group v-model="form.strategy">
|
||||
<el-radio label="全量" :value="1" />
|
||||
<el-radio label="增量(暂不可用)" :value="2" disabled />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="form.mode == 1" prop="targetDbId" label="目标数据库" class="w100" :required="form.mode === 1">
|
||||
<db-select-tree
|
||||
placeholder="请选择目标数据库"
|
||||
v-model:db-id="form.targetDbId"
|
||||
v-model:inst-name="form.targetInstName"
|
||||
v-model:db-name="form.targetDbName"
|
||||
v-model:tag-path="form.targetTagPath"
|
||||
v-model:db-type="form.targetDbType"
|
||||
@select-db="onSelectTargetDb"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="nameCase" label="转换表、字段名" required>
|
||||
<el-radio-group v-model="form.nameCase">
|
||||
<el-radio label="无" :value="1" />
|
||||
<el-radio label="大写" :value="2" />
|
||||
<el-radio label="小写" :value="3" />
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">数据库对象</el-divider>
|
||||
<el-form-item>
|
||||
<el-input v-model="state.filterSrcTableText" placeholder="过滤表" size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item class="w100">
|
||||
<el-tree
|
||||
ref="srcTreeRef"
|
||||
class="w100"
|
||||
style="max-height: 200px; overflow-y: auto"
|
||||
default-expand-all
|
||||
:expand-on-click-node="false"
|
||||
:data="state.srcTableTree"
|
||||
node-key="id"
|
||||
show-checkbox
|
||||
@check-change="handleSrcTableCheckChange"
|
||||
:filter-node-method="filterSrcTableTreeNode"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<template #footer>
|
||||
@@ -155,12 +140,12 @@
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, nextTick, reactive, ref, toRefs, watch } from 'vue';
|
||||
import { nextTick, reactive, ref, toRefs, watch } from 'vue';
|
||||
import { dbApi } from './api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import DbSelectTree from '@/views/ops/db/component/DbSelectTree.vue';
|
||||
@@ -168,6 +153,7 @@ import CrontabInput from '@/components/crontab/CrontabInput.vue';
|
||||
import { getDbDialect, getDbDialectMap } from '@/views/ops/db/dialect';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import _ from 'lodash';
|
||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
@@ -223,9 +209,6 @@ const rules = {
|
||||
|
||||
const dbForm: any = ref(null);
|
||||
|
||||
const basicTab = 'basic';
|
||||
const tableTab = 'table';
|
||||
|
||||
type FormData = {
|
||||
id?: number;
|
||||
taskName: string;
|
||||
@@ -234,6 +217,7 @@ type FormData = {
|
||||
cron: string;
|
||||
mode: 1 | 2;
|
||||
targetFileDbType?: string;
|
||||
fileSaveDays?: number;
|
||||
dbType: 1 | 2;
|
||||
srcDbId?: number;
|
||||
srcDbName?: string;
|
||||
@@ -270,7 +254,6 @@ const srcTableListDisabled = ref(false);
|
||||
const defaultKeys = ['tab-check', 'all', 'table-list'];
|
||||
|
||||
const state = reactive({
|
||||
tabActiveName: 'basic',
|
||||
form: basicFormData,
|
||||
submitForm: {} as any,
|
||||
srcTableFields: [] as string[],
|
||||
@@ -293,20 +276,14 @@ const state = reactive({
|
||||
],
|
||||
});
|
||||
|
||||
const { tabActiveName, form, submitForm } = toRefs(state);
|
||||
const { form, submitForm } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveExec } = dbApi.saveDbTransferTask.useApi(submitForm);
|
||||
|
||||
// 基础字段信息是否填写完整
|
||||
const baseFieldCompleted = computed(() => {
|
||||
return state.form.srcDbId && (state.form.targetDbId || state.form.targetFileDbType);
|
||||
});
|
||||
|
||||
watch(dialogVisible, async (newValue: boolean) => {
|
||||
if (!newValue) {
|
||||
return;
|
||||
}
|
||||
state.tabActiveName = 'basic';
|
||||
const propsData = props.data as any;
|
||||
if (!propsData?.id) {
|
||||
let d = {} as FormData;
|
||||
@@ -447,10 +424,4 @@ const cancel = () => {
|
||||
emit('cancel');
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.db-transfer-edit {
|
||||
.el-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss"></style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,46 +1,33 @@
|
||||
<template>
|
||||
<div class="sync-task-edit">
|
||||
<el-dialog
|
||||
:title="title"
|
||||
v-model="dialogVisible"
|
||||
:before-close="cancel"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
width="850px"
|
||||
>
|
||||
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="45%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="title" :back="cancel" />
|
||||
</template>
|
||||
|
||||
<el-form :model="form" ref="dbForm" :rules="rules" label-width="auto">
|
||||
<el-tabs v-model="tabActiveName" style="height: 450px">
|
||||
<el-tabs v-model="tabActiveName">
|
||||
<el-tab-pane label="基本信息" :name="basicTab">
|
||||
<el-form-item>
|
||||
<el-row>
|
||||
<el-col :span="11">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="taskName" label="任务名" required>
|
||||
<el-input v-model.trim="form.taskName" placeholder="请输入同步任务名" auto-complete="off" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="11">
|
||||
<el-col :span="12">
|
||||
<el-form-item prop="taskCron" label="cron" required>
|
||||
<CrontabInput v-model="form.taskCron" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="2">
|
||||
<el-form-item prop="status" label="状态" label-width="60" required>
|
||||
<el-switch
|
||||
v-model="form.status"
|
||||
inline-prompt
|
||||
active-text="启用"
|
||||
inactive-text="禁用"
|
||||
:active-value="1"
|
||||
:inactive-value="-1"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="status" label="状态" label-width="60" required>
|
||||
<el-switch v-model="form.status" inline-prompt active-text="启用" inactive-text="禁用" :active-value="1" :inactive-value="-1" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item prop="srcDbId" label="源数据库" required>
|
||||
<db-select-tree
|
||||
placeholder="请选择源数据库"
|
||||
@@ -220,7 +207,18 @@
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</el-drawer>
|
||||
|
||||
<!-- <el-dialog
|
||||
:title="title"
|
||||
v-model="dialogVisible"
|
||||
:before-close="cancel"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
width="850px"
|
||||
>
|
||||
</el-dialog> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -233,6 +231,7 @@ import MonacoEditor from '@/components/monaco/MonacoEditor.vue';
|
||||
import { DbInst, registerDbCompletionItemProvider } from '@/views/ops/db/db';
|
||||
import { compatibleDuplicateStrategy, DbType, DuplicateStrategy, getDbDialect } from '@/views/ops/db/dialect';
|
||||
import CrontabInput from '@/components/crontab/CrontabInput.vue';
|
||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
|
||||
@@ -10,46 +10,46 @@ import {
|
||||
RowDefinition,
|
||||
sqlColumnType,
|
||||
} from './index';
|
||||
import {DbInst} from '@/views/ops/db/db';
|
||||
import {language as sqlLanguage} from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
|
||||
import { DbInst } from '@/views/ops/db/db';
|
||||
import { language as sqlLanguage } from 'monaco-editor/esm/vs/basic-languages/sql/sql.js';
|
||||
|
||||
export {SqliteDialect};
|
||||
export { SqliteDialect };
|
||||
|
||||
// 参考官方文档:https://www.sqlite.org/datatype3.html
|
||||
const SQLITE_TYPE_LIST: sqlColumnType[] = [
|
||||
// INTEGER
|
||||
{udtName: 'int', dataType: 'int', desc: '', space: '', range: ''},
|
||||
{udtName: 'integer', dataType: 'integer', desc: '', space: '', range: ''},
|
||||
{udtName: 'tinyint', dataType: 'tinyint', desc: '', space: '', range: ''},
|
||||
{udtName: 'smallint', dataType: 'smallint', desc: '', space: '', range: ''},
|
||||
{udtName: 'mediumint', dataType: 'mediumint', desc: '', space: '', range: ''},
|
||||
{udtName: 'bigint', dataType: 'bigint', desc: '', space: '', range: ''},
|
||||
{udtName: 'unsigned big int', dataType: 'unsigned big int', desc: '', space: '', range: ''},
|
||||
{udtName: 'int2', dataType: 'int2', desc: '', space: '', range: ''},
|
||||
{udtName: 'int8', dataType: 'int8', desc: '', space: '', range: ''},
|
||||
{ udtName: 'int', dataType: 'int', desc: '', space: '', range: '' },
|
||||
{ udtName: 'integer', dataType: 'integer', desc: '', space: '', range: '' },
|
||||
{ udtName: 'tinyint', dataType: 'tinyint', desc: '', space: '', range: '' },
|
||||
{ udtName: 'smallint', dataType: 'smallint', desc: '', space: '', range: '' },
|
||||
{ udtName: 'mediumint', dataType: 'mediumint', desc: '', space: '', range: '' },
|
||||
{ udtName: 'bigint', dataType: 'bigint', desc: '', space: '', range: '' },
|
||||
{ udtName: 'unsigned big int', dataType: 'unsigned big int', desc: '', space: '', range: '' },
|
||||
{ udtName: 'int2', dataType: 'int2', desc: '', space: '', range: '' },
|
||||
{ udtName: 'int8', dataType: 'int8', desc: '', space: '', range: '' },
|
||||
// TEXT
|
||||
{udtName: 'character', dataType: 'character', desc: '', space: '', range: ''},
|
||||
{udtName: 'varchar', dataType: 'varchar', desc: '', space: '', range: ''},
|
||||
{udtName: 'varying character', dataType: 'varying character', desc: '', space: '', range: ''},
|
||||
{udtName: 'nchar', dataType: 'nchar', desc: '', space: '', range: ''},
|
||||
{udtName: 'native character', dataType: 'native character', desc: '', space: '', range: ''},
|
||||
{udtName: 'nvarchar', dataType: 'nvarchar', desc: '', space: '', range: ''},
|
||||
{udtName: 'text', dataType: 'text', desc: '', space: '', range: ''},
|
||||
{udtName: 'clob', dataType: 'clob', desc: '', space: '', range: ''},
|
||||
{ udtName: 'character', dataType: 'character', desc: '', space: '', range: '' },
|
||||
{ udtName: 'varchar', dataType: 'varchar', desc: '', space: '', range: '' },
|
||||
{ udtName: 'varying character', dataType: 'varying character', desc: '', space: '', range: '' },
|
||||
{ udtName: 'nchar', dataType: 'nchar', desc: '', space: '', range: '' },
|
||||
{ udtName: 'native character', dataType: 'native character', desc: '', space: '', range: '' },
|
||||
{ udtName: 'nvarchar', dataType: 'nvarchar', desc: '', space: '', range: '' },
|
||||
{ udtName: 'text', dataType: 'text', desc: '', space: '', range: '' },
|
||||
{ udtName: 'clob', dataType: 'clob', desc: '', space: '', range: '' },
|
||||
// blob
|
||||
{udtName: 'blob', dataType: 'blob', desc: '', space: '', range: ''},
|
||||
{udtName: 'no datatype specified', dataType: 'no datatype specified', desc: '', space: '', range: ''},
|
||||
{ udtName: 'blob', dataType: 'blob', desc: '', space: '', range: '' },
|
||||
{ udtName: 'no datatype specified', dataType: 'no datatype specified', desc: '', space: '', range: '' },
|
||||
// REAL
|
||||
{udtName: 'real', dataType: 'real', desc: '', space: '', range: ''},
|
||||
{udtName: 'double', dataType: 'double', desc: '', space: '', range: ''},
|
||||
{udtName: 'double precision', dataType: 'double precision', desc: '', space: '', range: ''},
|
||||
{udtName: 'float', dataType: 'float', desc: '', space: '', range: ''},
|
||||
{ udtName: 'real', dataType: 'real', desc: '', space: '', range: '' },
|
||||
{ udtName: 'double', dataType: 'double', desc: '', space: '', range: '' },
|
||||
{ udtName: 'double precision', dataType: 'double precision', desc: '', space: '', range: '' },
|
||||
{ udtName: 'float', dataType: 'float', desc: '', space: '', range: '' },
|
||||
// NUMERIC
|
||||
{udtName: 'numeric', dataType: 'numeric', desc: '', space: '', range: ''},
|
||||
{udtName: 'decimal', dataType: 'decimal', desc: '', space: '', range: ''},
|
||||
{udtName: 'boolean', dataType: 'boolean', desc: '', space: '', range: ''},
|
||||
{udtName: 'date', dataType: 'date', desc: '', space: '', range: ''},
|
||||
{udtName: 'datetime', dataType: 'datetime', desc: '', space: '', range: ''},
|
||||
{ udtName: 'numeric', dataType: 'numeric', desc: '', space: '', range: '' },
|
||||
{ udtName: 'decimal', dataType: 'decimal', desc: '', space: '', range: '' },
|
||||
{ udtName: 'boolean', dataType: 'boolean', desc: '', space: '', range: '' },
|
||||
{ udtName: 'date', dataType: 'date', desc: '', space: '', range: '' },
|
||||
{ udtName: 'datetime', dataType: 'datetime', desc: '', space: '', range: '' },
|
||||
];
|
||||
|
||||
const addCustomKeywords = ['PRAGMA', 'database_list', 'sqlite_master'];
|
||||
@@ -57,61 +57,61 @@ const addCustomKeywords = ['PRAGMA', 'database_list', 'sqlite_master'];
|
||||
// 参考官方文档:https://www.sqlite.org/lang_corefunc.html
|
||||
const functions: EditorCompletionItem[] = [
|
||||
// 字符函数
|
||||
{label: 'abs', insertText: 'abs(X)', description: '返回给定数值的绝对值'},
|
||||
{label: 'changes', insertText: 'changes()', description: '返回最近增删改影响的行数'},
|
||||
{label: 'coalesce', insertText: 'coalesce(X,Y,...)', description: '返回第一个不为空的值'},
|
||||
{label: 'hex', insertText: 'hex(X)', description: '返回给定字符的hex值'},
|
||||
{label: 'ifnull', insertText: 'ifnull(X,Y)', description: '返回第一个不为空的值'},
|
||||
{label: 'iif', insertText: 'iif(X,Y,Z)', description: '如果x为真则返回y,否则返回z'},
|
||||
{label: 'instr', insertText: 'instr(X,Y)', description: '返回字符y在x的第n个位置'},
|
||||
{label: 'length', insertText: 'length(X)', description: '返回给定字符的长度'},
|
||||
{label: 'load_extension', insertText: 'load_extension(X[,Y])', description: '加载扩展块'},
|
||||
{label: 'lower', insertText: 'lower(X)', description: '返回小写字符'},
|
||||
{label: 'ltrim', insertText: 'ltrim(X[,Y])', description: '左trim'},
|
||||
{label: 'nullif', insertText: 'nullif(X,Y)', description: '比较两值相等则返回null,否则返回第一个值'},
|
||||
{label: 'printf', insertText: "printf('%s',...)", description: '字符串格式化拼接,如%s %d'},
|
||||
{label: 'quote', insertText: 'quote(X)', description: '把字符串用引号包起来'},
|
||||
{label: 'random', insertText: 'random()', description: '生成随机数'},
|
||||
{label: 'randomblob', insertText: 'randomblob(N)', description: '生成一个包含N个随机字节的BLOB'},
|
||||
{label: 'replace', insertText: 'replace(X,Y,Z)', description: '替换字符串'},
|
||||
{label: 'round', insertText: 'round(X[,Y])', description: '将数值四舍五入到指定的小数位数'},
|
||||
{label: 'rtrim', insertText: 'rtrim(X[,Y])', description: '右trim'},
|
||||
{label: 'sign', insertText: 'sign(X)', description: '返回数字符号 1正 -1负 0零 null'},
|
||||
{label: 'soundex', insertText: 'soundex(X)', description: '返回字符串X的soundex编码字符串'},
|
||||
{label: 'sqlite_compileoption_get', insertText: 'sqlite_compileoption_get(N)', description: '获取指定编译选项的值'},
|
||||
{ label: 'abs', insertText: 'abs(X)', description: '返回给定数值的绝对值' },
|
||||
{ label: 'changes', insertText: 'changes()', description: '返回最近增删改影响的行数' },
|
||||
{ label: 'coalesce', insertText: 'coalesce(X,Y,...)', description: '返回第一个不为空的值' },
|
||||
{ label: 'hex', insertText: 'hex(X)', description: '返回给定字符的hex值' },
|
||||
{ label: 'ifnull', insertText: 'ifnull(X,Y)', description: '返回第一个不为空的值' },
|
||||
{ label: 'iif', insertText: 'iif(X,Y,Z)', description: '如果x为真则返回y,否则返回z' },
|
||||
{ label: 'instr', insertText: 'instr(X,Y)', description: '返回字符y在x的第n个位置' },
|
||||
{ label: 'length', insertText: 'length(X)', description: '返回给定字符的长度' },
|
||||
{ label: 'load_extension', insertText: 'load_extension(X[,Y])', description: '加载扩展块' },
|
||||
{ label: 'lower', insertText: 'lower(X)', description: '返回小写字符' },
|
||||
{ label: 'ltrim', insertText: 'ltrim(X[,Y])', description: '左trim' },
|
||||
{ label: 'nullif', insertText: 'nullif(X,Y)', description: '比较两值相等则返回null,否则返回第一个值' },
|
||||
{ label: 'printf', insertText: "printf('%s',...)", description: '字符串格式化拼接,如%s %d' },
|
||||
{ label: 'quote', insertText: 'quote(X)', description: '把字符串用引号包起来' },
|
||||
{ label: 'random', insertText: 'random()', description: '生成随机数' },
|
||||
{ label: 'randomblob', insertText: 'randomblob(N)', description: '生成一个包含N个随机字节的BLOB' },
|
||||
{ label: 'replace', insertText: 'replace(X,Y,Z)', description: '替换字符串' },
|
||||
{ label: 'round', insertText: 'round(X[,Y])', description: '将数值四舍五入到指定的小数位数' },
|
||||
{ label: 'rtrim', insertText: 'rtrim(X[,Y])', description: '右trim' },
|
||||
{ label: 'sign', insertText: 'sign(X)', description: '返回数字符号 1正 -1负 0零 null' },
|
||||
{ label: 'soundex', insertText: 'soundex(X)', description: '返回字符串X的soundex编码字符串' },
|
||||
{ label: 'sqlite_compileoption_get', insertText: 'sqlite_compileoption_get(N)', description: '获取指定编译选项的值' },
|
||||
{
|
||||
label: 'sqlite_compileoption_used',
|
||||
insertText: 'sqlite_compileoption_used(X)',
|
||||
description: '检查SQLite编译时是否使用了指定的编译选项'
|
||||
description: '检查SQLite编译时是否使用了指定的编译选项',
|
||||
},
|
||||
{label: 'sqlite_source_id', insertText: 'sqlite_source_id()', description: '获取sqlite源代码标识符'},
|
||||
{label: 'sqlite_version', insertText: 'sqlite_version()', description: '获取sqlite版本'},
|
||||
{label: 'substr', insertText: 'substr(X,Y[,Z])', description: '截取字符串'},
|
||||
{label: 'substring', insertText: 'substring(X,Y[,Z])', description: '截取字符串'},
|
||||
{label: 'trim', insertText: 'trim(X[,Y])', description: '去除给定字符串前后的字符,默认空格'},
|
||||
{label: 'typeof', insertText: 'typeof(X)', description: '返回X的基本类型:null,integer,real,text,blob'},
|
||||
{label: 'unicode', insertText: 'unicode(X)', description: '返回与字符串X的第一个字符相对应的数字unicode代码点'},
|
||||
{label: 'unlikely', insertText: 'unlikely(X)', description: '返回大写字符'},
|
||||
{label: 'upper', insertText: 'upper(X)', description: '返回由0x00的N个字节组成的BLOB'},
|
||||
{label: 'zeroblob', insertText: 'zeroblob(N)', description: '返回分组中的平均值'},
|
||||
{label: 'avg', insertText: 'avg(X)', description: '返回总条数'},
|
||||
{label: 'count', insertText: 'count(*)', description: '返回分组中用给定非空字符串连接的值'},
|
||||
{label: 'group_concat', insertText: 'group_concat(X[,Y])', description: '返回分组中最大值'},
|
||||
{label: 'max', insertText: 'max(X)', description: '返回分组中最小值'},
|
||||
{label: 'min', insertText: 'min(X)', description: '返回分组中非空值的总和。'},
|
||||
{label: 'sum', insertText: 'sum(X)', description: '返回分组中非空值的总和。'},
|
||||
{label: 'total', insertText: 'total(X)', description: '返回YYYY-MM-DD格式的字符串'},
|
||||
{label: 'date', insertText: 'date(time-value[, modifier, ...])', description: '返回HH:MM:SS格式的字符串'},
|
||||
{ label: 'sqlite_source_id', insertText: 'sqlite_source_id()', description: '获取sqlite源代码标识符' },
|
||||
{ label: 'sqlite_version', insertText: 'sqlite_version()', description: '获取sqlite版本' },
|
||||
{ label: 'substr', insertText: 'substr(X,Y[,Z])', description: '截取字符串' },
|
||||
{ label: 'substring', insertText: 'substring(X,Y[,Z])', description: '截取字符串' },
|
||||
{ label: 'trim', insertText: 'trim(X[,Y])', description: '去除给定字符串前后的字符,默认空格' },
|
||||
{ label: 'typeof', insertText: 'typeof(X)', description: '返回X的基本类型:null,integer,real,text,blob' },
|
||||
{ label: 'unicode', insertText: 'unicode(X)', description: '返回与字符串X的第一个字符相对应的数字unicode代码点' },
|
||||
{ label: 'unlikely', insertText: 'unlikely(X)', description: '返回大写字符' },
|
||||
{ label: 'upper', insertText: 'upper(X)', description: '返回由0x00的N个字节组成的BLOB' },
|
||||
{ label: 'zeroblob', insertText: 'zeroblob(N)', description: '返回分组中的平均值' },
|
||||
{ label: 'avg', insertText: 'avg(X)', description: '返回总条数' },
|
||||
{ label: 'count', insertText: 'count(*)', description: '返回分组中用给定非空字符串连接的值' },
|
||||
{ label: 'group_concat', insertText: 'group_concat(X[,Y])', description: '返回分组中最大值' },
|
||||
{ label: 'max', insertText: 'max(X)', description: '返回分组中最小值' },
|
||||
{ label: 'min', insertText: 'min(X)', description: '返回分组中非空值的总和。' },
|
||||
{ label: 'sum', insertText: 'sum(X)', description: '返回分组中非空值的总和。' },
|
||||
{ label: 'total', insertText: 'total(X)', description: '返回YYYY-MM-DD格式的字符串' },
|
||||
{ label: 'date', insertText: 'date(time-value[, modifier, ...])', description: '返回HH:MM:SS格式的字符串' },
|
||||
{
|
||||
label: 'time',
|
||||
insertText: 'time(time-value[, modifier, ...])',
|
||||
description: '将日期和时间字符串转换为特定的日期和时间格式'
|
||||
description: '将日期和时间字符串转换为特定的日期和时间格式',
|
||||
},
|
||||
{label: 'datetime', insertText: 'datetime(time-value[, modifier, ...])', description: '计算日期和时间的儒略日数'},
|
||||
{ label: 'datetime', insertText: 'datetime(time-value[, modifier, ...])', description: '计算日期和时间的儒略日数' },
|
||||
{
|
||||
label: 'julianday',
|
||||
insertText: 'julianday(time-value[, modifier, ...])',
|
||||
description: '将日期和时间格式化为指定的字符串'
|
||||
description: '将日期和时间格式化为指定的字符串',
|
||||
},
|
||||
];
|
||||
|
||||
@@ -123,17 +123,17 @@ class SqliteDialect implements DbDialect {
|
||||
return sqliteDialectInfo;
|
||||
}
|
||||
|
||||
let {keywords, operators, builtinVariables} = sqlLanguage;
|
||||
let { keywords, operators, builtinVariables } = sqlLanguage;
|
||||
|
||||
let editorCompletions: EditorCompletion = {
|
||||
keywords: keywords
|
||||
.filter((a: string) => addCustomKeywords.indexOf(a) === -1)
|
||||
.map((a: string): EditorCompletionItem => ({label: a, description: 'keyword'}))
|
||||
.concat(commonCustomKeywords.map((a): EditorCompletionItem => ({label: a, description: 'keyword'})))
|
||||
.concat(addCustomKeywords.map((a): EditorCompletionItem => ({label: a, description: 'keyword'}))),
|
||||
operators: operators.map((a: string): EditorCompletionItem => ({label: a, description: 'operator'})),
|
||||
.map((a: string): EditorCompletionItem => ({ label: a, description: 'keyword' }))
|
||||
.concat(commonCustomKeywords.map((a): EditorCompletionItem => ({ label: a, description: 'keyword' })))
|
||||
.concat(addCustomKeywords.map((a): EditorCompletionItem => ({ label: a, description: 'keyword' }))),
|
||||
operators: operators.map((a: string): EditorCompletionItem => ({ label: a, description: 'operator' })),
|
||||
functions,
|
||||
variables: builtinVariables.map((a: string): EditorCompletionItem => ({label: a, description: 'var'})),
|
||||
variables: builtinVariables.map((a: string): EditorCompletionItem => ({ label: a, description: 'var' })),
|
||||
};
|
||||
|
||||
sqliteDialectInfo = {
|
||||
@@ -149,10 +149,7 @@ class SqliteDialect implements DbDialect {
|
||||
|
||||
getDefaultSelectSql(db: string, table: string, condition: string, orderBy: string, pageNum: number, limit: number) {
|
||||
return `SELECT *
|
||||
FROM ${this.quoteIdentifier(table)} ${condition ? 'WHERE ' + condition : ''} ${orderBy ? orderBy : ''} ${this.getPageSql(
|
||||
pageNum,
|
||||
limit
|
||||
)};`;
|
||||
FROM ${this.quoteIdentifier(table)} ${condition ? 'WHERE ' + condition : ''} ${orderBy ? orderBy : ''} ${this.getPageSql(pageNum, limit)};`;
|
||||
}
|
||||
|
||||
getPageSql(pageNum: number, limit: number) {
|
||||
@@ -170,7 +167,7 @@ class SqliteDialect implements DbDialect {
|
||||
notNull: true,
|
||||
pri: true,
|
||||
auto_increment: true,
|
||||
remark: '主键ID'
|
||||
remark: '主键ID',
|
||||
},
|
||||
{
|
||||
name: 'creator_id',
|
||||
@@ -181,7 +178,7 @@ class SqliteDialect implements DbDialect {
|
||||
notNull: true,
|
||||
pri: false,
|
||||
auto_increment: false,
|
||||
remark: '创建人id'
|
||||
remark: '创建人id',
|
||||
},
|
||||
{
|
||||
name: 'creator',
|
||||
@@ -214,7 +211,7 @@ class SqliteDialect implements DbDialect {
|
||||
notNull: true,
|
||||
pri: false,
|
||||
auto_increment: false,
|
||||
remark: '修改人id'
|
||||
remark: '修改人id',
|
||||
},
|
||||
{
|
||||
name: 'updator',
|
||||
@@ -225,7 +222,7 @@ class SqliteDialect implements DbDialect {
|
||||
notNull: true,
|
||||
pri: false,
|
||||
auto_increment: false,
|
||||
remark: '修改姓名'
|
||||
remark: '修改姓名',
|
||||
},
|
||||
{
|
||||
name: 'update_time',
|
||||
@@ -299,11 +296,15 @@ class SqliteDialect implements DbDialect {
|
||||
return sql.join(';');
|
||||
}
|
||||
|
||||
getModifyColumnSql(tableData: any, tableName: string, changeData: {
|
||||
del: RowDefinition[];
|
||||
add: RowDefinition[];
|
||||
upd: RowDefinition[]
|
||||
}): string {
|
||||
getModifyColumnSql(
|
||||
tableData: any,
|
||||
tableName: string,
|
||||
changeData: {
|
||||
del: RowDefinition[];
|
||||
add: RowDefinition[];
|
||||
upd: RowDefinition[];
|
||||
}
|
||||
): string {
|
||||
// sqlite修改表结构需要先删除再创建
|
||||
|
||||
// 1.删除旧表索引 DROP INDEX "main"."aa";
|
||||
@@ -341,17 +342,15 @@ class SqliteDialect implements DbDialect {
|
||||
// 生成sql
|
||||
sql.push(
|
||||
`INSERT INTO ${this.quoteIdentifier(tableData.db)}.${this.quoteIdentifier(tableName)} (${insertFields.join(',')})
|
||||
SELECT ${queryFields.join(
|
||||
','
|
||||
)}
|
||||
SELECT ${queryFields.join(',')}
|
||||
FROM ${this.quoteIdentifier(tableData.db)}.${this.quoteIdentifier(oldTableName)}`
|
||||
);
|
||||
|
||||
// 5.创建索引
|
||||
tableData.indexs.res.forEach((a: any) => {
|
||||
a.indexName &&
|
||||
sql.push(
|
||||
`CREATE
|
||||
sql.push(
|
||||
`CREATE
|
||||
${a.unique ? 'UNIQUE' : ''} INDEX
|
||||
${this.quoteIdentifier(tableData.db)}
|
||||
.
|
||||
@@ -361,7 +360,7 @@ class SqliteDialect implements DbDialect {
|
||||
(
|
||||
${a.columnNames.join(',')}
|
||||
)`
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
return sql.join(';') + ';';
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
:before-close="cancelSaveTeam"
|
||||
:destroy-on-close="true"
|
||||
:close-on-click-modal="false"
|
||||
size="40%"
|
||||
>
|
||||
<template #header>
|
||||
<DrawerHeader :header="addTeamDialog.form.id ? '编辑团队' : '添加团队'" :back="cancelSaveTeam" />
|
||||
|
||||
@@ -8,6 +8,7 @@ type DbTransferTaskForm struct {
|
||||
Cron string `json:"cron"` // 定时任务cron表达式
|
||||
Mode int `binding:"required" json:"mode"` // 数据迁移方式,1、迁移到数据库 2、迁移到文件
|
||||
TargetFileDbType string `json:"targetFileDbType"` // 目标文件数据库类型
|
||||
FileSaveDays int `json:"fileSaveDays"` // 文件保存天数
|
||||
Status int `json:"status" form:"status"` // 启用状态 1启用 -1禁用
|
||||
|
||||
CheckedKeys string `binding:"required" json:"checkedKeys"` // 选中需要迁移的表
|
||||
|
||||
@@ -19,6 +19,7 @@ type DbTransferTaskListVO struct {
|
||||
Cron string `json:"cron"` // 定时任务cron表达式
|
||||
Mode int `json:"mode"` // 数据迁移方式,1、迁移到数据库 2、迁移到文件
|
||||
TargetFileDbType string `json:"targetFileDbType"` // 目标文件数据库类型
|
||||
FileSaveDays int `json:"fileSaveDays"` // 文件保存天数
|
||||
|
||||
CheckedKeys string `json:"checkedKeys"` // 选中需要迁移的表
|
||||
DeleteTable int `json:"deleteTable"` // 创建表前是否删除表
|
||||
|
||||
@@ -31,8 +31,10 @@ func Init() {
|
||||
//if err := GetDbBinlogApp().Init(); err != nil {
|
||||
// panic(fmt.Sprintf("初始化 DbBinlogApp 失败: %v", err))
|
||||
//}
|
||||
|
||||
GetDataSyncTaskApp().InitCronJob()
|
||||
GetDbTransferTaskApp().InitCronJob()
|
||||
GetDbTransferTaskApp().TimerDeleteTransferFile()
|
||||
InitDbFlowHandler()
|
||||
})()
|
||||
}
|
||||
@@ -56,6 +58,7 @@ func GetDbBinlogApp() *DbBinlogApp {
|
||||
func GetDataSyncTaskApp() DataSyncTask {
|
||||
return ioc.Get[DataSyncTask]("DbDataSyncTaskApp")
|
||||
}
|
||||
|
||||
func GetDbTransferTaskApp() DbTransferTask {
|
||||
return ioc.Get[DbTransferTask]("DbTransferTaskApp")
|
||||
}
|
||||
|
||||
@@ -53,6 +53,9 @@ type DbTransferTask interface {
|
||||
IsRunning(taskId uint64) bool
|
||||
|
||||
Stop(ctx context.Context, taskId uint64) error
|
||||
|
||||
// TimerDeleteTransferFile 定时删除迁移文件
|
||||
TimerDeleteTransferFile()
|
||||
}
|
||||
|
||||
type dbTransferAppImpl struct {
|
||||
@@ -80,6 +83,9 @@ func (app *dbTransferAppImpl) Save(ctx context.Context, taskEntity *entity.DbTra
|
||||
} else {
|
||||
err = app.UpdateById(ctx, taskEntity)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 视情况添加或删除任务
|
||||
task, err := app.GetById(taskEntity.Id)
|
||||
if err != nil {
|
||||
@@ -549,6 +555,29 @@ func (app *dbTransferAppImpl) transferIndex(_ context.Context, tableInfo dbi.Tab
|
||||
return targetDialect.CreateIndex(tableInfo, indexs)
|
||||
}
|
||||
|
||||
func (d *dbTransferAppImpl) TimerDeleteTransferFile() {
|
||||
logx.Debug("开始定时删除迁移文件...")
|
||||
scheduler.AddFun("@every 100m", func() {
|
||||
dts, err := d.ListByCond(model.NewCond().Eq("mode", entity.DbTransferTaskModeFile).Ge("file_save_days", 1))
|
||||
if err != nil {
|
||||
logx.Errorf("定时获取数据库迁移至文件任务失败: %s", err.Error())
|
||||
return
|
||||
}
|
||||
for _, dt := range dts {
|
||||
needDelFiles, err := d.transferFileApp.ListByCond(model.NewCond().Eq("task_id", dt.Id).Le("create_time", time.Now().AddDate(0, 0, -dt.FileSaveDays)))
|
||||
if err != nil {
|
||||
logx.Errorf("定时获取迁移文件失败: %s", err.Error())
|
||||
continue
|
||||
}
|
||||
for _, nf := range needDelFiles {
|
||||
if err := d.transferFileApp.Delete(context.Background(), nf.Id); err != nil {
|
||||
logx.Errorf("定时删除迁移文件失败: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// MarkRunning 标记任务执行中
|
||||
func (app *dbTransferAppImpl) MarkRunning(taskId uint64) {
|
||||
cache.Set(fmt.Sprintf("mayfly:db:transfer:%d", taskId), 1, -1)
|
||||
|
||||
@@ -54,7 +54,7 @@ func (app *dbTransferFileAppImpl) Delete(ctx context.Context, id ...uint64) erro
|
||||
|
||||
// 删除对应的文件
|
||||
for _, file := range arr {
|
||||
_ = app.fileApp.Remove(ctx, file.FileKey)
|
||||
app.fileApp.Remove(ctx, file.FileKey)
|
||||
}
|
||||
|
||||
// 删除数据
|
||||
|
||||
@@ -89,7 +89,7 @@ func (sd *SqliteMetaData) GetTables(tableNames ...string) ([]dbi.Table, error) {
|
||||
func (sd *SqliteMetaData) getDataTypes(dataType string) (string, string, string) {
|
||||
matches := dataTypeRegexp.FindStringSubmatch(dataType)
|
||||
if len(matches) == 0 {
|
||||
return "", "", ""
|
||||
return dataType, "", ""
|
||||
}
|
||||
return matches[1], matches[2], matches[3]
|
||||
}
|
||||
@@ -133,7 +133,7 @@ func (sd *SqliteMetaData) GetColumns(tableNames ...string) ([]dbi.Column, error)
|
||||
} else {
|
||||
column.CharMaxLength = cast.ToInt(length)
|
||||
}
|
||||
column.DataType = dbi.ColumnDataType(dataType)
|
||||
column.DataType = dbi.ColumnDataType(strings.ToLower(dataType))
|
||||
columnHelper.FixColumn(&column)
|
||||
|
||||
columns = append(columns, column)
|
||||
|
||||
@@ -15,6 +15,7 @@ type DbTransferTask struct {
|
||||
Cron string `orm:"column(cron)" json:"cron"` // 定时任务cron表达式
|
||||
Mode int8 `orm:"column(mode)" json:"mode"` // 数据迁移方式,1、迁移到数据库 2、迁移到文件
|
||||
TargetFileDbType string `orm:"column(target_file_db_type)" json:"targetFileDbType"` // 目标文件数据库类型
|
||||
FileSaveDays int `json:"fileSaveDays"` // 文件保存天数
|
||||
TaskKey string `orm:"column(key)" json:"taskKey"` // 定时任务唯一uuid key
|
||||
|
||||
CheckedKeys string `orm:"column(checked_keys)" json:"checkedKeys"` // 选中需要迁移的表
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/pkg/eventbus"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/ioc"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func InitIoc() {
|
||||
@@ -13,6 +19,26 @@ func InitIoc() {
|
||||
ioc.Register(new(machineCmdConfAppImpl), ioc.WithComponentName("MachineCmdConfApp"))
|
||||
}
|
||||
|
||||
func Init() {
|
||||
sync.OnceFunc(func() {
|
||||
GetMachineCronJobApp().InitCronJob()
|
||||
|
||||
GetMachineApp().TimerUpdateStats()
|
||||
|
||||
GetMachineTermOpApp().TimerDeleteTermOp()
|
||||
|
||||
global.EventBus.Subscribe(event.EventTopicDeleteMachine, "machineFile", func(ctx context.Context, event *eventbus.Event) error {
|
||||
me := event.Val.(*entity.Machine)
|
||||
return GetMachineFileApp().DeleteByCond(ctx, &entity.MachineFile{MachineId: me.Id})
|
||||
})
|
||||
|
||||
global.EventBus.Subscribe(event.EventTopicDeleteMachine, "machineScript", func(ctx context.Context, event *eventbus.Event) error {
|
||||
me := event.Val.(*entity.Machine)
|
||||
return GetMachineScriptApp().DeleteByCond(ctx, &entity.MachineScript{MachineId: me.Id})
|
||||
})
|
||||
})()
|
||||
}
|
||||
|
||||
func GetMachineApp() Machine {
|
||||
return ioc.Get[Machine]("MachineApp")
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
package init
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/machine/application"
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/internal/machine/infrastructure/persistence"
|
||||
"mayfly-go/internal/machine/router"
|
||||
"mayfly-go/pkg/eventbus"
|
||||
"mayfly-go/pkg/global"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -18,23 +13,5 @@ func init() {
|
||||
application.InitIoc()
|
||||
})
|
||||
initialize.AddInitRouterFunc(router.Init)
|
||||
initialize.AddInitFunc(Init)
|
||||
}
|
||||
|
||||
func Init() {
|
||||
application.GetMachineCronJobApp().InitCronJob()
|
||||
|
||||
application.GetMachineApp().TimerUpdateStats()
|
||||
|
||||
application.GetMachineTermOpApp().TimerDeleteTermOp()
|
||||
|
||||
global.EventBus.Subscribe(event.EventTopicDeleteMachine, "machineFile", func(ctx context.Context, event *eventbus.Event) error {
|
||||
me := event.Val.(*entity.Machine)
|
||||
return application.GetMachineFileApp().DeleteByCond(ctx, &entity.MachineFile{MachineId: me.Id})
|
||||
})
|
||||
|
||||
global.EventBus.Subscribe(event.EventTopicDeleteMachine, "machineScript", func(ctx context.Context, event *eventbus.Event) error {
|
||||
me := event.Val.(*entity.Machine)
|
||||
return application.GetMachineScriptApp().DeleteByCond(ctx, &entity.MachineScript{MachineId: me.Id})
|
||||
})
|
||||
initialize.AddInitFunc(application.Init)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import "fmt"
|
||||
|
||||
const (
|
||||
AppName = "mayfly-go"
|
||||
Version = "v1.8.9"
|
||||
Version = "v1.9.0"
|
||||
)
|
||||
|
||||
func GetAppInfo() string {
|
||||
|
||||
Binary file not shown.
@@ -69,6 +69,7 @@ CREATE TABLE `t_db_transfer_task` (
|
||||
`task_key` varchar(100) NULL comment '定时任务唯一uuid key',
|
||||
`mode` TINYINT(3) NOT NULL DEFAULT 1 comment '数据迁移方式,1、迁移到数据库 2、迁移到文件',
|
||||
`target_file_db_type` varchar(200) NULL comment '目标文件语言类型,类型枚举同target_db_type',
|
||||
`file_save_days` int NULL comment '文件保存天数',
|
||||
`status` tinyint(3) NOT NULL DEFAULT '1' comment '启用状态 1启用 -1禁用',
|
||||
`upd_field_src` varchar(100) DEFAULT NULL COMMENT '更新值来源字段,默认同更新字段,如果查询结果指定了字段别名且与原更新字段不一致,则取这个字段值为当前更新值',
|
||||
`delete_time` datetime DEFAULT NULL COMMENT '删除时间',
|
||||
|
||||
@@ -11,7 +11,7 @@ INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `we
|
||||
|
||||
-- 新增数据库迁移相关的系统配置
|
||||
DELETE FROM `t_sys_config` WHERE `key` = 'DbBackupRestore';
|
||||
UPDATE `t_sys_config` SET param = '[{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB、2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"},{"model":"guacdHost","name":"guacd服务ip","placeholder":"guacd服务ip,默认 127.0.0.1","required":false},{"name":"guacd服务端口","model":"guacdPort","placeholder":"guacd服务端口,默认 4822","required":false},{"model":"guacdFilePath","name":"guacd服务文件存储位置","placeholder":"guacd服务文件存储位置,用于挂载RDP文件夹"}]' WHERE `key`='MachineConfig';
|
||||
UPDATE `t_sys_config` SET params = '[{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB、2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"},{"model":"guacdHost","name":"guacd服务ip","placeholder":"guacd服务ip,默认 127.0.0.1","required":false},{"name":"guacd服务端口","model":"guacdPort","placeholder":"guacd服务端口,默认 4822","required":false},{"model":"guacdFilePath","name":"guacd服务文件存储位置","placeholder":"guacd服务文件存储位置,用于挂载RDP文件夹"}]' WHERE `key`='MachineConfig';
|
||||
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('文件配置', 'FileConfig', '[{"model":"basePath","name":"基础路径","placeholder":"默认为可执行文件对应目录下./file"}]', '{"basePath":"./file"}', '系统文件相关配置', 'admin,', '2024-10-20 22:30:01', 1, 'admin', '2024-10-21 13:51:17', 1, 'admin', 0, NULL);
|
||||
|
||||
-- 数据库迁移到文件
|
||||
@@ -22,6 +22,7 @@ ALTER TABLE `t_db_transfer_task`
|
||||
ADD COLUMN `task_key` varchar(100) NULL comment '定时任务唯一uuid key',
|
||||
ADD COLUMN `mode` TINYINT(3) NOT NULL DEFAULT 1 comment '数据迁移方式,1、迁移到数据库 2、迁移到文件',
|
||||
ADD COLUMN `target_file_db_type` varchar(200) NULL comment '目标文件语言类型,类型枚举同target_db_type',
|
||||
ADD COLUMN `file_save_days` int NULL comment '文件保存天数',
|
||||
ADD COLUMN `status` tinyint(3) NOT NULL DEFAULT '1' comment '启用状态 1启用 -1禁用';
|
||||
|
||||
UPDATE `t_db_transfer_task` SET mode = 1 WHERE 1=1;
|
||||
Reference in New Issue
Block a user