This commit is contained in:
吴红兵
2025-12-02 10:37:49 +08:00
commit 1f645dad3e
1183 changed files with 147673 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
<template>
<el-dialog :title="form.id ? $t('common.editBtn') : $t('common.addBtn')" v-model="visible"
:close-on-click-modal="false" draggable>
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="90px" v-loading="loading">
<el-row :gutter="20">
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.dsType')" prop="dsType">
<el-select v-model="form.dsType" :placeholder="t('datasourceconf.inputdsTypeTip')">
<el-option :key="item.value" :label="item.label" :value="item.value" v-for="item in ds_type"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.name')" prop="name">
<el-input v-model="form.name" :placeholder="t('datasourceconf.inputnameTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.username')" prop="username">
<el-input v-model="form.username" :placeholder="t('datasourceconf.inputusernameTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.password')" prop="password">
<el-input v-model="form.password" :placeholder="t('datasourceconf.inputpasswordTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item :label="t('datasourceconf.confType')" prop="confType">
<el-radio-group v-model="form.confType">
<el-radio :label="Number(item.value)" v-for="(item, index) in ds_config_type" border :key="index">
{{ item.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="form.confType === 0 && form.dsType === 'mssql'">
<el-form-item :label="t('datasourceconf.instance')" prop="instance">
<el-input v-model="form.instance" :placeholder="t('datasourceconf.inputinstanceTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="form.confType === 0">
<el-form-item :label="t('datasourceconf.port')" prop="port">
<el-input-number v-model="form.port" :placeholder="t('datasourceconf.inputportTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="form.confType === 0">
<el-form-item :label="t('datasourceconf.host')" prop="host">
<el-input v-model="form.host" :placeholder="t('datasourceconf.inputhostTip')"/>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20" v-if="form.confType === 0">
<el-form-item :label="t('datasourceconf.dsName')" prop="dsName">
<el-input v-model="form.dsName" :placeholder="t('datasourceconf.inputdsNameTip')"/>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20" v-if="form.confType === 1">
<el-form-item :label="t('datasourceconf.url')" prop="url">
<el-input v-model="form.url" type="textarea" :placeholder="t('datasourceconf.inputurlTip')"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">{{ $t('common.confirmButtonText') }}</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="systemDatasourceConfDialog">
import {useMessage} from '/@/hooks/message';
import {getObj, addObj, putObj} from '/@/api/gen/datasource';
import {useI18n} from 'vue-i18n';
import {useDict} from '/@/hooks/dict';
import {rule} from "/@/utils/validate";
// 定义子组件向父组件传值/事件
const emit = defineEmits(['refresh']);
const {t} = useI18n();
// 定义变量内容
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
// 定义字典处理
const {ds_config_type, ds_type} = useDict('ds_config_type', 'ds_type');
// 提交表单数据
const form = reactive({
id: '',
name: '',
url: '',
username: '',
password: ('' as string) || undefined,
createTime: '',
updateTime: '',
dsType: '',
confType: 0,
dsName: '',
instance: '',
port: 3306,
host: '',
});
/**
*
* @param {校验数据源名} rule
* @param {*} value
* @param {*} callback
*/
const validateDsName = (_rule, value, callback) => {
var re = /(?=.*[a-z])(?=.*_)/;
if (value && !re.test(value)) {
callback(new Error('数据源名称不合法, 组名_数据源名形式'));
} else {
callback();
}
};
// 定义校验规则
const dataRules = ref({
name: [
{required: true, message: '别名不能为空', trigger: 'blur'},
{validator: validateDsName, trigger: 'blur'},
],
url: [{required: true, message: 'jdbcurl不能为空', trigger: 'blur'}, {
min: 10,
max: 500,
message: 'URL长度必须介于 10 和 500 字符之间',
trigger: 'blur'
},],
username: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '用户名不能为空', trigger: 'blur'}],
password: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '密码不能为空', trigger: 'blur'}],
dsType: [{required: true, message: '数据库类型不能为空', trigger: 'blur'}],
confType: [{required: true, message: '配置类型不能为空', trigger: 'blur'}],
dsName: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '数据库名称不能为空', trigger: 'blur'}],
instance: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '实例不能为空', trigger: 'blur'}],
port: [{required: true, message: '端口不能为空', trigger: 'blur'}],
host: [{ validator: rule.overLength, trigger: 'blur' },{required: true, message: '主机不能为空', trigger: 'blur'}],
});
// 打开弹窗
const openDialog = async (id: string) => {
visible.value = true;
form.id = '';
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取DatasourceConf信息
if (id) {
form.id = id;
await getDatasourceConfData(id);
// 修改密码时候,原密码打码
form.password = '********';
}
};
// 提交
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {
});
if (!valid) return false;
form.password = form.password?.includes('******') ? undefined : form.password;
try {
loading.value = true;
form.id ? await putObj(form) : await addObj(form);
useMessage().success(t(form.id ? 'common.editSuccessText' : 'common.addSuccessText'));
visible.value = false;
emit('refresh');
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
};
// 初始化表单数据
const getDatasourceConfData = (id: string) => {
// 获取数据
return getObj(id).then((res: any) => {
Object.assign(form, res.data);
});
};
// 暴露变量
defineExpose({
openDialog,
});
</script>

