feat: 系统管理-数据源管理
This commit is contained in:
parent
9e2c0069b6
commit
42d49a3083
|
@ -0,0 +1,11 @@
|
|||
import server from '@/utils/request';
|
||||
|
||||
|
||||
// 获取数据源列表
|
||||
export const getDataSourceList_api = (data: object) => server.post(`/datasource/config/_query/`, data);
|
||||
|
||||
// 获取数据库类型字典
|
||||
export const getDataTypeDict_api = () => server.get(`/datasource/config/types`);
|
||||
|
||||
// 修改数据源状态
|
||||
export const changeStatus_api = (id:string, status:'_disable'|'_enable') => server.put(`/datasource/config/${id}/${status}`);
|
|
@ -0,0 +1,224 @@
|
|||
<template>
|
||||
<a-modal
|
||||
class="edit-dialog-container"
|
||||
:title="dialog.title"
|
||||
width="1050px"
|
||||
@ok="dialog.handleOk"
|
||||
:confirmLoading="dialog.loading.value"
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
v-model:visible="dialog.visible.value"
|
||||
>
|
||||
<a-form ref="formRef" :model="form.data" layout="vertical">
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
name="name"
|
||||
label="名称"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入名称' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.name"
|
||||
placeholder="请输入名称"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
name="typeId"
|
||||
label="类型"
|
||||
:rules="[{ required: true, message: '请选择类型' }]"
|
||||
>
|
||||
<a-select
|
||||
v-model:value="form.data.typeId"
|
||||
style="width: 120px"
|
||||
:options="form.typeOptions"
|
||||
placeholder="请选择类型"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24" v-if="form.data.typeId === 'rdb'">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'url']"
|
||||
label="URL"
|
||||
:rules="[{ required: true, message: '请输入URL' }]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.url"
|
||||
placeholder="请输入r2bdc或者jdbc连接地址,示例:r2dbc:mysql://127.0.0.1:3306/test"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24" v-if="form.data.typeId === 'rabbitmq'">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'adminUrl']"
|
||||
label="管理地址"
|
||||
:rules="[{ required: true, message: '请输入管理地址' }]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.adminUrl"
|
||||
placeholder="请输入管理地址,示例:http://localhost:15672"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24" v-if="form.data.typeId === 'rabbitmq'">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'addresses']"
|
||||
label="链接地址"
|
||||
:rules="[{ required: true, message: '请输入链接地址' }]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.addresses"
|
||||
placeholder="请输入链接地址,示例:localhost:5672"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'username']"
|
||||
label="用户名"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入用户名' },
|
||||
{
|
||||
max: 64,
|
||||
message: '最多可输入64个字符',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.username"
|
||||
placeholder="请输入用户名"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :span="12">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'password']"
|
||||
label="密码"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入密码' },
|
||||
{
|
||||
max: 64,
|
||||
message: '最多可输入64个字符',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input-password
|
||||
v-model:value="form.data.shareConfig.password"
|
||||
placeholder="请输入密码"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24" v-if="form.data.typeId === 'rabbitmq'">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'virtualHost']"
|
||||
label="虚拟域"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入虚拟域' },
|
||||
{
|
||||
max: 64,
|
||||
message: '最多可输入64个字符',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.virtualHost"
|
||||
placeholder="请输入虚拟域"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24" v-if="form.data.typeId === 'rdb'">
|
||||
<a-col :span="24">
|
||||
<a-form-item
|
||||
:name="['shareConfig', 'schema']"
|
||||
label="schema"
|
||||
:rules="[
|
||||
{ required: true, message: '请输入schema' },
|
||||
{
|
||||
max: 64,
|
||||
message: '最多可输入64个字符',
|
||||
},
|
||||
]"
|
||||
>
|
||||
<a-input
|
||||
v-model:value="form.data.shareConfig.schema"
|
||||
placeholder="请输入schema"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-item name="description" label="说明">
|
||||
<a-textarea
|
||||
v-model:value="form.data.description"
|
||||
placeholder="请输入说明"
|
||||
:rows="3"
|
||||
showCount
|
||||
:maxlength="200"
|
||||
/>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getDataTypeDict_api } from '@/api/system/dataSource';
|
||||
import type { dictItemType, optionItemType, sourceItemType } from '../typing';
|
||||
|
||||
// 弹窗相关
|
||||
const dialog = {
|
||||
title: '',
|
||||
loading: ref<boolean>(false),
|
||||
visible: ref<boolean>(false),
|
||||
handleOk: () => {},
|
||||
// 打开弹窗
|
||||
changeVisible: (row: sourceItemType) => {
|
||||
if (row.id) dialog.title = '编辑数据源';
|
||||
else dialog.title = '新增数据源';
|
||||
form.data = { ...row };
|
||||
dialog.visible.value = true;
|
||||
},
|
||||
};
|
||||
// 将打开弹窗的操作暴露给父组件
|
||||
defineExpose({
|
||||
openDialog: dialog.changeVisible,
|
||||
});
|
||||
|
||||
const form = reactive({
|
||||
data: {
|
||||
shareConfig: {},
|
||||
} as sourceItemType,
|
||||
|
||||
typeOptions: [] as optionItemType[],
|
||||
|
||||
getTypeOption: () => {
|
||||
getDataTypeDict_api().then((resp: any) => {
|
||||
const result = resp.result as dictItemType[];
|
||||
form.typeOptions = result.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
});
|
||||
},
|
||||
});
|
||||
form.getTypeOption();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
|
@ -0,0 +1,304 @@
|
|||
<template>
|
||||
<div class="data-source-container">
|
||||
<Search :columns="query.columns" @search="query.search" />
|
||||
|
||||
<JTable
|
||||
ref="tableRef"
|
||||
:columns="table.columns"
|
||||
:request="getDataSourceList_api"
|
||||
model="TABLE"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
<PermissionButton
|
||||
type="primary"
|
||||
:uhasPermission="`${permission}:add`"
|
||||
@click="table.openDialog({})"
|
||||
>
|
||||
<AIcon type="PlusOutlined" />新增
|
||||
</PermissionButton>
|
||||
</template>
|
||||
<template #state="slotProps">
|
||||
<BadgeStatus
|
||||
:status="slotProps.state?.value"
|
||||
:text="slotProps.state?.text"
|
||||
:statusNames="{
|
||||
enabled: 'success',
|
||||
disabled: 'error',
|
||||
}"
|
||||
>
|
||||
</BadgeStatus>
|
||||
</template>
|
||||
<template #typeId="slotProps">
|
||||
{{
|
||||
(table.typeOptions.value.length &&
|
||||
table.getTypeLabel(slotProps.typeId)) ||
|
||||
''
|
||||
}}
|
||||
</template>
|
||||
<template #action="slotProps">
|
||||
<a-space :size="16">
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:update`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: '编辑',
|
||||
}"
|
||||
@click="table.openDialog(slotProps)"
|
||||
>
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:manage`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title:
|
||||
slotProps?.typeId === 'rabbitmq'
|
||||
? '暂不支持管理功能'
|
||||
: table.getRowStatus(slotProps)
|
||||
? '管理'
|
||||
: '请先启用数据源',
|
||||
}"
|
||||
@click="
|
||||
() =>
|
||||
router.push(
|
||||
`/system/DataSource/Management?id=${slotProps.id}`,
|
||||
)
|
||||
"
|
||||
>
|
||||
<AIcon type="icon-ziyuankuguanli" />
|
||||
</PermissionButton>
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:action`"
|
||||
type="link"
|
||||
:popConfirm="{
|
||||
title: `确定要${
|
||||
table.getRowStatus(slotProps) ? '禁用' : '启用'
|
||||
}吗?`,
|
||||
onConfirm: () => table.clickChangeStatus(slotProps),
|
||||
}"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '禁用'
|
||||
: '启用',
|
||||
}"
|
||||
>
|
||||
<AIcon
|
||||
:type="
|
||||
table.getRowStatus(slotProps)
|
||||
? 'StopOutlined'
|
||||
: 'PlayCircleOutlined'
|
||||
"
|
||||
/>
|
||||
<!-- <AIcon type="PlayCircleOutlined" /> -->
|
||||
</PermissionButton>
|
||||
|
||||
<PermissionButton
|
||||
:uhasPermission="`${permission}:delete`"
|
||||
type="link"
|
||||
:tooltip="{
|
||||
title: table.getRowStatus(slotProps)
|
||||
? '请先禁用,再删除'
|
||||
: '删除',
|
||||
}"
|
||||
:popConfirm="{
|
||||
title: `确认删除`,
|
||||
onConfirm: () => table.clickDel(slotProps),
|
||||
}"
|
||||
:disabled="table.getRowStatus(slotProps)"
|
||||
>
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</a-space>
|
||||
</template>
|
||||
</JTable>
|
||||
|
||||
<div class="dialogs">
|
||||
<EditDialog ref="editDialogRef" @confirm="table.refresh" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="DataSource">
|
||||
import PermissionButton from '@/components/PermissionButton/index.vue';
|
||||
import BadgeStatus from '@/components/BadgeStatus/index.vue';
|
||||
import EditDialog from './components/EditDialog.vue';
|
||||
|
||||
import type { dictItemType, optionItemType, sourceItemType } from './typing';
|
||||
|
||||
import {
|
||||
getDataSourceList_api,
|
||||
getDataTypeDict_api,
|
||||
changeStatus_api,
|
||||
} from '@/api/system/dataSource';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const permission = 'system/Relationship';
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const query = {
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'typeId',
|
||||
key: 'typeId',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: () =>
|
||||
new Promise((resolve) => {
|
||||
if (table.typeOptions.value.length > 0)
|
||||
return resolve(table.typeOptions.value);
|
||||
getDataTypeDict_api().then((resp: any) => {
|
||||
const result = resp.result as dictItemType[];
|
||||
resolve(
|
||||
result.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
})),
|
||||
);
|
||||
});
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
search: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
ellipsis: true,
|
||||
fixed: 'left',
|
||||
search: {
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
label: '正常',
|
||||
value: 'enabled',
|
||||
},
|
||||
{
|
||||
label: '已禁用',
|
||||
value: 'disabled',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
params: ref({}),
|
||||
search: (params: object) => {
|
||||
query.params.value = params;
|
||||
},
|
||||
};
|
||||
|
||||
const editDialogRef = ref(); // 新增弹窗实例
|
||||
const tableRef = ref<Record<string, any>>({}); // 表格实例
|
||||
const table = {
|
||||
columns: [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: '250px',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'typeId',
|
||||
key: 'typeId',
|
||||
scopedSlots: true,
|
||||
},
|
||||
|
||||
{
|
||||
title: '说明',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'state',
|
||||
key: 'state',
|
||||
scopedSlots: true,
|
||||
width: '120px',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
key: 'action',
|
||||
scopedSlots: true,
|
||||
width: '200px',
|
||||
},
|
||||
],
|
||||
|
||||
typeOptions: ref<optionItemType[]>([]),
|
||||
|
||||
getTypeOption: () => {
|
||||
getDataTypeDict_api().then((resp: any) => {
|
||||
const result = resp.result as dictItemType[];
|
||||
table.typeOptions.value = result.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
});
|
||||
},
|
||||
getTypeLabel: (val: string): string => {
|
||||
const options = table.typeOptions.value;
|
||||
if (options.length < 1 || val === '') return '';
|
||||
return options.find((item) => item.value === val)?.label || '';
|
||||
},
|
||||
|
||||
getRowStatus: (row: sourceItemType) => {
|
||||
return row.state?.value === 'enabled';
|
||||
},
|
||||
// 打开编辑弹窗
|
||||
openDialog: (row: sourceItemType | {}) => {
|
||||
editDialogRef.value.openDialog({shareConfig:{},...row});
|
||||
},
|
||||
// 删除
|
||||
clickDel: (row: sourceItemType) => {
|
||||
// delRelation_api(row.id).then((resp: any) => {
|
||||
// if (resp.status === 200) {
|
||||
// tableRef.value?.reload();
|
||||
// message.success('操作成功!');
|
||||
// }
|
||||
// });
|
||||
},
|
||||
clickChangeStatus: (row: sourceItemType) => {
|
||||
const status = row.state.value === 'enabled' ? '_disable' : '_enable';
|
||||
|
||||
changeStatus_api(row.id as string, status).then(() => {
|
||||
message.success('操作成功');
|
||||
table.refresh();
|
||||
});
|
||||
},
|
||||
// 刷新列表
|
||||
refresh: () => {
|
||||
tableRef.value.reload();
|
||||
},
|
||||
};
|
||||
table.getTypeOption();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.data-source-container {
|
||||
padding: 24px;
|
||||
:deep(.ant-table-cell) {
|
||||
.ant-btn-link {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,24 @@
|
|||
export type dictItemType = {
|
||||
id: string,
|
||||
name: string
|
||||
}
|
||||
export type optionItemType = {
|
||||
label: string,
|
||||
value: string
|
||||
}
|
||||
export type sourceItemType = {
|
||||
id?: string,
|
||||
name: string,
|
||||
state: { text: string, value: "enabled" | 'disabled' },
|
||||
typeId: string,
|
||||
shareConfig:{
|
||||
url:string,
|
||||
adminUrl:string,
|
||||
addresses:string,
|
||||
username:string,
|
||||
password:string,
|
||||
virtualHost:string,
|
||||
schema:string
|
||||
}
|
||||
description: string
|
||||
}
|
|
@ -20,7 +20,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { dictType, optionsType } from '../typing.d.ts';
|
||||
import type { dictType, optionsType } from '../typing';
|
||||
import { updatePermission_api } from '@/api/system/department';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
|
|
|
@ -167,7 +167,7 @@ import {
|
|||
} from '@/api/system/department';
|
||||
import { intersection } from 'lodash-es';
|
||||
|
||||
import { dictType } from '../typing.d.ts';
|
||||
import type { dictType } from '../typing';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
const permission = 'system/Department';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
type dictType = {
|
||||
export type dictType = {
|
||||
id: string;
|
||||
name: string;
|
||||
}[];
|
||||
|
||||
type optionsType = {
|
||||
export type optionsType = {
|
||||
label: string,
|
||||
value: string;
|
||||
disabled?:boolean
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
:columns="table.columns"
|
||||
:request="getRelationshipList_api"
|
||||
model="TABLE"
|
||||
:params="query.params"
|
||||
:params="query.params.value"
|
||||
:defaultParams="{ sorts: [{ name: 'createTime', order: 'desc' }] }"
|
||||
>
|
||||
<template #headerTitle>
|
||||
|
@ -122,9 +122,9 @@ const query = {
|
|||
},
|
||||
},
|
||||
],
|
||||
params: {},
|
||||
params: ref({}),
|
||||
search: (params: object) => {
|
||||
query.params = params;
|
||||
query.params.value = params;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue