update: 数据源管理-管理模块
This commit is contained in:
parent
67df928602
commit
58e5eec93b
|
@ -3,9 +3,22 @@ import server from '@/utils/request';
|
|||
|
||||
// 获取数据源列表
|
||||
export const getDataSourceList_api = (data: object) => server.post(`/datasource/config/_query/`, data);
|
||||
// 获取数据源信息
|
||||
export const getDataSourceInfo_api = (id: string) => server.get(`/datasource/config/${id}`);
|
||||
|
||||
// 获取数据库类型字典
|
||||
export const getDataTypeDict_api = () => server.get(`/datasource/config/types`);
|
||||
|
||||
// 修改数据源状态
|
||||
export const changeStatus_api = (id:string, status:'_disable'|'_enable') => server.put(`/datasource/config/${id}/${status}`);
|
||||
export const changeStatus_api = (id: string, status: '_disable' | '_enable') => server.put(`/datasource/config/${id}/${status}`);
|
||||
// 新增/更新数据源
|
||||
export const saveDataSource_api = (data: any) => data.id ? server.patch(`datasource/config`, data) : server.post(`/datasource/config`, data)
|
||||
|
||||
// 删除数据源
|
||||
export const delDataSource_api = (id: string) => server.remove(`/datasource/config/${id}`);
|
||||
// 获取左侧树
|
||||
export const rdbTree_api = (id: string) => server.get(`/datasource/rdb/${id}/tables?includeColumns=false`);
|
||||
// 获取右侧表格
|
||||
export const rdbTables_api = (id: string,key:string) => server.get(`/datasource/rdb/${id}/table/${key}`);
|
||||
// 保存表格
|
||||
export const saveTable_api = (id: string,data:object) => server.patch(`/datasource/rdb/${id}/table`,data);
|
||||
|
|
|
@ -0,0 +1,381 @@
|
|||
<template>
|
||||
<a-card class="mangement-container">
|
||||
<div class="left">
|
||||
<a-input-search
|
||||
v-model:value="leftData.searchValue"
|
||||
placeholder="请输入"
|
||||
style="margin-bottom: 24px"
|
||||
/>
|
||||
<a-tree
|
||||
showLine
|
||||
autoExpandParent
|
||||
:tree-data="leftData.treeData"
|
||||
v-model:selectedKeys="leftData.selectedKeys"
|
||||
@select="leftData.onSelect"
|
||||
>
|
||||
<template #title="{ dataRef }">
|
||||
<div
|
||||
v-if="dataRef.root"
|
||||
style="
|
||||
justify-content: space-between;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
"
|
||||
>
|
||||
<span>
|
||||
{{ dataRef.title }}
|
||||
</span>
|
||||
<AIcon
|
||||
type="PlusOutlined"
|
||||
style="color: #1d39c4"
|
||||
@click="leftData.addTable"
|
||||
/>
|
||||
</div>
|
||||
<span v-else>
|
||||
{{ dataRef.title }}
|
||||
</span>
|
||||
</template>
|
||||
</a-tree>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="btns">
|
||||
<a-button type="primary" @click="table.clickSave"
|
||||
>保存</a-button
|
||||
>
|
||||
</div>
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
model="TABLE"
|
||||
:dataSource="table.data"
|
||||
>
|
||||
<template #previousName="slotProps">
|
||||
<a-input
|
||||
:disabled="slotProps.scale === 0"
|
||||
v-model:value="slotProps.previousName"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</template>
|
||||
<template #type="slotProps">
|
||||
<a-input
|
||||
v-model:value="slotProps.type"
|
||||
placeholder="请输入类型"
|
||||
/>
|
||||
</template>
|
||||
<template #length="slotProps">
|
||||
<a-input-number v-model:value="slotProps.length" />
|
||||
</template>
|
||||
<template #precision="slotProps">
|
||||
<a-input-number v-model:value="slotProps.precision" />
|
||||
</template>
|
||||
<template #notnull="slotProps">
|
||||
<a-radio-group
|
||||
v-model:value="slotProps.notnull"
|
||||
button-style="solid"
|
||||
>
|
||||
<a-radio-button :value="true">是</a-radio-button>
|
||||
<a-radio-button :value="false">否</a-radio-button>
|
||||
</a-radio-group>
|
||||
</template>
|
||||
<template #comment="slotProps">
|
||||
<a-input
|
||||
v-model:value="slotProps.comment"
|
||||
placeholder="请输入说明"
|
||||
/>
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<PermissionButton
|
||||
:uhasPermission="`{permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{ title: '删除' }"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="slotProps.status"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</template>
|
||||
</JTable>
|
||||
<a-botton class="add-row" @click="table.addRow"
|
||||
><AIcon type="PlusOutlined" /> 新增行</a-botton
|
||||
>
|
||||
</div>
|
||||
</a-card>
|
||||
<div class="dialogs">
|
||||
<a-modal
|
||||
v-model:visible="dialog.visible"
|
||||
title="新增"
|
||||
@ok="dialog.handleOk"
|
||||
>
|
||||
<a-form :model="dialog.form" ref="addFormRef">
|
||||
<a-form-item
|
||||
label="名称"
|
||||
name="name"
|
||||
:rules="[
|
||||
{
|
||||
required: true,
|
||||
message: '请输入名称',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
max: 64,
|
||||
message: '最多可输入64个字符',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
pattern: /^[0-9].*$/,
|
||||
message: '不能以数字开头',
|
||||
trigger: 'change',
|
||||
},
|
||||
{
|
||||
pattern: /^\w+$/,
|
||||
message: '名称只能由数字、字母、下划线、中划线组成',
|
||||
trigger: 'change',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="dialog.form.name"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="Management">
|
||||
import {
|
||||
getDataSourceInfo_api,
|
||||
rdbTree_api,
|
||||
rdbTables_api,
|
||||
saveTable_api,
|
||||
} from '@/api/system/dataSource';
|
||||
import { FormInstance, message } from 'ant-design-vue';
|
||||
import { DataNode } from 'ant-design-vue/lib/tree';
|
||||
import { dictItemType, sourceItemType } from '../typing';
|
||||
|
||||
const id = useRoute().query.id as string;
|
||||
|
||||
const info = reactive({
|
||||
data: {} as sourceItemType,
|
||||
init: () => {
|
||||
id &&
|
||||
getDataSourceInfo_api(id).then((resp: any) => {
|
||||
info.data = resp.result;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const leftData = reactive({
|
||||
searchValue: '',
|
||||
sourceTree: [] as dictItemType[],
|
||||
treeData: [] as DataNode[],
|
||||
selectedKeys: [] as string[],
|
||||
oldKey: '',
|
||||
|
||||
init: () => {
|
||||
leftData.getTree();
|
||||
watch(
|
||||
[
|
||||
() => leftData.searchValue,
|
||||
() => leftData.sourceTree,
|
||||
() => info.data,
|
||||
],
|
||||
(n) => {
|
||||
if (leftData.sourceTree.length < 1 || !info.data.shareConfig)
|
||||
return;
|
||||
let filterArr = [];
|
||||
if (leftData.searchValue) {
|
||||
filterArr = leftData.sourceTree.filter((item) =>
|
||||
item.name.includes(n[0]),
|
||||
);
|
||||
} else filterArr = leftData.sourceTree;
|
||||
leftData.treeData = [
|
||||
{
|
||||
title: info.data.shareConfig.schema,
|
||||
key: info.data.shareConfig.schema,
|
||||
root: true,
|
||||
children: filterArr.map((item) => ({
|
||||
title: item.name,
|
||||
key: item.name,
|
||||
})),
|
||||
},
|
||||
];
|
||||
leftData.selectedKeys = [filterArr[0].name];
|
||||
leftData.onSelect([filterArr[0].name]);
|
||||
},
|
||||
{},
|
||||
);
|
||||
},
|
||||
getTree: () => {
|
||||
rdbTree_api(id)
|
||||
.then((resp: any) => {
|
||||
leftData.sourceTree = resp.result;
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
onSelect: (selectedKeys: string[], e?: any) => {
|
||||
if (e?.node?.root) {
|
||||
leftData.selectedKeys = [leftData.oldKey];
|
||||
return;
|
||||
}
|
||||
leftData.oldKey = selectedKeys[0];
|
||||
const key = selectedKeys[0];
|
||||
table.getTabelData(key);
|
||||
},
|
||||
addTable: (e: Event) => {
|
||||
e.stopPropagation();
|
||||
},
|
||||
});
|
||||
|
||||
const table = reactive({
|
||||
columns: [
|
||||
{
|
||||
title: '列名',
|
||||
dataIndex: 'previousName',
|
||||
key: 'previousName',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '长度',
|
||||
dataIndex: 'length',
|
||||
key: 'length',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '精度',
|
||||
dataIndex: 'precision',
|
||||
key: 'precision',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '不能为空',
|
||||
dataIndex: 'notnull',
|
||||
key: 'notnull',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'comment',
|
||||
key: 'comment',
|
||||
scopedSlots: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
scopedSlots: true,
|
||||
},
|
||||
],
|
||||
data: [] as any,
|
||||
|
||||
getTabelData: (key: string) => {
|
||||
rdbTables_api(id, key).then((resp: any) => {
|
||||
table.data = resp.result.columns;
|
||||
});
|
||||
},
|
||||
addRow: () => {
|
||||
table.data.push({
|
||||
precision: 0,
|
||||
length: 0,
|
||||
notnull: false,
|
||||
});
|
||||
},
|
||||
clickSave: () => {
|
||||
const params = {
|
||||
name: leftData.selectedKeys[0],
|
||||
columns: table.data,
|
||||
};
|
||||
saveTable_api(id, params).then(() => {
|
||||
table.getTabelData(params.name);
|
||||
});
|
||||
},
|
||||
clickDel: (row: any) => {},
|
||||
});
|
||||
|
||||
const addFormRef = ref<FormInstance >();
|
||||
const dialog = reactive({
|
||||
visible: false,
|
||||
form: {
|
||||
name: '',
|
||||
},
|
||||
handleOk: () => {
|
||||
addFormRef.value && addFormRef.value.validate().then(()=>{
|
||||
const name = dialog.form.name
|
||||
leftData.sourceTree.unshift({
|
||||
id:name,
|
||||
name
|
||||
})
|
||||
leftData.oldKey = name;
|
||||
leftData.selectedKeys = [name]
|
||||
table.data = []
|
||||
})
|
||||
},
|
||||
});
|
||||
|
||||
init();
|
||||
function init() {
|
||||
info.init();
|
||||
leftData.init();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mangement-container {
|
||||
padding: 24px;
|
||||
background-color: transparent;
|
||||
:deep(.ant-card-body) {
|
||||
display: flex;
|
||||
background-color: #fff;
|
||||
|
||||
.left {
|
||||
flex-basis: 280px;
|
||||
padding-right: 24px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.ant-tree-treenode {
|
||||
width: 100%;
|
||||
.ant-tree-switcher-noop {
|
||||
display: none;
|
||||
}
|
||||
.ant-tree-node-content-wrapper {
|
||||
width: 100%;
|
||||
.ant-tree-title {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
&:first-child .ant-tree-node-selected {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
.right {
|
||||
width: calc(100% - 280px);
|
||||
box-sizing: border-box;
|
||||
border-left: 1px solid #f0f0f0;
|
||||
|
||||
.btns {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
padding: 0px 24px;
|
||||
}
|
||||
|
||||
.add-row {
|
||||
display: block;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -34,9 +34,9 @@
|
|||
>
|
||||
<a-select
|
||||
v-model:value="form.data.typeId"
|
||||
style="width: 120px"
|
||||
:options="form.typeOptions"
|
||||
placeholder="请选择类型"
|
||||
:disabled="!!form.data.id"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
|
@ -83,7 +83,7 @@
|
|||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-row :gutter="24" v-show="form.data.typeId">
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'username']"
|
||||
|
@ -179,28 +179,42 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDataTypeDict_api } from '@/api/system/dataSource';
|
||||
import {
|
||||
getDataTypeDict_api,
|
||||
saveDataSource_api,
|
||||
} from '@/api/system/dataSource';
|
||||
import { FormInstance, message } from 'ant-design-vue';
|
||||
import type { dictItemType, optionItemType, sourceItemType } from '../typing';
|
||||
|
||||
const emits = defineEmits(['confirm']);
|
||||
|
||||
// 弹窗相关
|
||||
const dialog = {
|
||||
title: '',
|
||||
loading: ref<boolean>(false),
|
||||
visible: ref<boolean>(false),
|
||||
handleOk: () => {},
|
||||
handleOk: () => {
|
||||
formRef.value?.validate().then(() => {
|
||||
form.submit();
|
||||
});
|
||||
},
|
||||
// 打开弹窗
|
||||
changeVisible: (row: sourceItemType) => {
|
||||
openDialog: (row: sourceItemType) => {
|
||||
if (row.id) dialog.title = '编辑数据源';
|
||||
else dialog.title = '新增数据源';
|
||||
form.data = { ...row };
|
||||
dialog.visible.value = true;
|
||||
nextTick(() => {
|
||||
formRef.value?.clearValidate();
|
||||
dialog.visible.value = true;
|
||||
});
|
||||
},
|
||||
};
|
||||
// 将打开弹窗的操作暴露给父组件
|
||||
defineExpose({
|
||||
openDialog: dialog.changeVisible,
|
||||
openDialog: dialog.openDialog,
|
||||
});
|
||||
|
||||
const formRef = ref<FormInstance>();
|
||||
const form = reactive({
|
||||
data: {
|
||||
shareConfig: {},
|
||||
|
@ -217,8 +231,16 @@ const form = reactive({
|
|||
}));
|
||||
});
|
||||
},
|
||||
submit: () => {
|
||||
dialog.loading.value = true;
|
||||
saveDataSource_api(form.data)
|
||||
.then(() => {
|
||||
message.success('操作成功');
|
||||
emits('confirm');
|
||||
dialog.visible.value = false;
|
||||
})
|
||||
.finally(() => (dialog.loading.value = false));
|
||||
},
|
||||
});
|
||||
form.getTypeOption();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
`/system/DataSource/Management?id=${slotProps.id}`,
|
||||
)
|
||||
"
|
||||
:disabled="slotProps?.typeId === 'rabbitmq' || !table.getRowStatus(slotProps)"
|
||||
>
|
||||
<AIcon type="icon-ziyuankuguanli" />
|
||||
</PermissionButton>
|
||||
|
@ -131,6 +132,7 @@ import {
|
|||
getDataSourceList_api,
|
||||
getDataTypeDict_api,
|
||||
changeStatus_api,
|
||||
delDataSource_api
|
||||
} from '@/api/system/dataSource';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
|
@ -226,6 +228,7 @@ const table = {
|
|||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
|
@ -240,6 +243,7 @@ const table = {
|
|||
key: 'action',
|
||||
scopedSlots: true,
|
||||
width: '200px',
|
||||
fixed:'right'
|
||||
},
|
||||
],
|
||||
|
||||
|
@ -265,16 +269,16 @@ const table = {
|
|||
},
|
||||
// 打开编辑弹窗
|
||||
openDialog: (row: sourceItemType | {}) => {
|
||||
editDialogRef.value.openDialog({shareConfig:{},...row});
|
||||
editDialogRef.value.openDialog({ shareConfig: {}, ...row });
|
||||
},
|
||||
// 删除
|
||||
clickDel: (row: sourceItemType) => {
|
||||
// delRelation_api(row.id).then((resp: any) => {
|
||||
// if (resp.status === 200) {
|
||||
// tableRef.value?.reload();
|
||||
// message.success('操作成功!');
|
||||
// }
|
||||
// });
|
||||
delDataSource_api(row.id as string).then((resp: any) => {
|
||||
if (resp.status === 200) {
|
||||
tableRef.value?.reload();
|
||||
message.success('操作成功!');
|
||||
}
|
||||
});
|
||||
},
|
||||
clickChangeStatus: (row: sourceItemType) => {
|
||||
const status = row.state.value === 'enabled' ? '_disable' : '_enable';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export type dictItemType = {
|
||||
id: string,
|
||||
name: string
|
||||
name: string,
|
||||
children?:dictItemType
|
||||
}
|
||||
export type optionItemType = {
|
||||
label: string,
|
||||
|
|
Loading…
Reference in New Issue