View File

@@ -0,0 +1,37 @@
export default {
datasourceconf: {
index: '#',
importDatasourceConfTip: ' import DatasourceConf',
id: 'id',
name: 'name',
url: 'url',
username: 'username',
password: 'password',
docBtn: 'doc',
createTime: 'createTime',
updateTime: 'updateTime',
delFlag: 'delFlag',
tenantId: 'tenantId',
dsType: 'dsType',
confType: 'confType',
dsName: 'dsName',
instance: 'instance',
port: 'port',
host: 'host',
inputidTip: 'input id',
inputnameTip: 'input name',
inputurlTip: 'input url',
inputusernameTip: 'input username',
inputpasswordTip: 'input password',
inputcreateTimeTip: 'input createTime',
inputupdateTimeTip: 'input updateTime',
inputdelFlagTip: 'input delFlag',
inputtenantIdTip: 'input tenantId',
inputdsTypeTip: 'input dsType',
inputconfTypeTip: 'input confType',
inputdsNameTip: 'input dsName',
inputinstanceTip: 'input instance',
inputportTip: 'input port',
inputhostTip: 'input host',
},
};

View File

@@ -0,0 +1,37 @@
export default {
datasourceconf: {
index: '#',
importDatasourceConfTip: '导入数据源',
id: '主键',
name: '别名',
url: 'jdbc-url',
username: '用户名',
password: '密码',
docBtn: '文档',
createTime: '创建时间',
updateTime: '更新',
delFlag: '删除标记',
tenantId: '租户ID',
dsType: '类型',
confType: '配置类型',
dsName: '库名称',
instance: '实例',
port: '端口',
host: '主机',
inputidTip: '请输入主键',
inputnameTip: '请输入别名',
inputurlTip: '请输入jdbcurl',
inputusernameTip: '请输入用户名',
inputpasswordTip: '请输入密码',
inputcreateTimeTip: '请输入创建时间',
inputupdateTimeTip: '请输入更新',
inputdelFlagTip: '请输入删除标记',
inputtenantIdTip: '请输入租户ID',
inputdsTypeTip: '请输入数据库类型',
inputconfTypeTip: '请输入配置类型',
inputdsNameTip: '请输入数据库名称',
inputinstanceTip: '请输入实例',
inputportTip: '请输入端口',
inputhostTip: '请输入主机',
},
};

View File

@@ -0,0 +1,128 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-row class="ml10" v-show="showSearch">
<el-form :inline="true" :model="state.queryForm" @keyup.enter="getDataList" ref="queryRef">
<el-form-item :label="$t('datasourceconf.dsName')" prop="dsName">
<el-input :placeholder="$t('datasourceconf.inputdsNameTip')" v-model="state.queryForm.dsName" />
</el-form-item>
<el-form-item>
<el-button @click="getDataList" icon="search" type="primary">
{{ $t('common.queryBtn') }}
</el-button>
<el-button @click="resetQuery" icon="Refresh">{{ $t('common.resetBtn') }} </el-button>
</el-form-item>
</el-form>
</el-row>
<el-row>
<div class="mb8" style="width: 100%">
<el-button @click="formDialogRef.openDialog()" class="ml10" icon="folder-add" type="primary">
{{ $t('common.addBtn') }}
</el-button>
<el-button :disabled="multiple" @click="handleDelete(selectObjs)" class="ml10" icon="Delete" type="primary">
{{ $t('common.delBtn') }}
</el-button>
<right-toolbar
@queryTable="getDataList"
class="ml10"
style="float: right; margin-right: 20px"
v-model:showSearch="showSearch"
></right-toolbar>
</div>
</el-row>
<el-table
:data="state.dataList"
@selection-change="handleSelectionChange"
style="width: 100%"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column align="center" type="selection" width="40" />
<el-table-column :label="t('datasourceconf.index')" type="index" width="60" />
<el-table-column :label="t('datasourceconf.name')" prop="name" show-overflow-tooltip />
<el-table-column :label="t('datasourceconf.dsName')" prop="dsName" show-overflow-tooltip />
<el-table-column :label="t('datasourceconf.dsType')" prop="dsType" show-overflow-tooltip />
<el-table-column :label="t('datasourceconf.username')" prop="username" show-overflow-tooltip />
<el-table-column :label="t('datasourceconf.createTime')" prop="createTime" show-overflow-tooltip />
<el-table-column :label="$t('common.action')" width="250">
<template #default="scope">
<el-button icon="document" @click="downloadDoc(scope.row.name)" text type="primary">{{ $t('datasourceconf.docBtn') }} </el-button>
<el-button icon="edit" @click="formDialogRef.openDialog(scope.row.id)" text type="primary">{{ $t('common.editBtn') }} </el-button>
<el-button icon="delete" @click="handleDelete([scope.row.id])" text type="primary">{{ $t('common.delBtn') }} </el-button>
</template>
</el-table-column>
</el-table>
<pagination @current-change="currentChangeHandle" @size-change="sizeChangeHandle" v-bind="state.pagination" />
</div>
<!-- 编辑新增 -->
<form-dialog @refresh="getDataList()" ref="formDialogRef" />
</div>
</template>
<script lang="ts" name="systemDatasourceConf" setup>
import { BasicTableProps, useTable } from '/@/hooks/table';
import { delObj, fetchList } from '/@/api/gen/datasource';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { useI18n } from 'vue-i18n';
import { downBlobFile } from '/@/utils/other';
// 引入组件
const FormDialog = defineAsyncComponent(() => import('./form.vue'));
const { t } = useI18n();
// 定义变量内容
const formDialogRef = ref();
// 搜索变量
const queryRef = ref();
const showSearch = ref(true);
// 多选变量
const selectObjs = ref([]) as any;
const multiple = ref(true);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
descs: ['create_time'],
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, tableStyle } = useTable(state);
const downloadDoc = (dsName: string) => {
downBlobFile('/gen/dsconf/doc', { dsName }, `${dsName}.html`);
};
// 清空搜索条件
const resetQuery = () => {
queryRef.value.resetFields();
getDataList();
};
// 多选事件
const handleSelectionChange = (objs: { id: string }[]) => {
selectObjs.value = objs.map(({ id }) => id);
multiple.value = !objs.length;
};
// 删除操作
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm(t('common.delConfirmText'));
} catch {
return;
}
try {
await delObj(ids);
getDataList();
useMessage().success(t('common.delSuccessText'));
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>