mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 07:20:24 +08:00
refactor: PageTable组件重构、使用useFetch封装接口请求
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import request from './request';
|
||||
import { randomUuid } from './utils/string';
|
||||
import { useApiFetch } from './useRequest';
|
||||
|
||||
/**
|
||||
* 可用于各模块定义各自api请求
|
||||
@@ -21,8 +21,6 @@ class Api {
|
||||
*/
|
||||
beforeHandler: Function;
|
||||
|
||||
static abortControllers: Map<string, AbortController> = new Map();
|
||||
|
||||
constructor(url: string, method: string) {
|
||||
this.url = url;
|
||||
this.method = method;
|
||||
@@ -46,68 +44,38 @@ class Api {
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求对应的该api
|
||||
* 响应式使用该api
|
||||
* @param params 响应式params
|
||||
* @param reqOptions 其他可选值
|
||||
* @returns
|
||||
*/
|
||||
useApi<T>(params: any = null, reqOptions: RequestInit = {}) {
|
||||
return useApiFetch<T>(this, params, reqOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch 请求对应的该api
|
||||
* @param {Object} param 请求该api的参数
|
||||
*/
|
||||
request(param: any = null, options: any = {}): Promise<any> {
|
||||
async request(param: any = null, options: any = {}): Promise<any> {
|
||||
const { execute, data } = this.useApi(param, options);
|
||||
await execute();
|
||||
return data.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* xhr 请求对应的该api
|
||||
* @param {Object} param 请求该api的参数
|
||||
*/
|
||||
async xhrReq(param: any = null, options: any = {}): Promise<any> {
|
||||
if (this.beforeHandler) {
|
||||
this.beforeHandler(param);
|
||||
}
|
||||
return request.request(this.method, this.url, param, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 允许取消的请求, 使用Api.cancelReq(key) 取消请求
|
||||
* @param key 用于取消该key关联的请求
|
||||
* @param {Object} param 请求该api的参数
|
||||
*/
|
||||
allowCancelReq(key: string, param: any = null, options: RequestInit = {}): Promise<any> {
|
||||
let controller = Api.abortControllers.get(key);
|
||||
if (!controller) {
|
||||
controller = new AbortController();
|
||||
Api.abortControllers.set(key, controller);
|
||||
}
|
||||
options.signal = controller.signal;
|
||||
|
||||
return this.request(param, options);
|
||||
return request.xhrReq(this.method, this.url, param, options);
|
||||
}
|
||||
|
||||
/** 静态方法 **/
|
||||
|
||||
/**
|
||||
* 取消请求
|
||||
* @param key 请求key
|
||||
*/
|
||||
static cancelReq(key: string) {
|
||||
let controller = Api.abortControllers.get(key);
|
||||
if (controller) {
|
||||
controller.abort();
|
||||
Api.removeAbortKey(key);
|
||||
}
|
||||
}
|
||||
|
||||
static removeAbortKey(key: string) {
|
||||
if (key) {
|
||||
console.log('remove abort key: ', key);
|
||||
Api.abortControllers.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据旧key生成新的abort key,可能旧key未取消,造成多余无用对象
|
||||
* @param oldKey 旧key
|
||||
* @returns key
|
||||
*/
|
||||
static genAbortKey(oldKey: string) {
|
||||
if (!oldKey) {
|
||||
return randomUuid();
|
||||
}
|
||||
if (Api.abortControllers.get(oldKey)) {
|
||||
return oldKey;
|
||||
}
|
||||
return randomUuid();
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂,返回Api对象,并设置url与method属性
|
||||
* @param url url
|
||||
@@ -151,3 +119,8 @@ class Api {
|
||||
}
|
||||
|
||||
export default Api;
|
||||
|
||||
export class PageRes {
|
||||
list: any[] = [];
|
||||
total: number = 0;
|
||||
}
|
||||
|
||||
@@ -4,10 +4,12 @@ import { getClientId, getToken } from './utils/storage';
|
||||
import { templateResolve } from './utils/string';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import axios from 'axios';
|
||||
import { useApiFetch } from './useRequest';
|
||||
import Api from './Api';
|
||||
|
||||
export default {
|
||||
request,
|
||||
fetchReq,
|
||||
xhrReq,
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
@@ -30,7 +32,7 @@ export interface Result {
|
||||
data?: any;
|
||||
}
|
||||
|
||||
enum ResultEnum {
|
||||
export enum ResultEnum {
|
||||
SUCCESS = 200,
|
||||
ERROR = 400,
|
||||
PARAM_ERROR = 405,
|
||||
@@ -38,7 +40,7 @@ enum ResultEnum {
|
||||
NO_PERMISSION = 501,
|
||||
}
|
||||
|
||||
const baseUrl: string = config.baseApiUrl;
|
||||
export const baseUrl: string = config.baseApiUrl;
|
||||
// const baseUrl: string = 'http://localhost:18888/api';
|
||||
// const baseWsUrl: string = config.baseWsUrl;
|
||||
|
||||
@@ -115,14 +117,15 @@ axiosInst.interceptors.response.use(
|
||||
);
|
||||
|
||||
/**
|
||||
* 请求uri
|
||||
* 该方法已处理请求结果中code != 200的message提示,如需其他错误处理(取消加载状态,重置对象状态等等),可catch继续处理
|
||||
* xhr请求url
|
||||
*
|
||||
* @param {Object} method 请求方法(GET,POST,PUT,DELTE等)
|
||||
* @param {Object} uri uri
|
||||
* @param {Object} params 参数
|
||||
* @param method 请求方法
|
||||
* @param url url
|
||||
* @param params 参数
|
||||
* @param options 可选
|
||||
* @returns
|
||||
*/
|
||||
function request(method: string, url: string, params: any = null, options: any = {}): Promise<any> {
|
||||
export function xhrReq(method: string, url: string, params: any = null, options: any = {}) {
|
||||
if (!url) {
|
||||
throw new Error('请求url不能为空');
|
||||
}
|
||||
@@ -157,6 +160,21 @@ function request(method: string, url: string, params: any = null, options: any =
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch请求url
|
||||
*
|
||||
* 该方法已处理请求结果中code != 200的message提示,如需其他错误处理(取消加载状态,重置对象状态等等),可catch继续处理
|
||||
*
|
||||
* @param {Object} method 请求方法(GET,POST,PUT,DELTE等)
|
||||
* @param {Object} uri uri
|
||||
* @param {Object} params 参数
|
||||
*/
|
||||
async function request(method: string, url: string, params: any = null, options: any = {}): Promise<any> {
|
||||
const { execute, data } = useApiFetch(Api.create(url, method), params, options);
|
||||
await execute();
|
||||
return data.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get请求uri
|
||||
* 该方法已处理请求结果中code != 200的message提示,如需其他错误处理(取消加载状态,重置对象状态等等),可catch继续处理
|
||||
@@ -190,64 +208,6 @@ export function joinClientParams(): string {
|
||||
return `token=${getToken()}&clientId=${getClientId()}`;
|
||||
}
|
||||
|
||||
async function fetchReq(method: string, url: string, params: any = null, options: RequestInit = {}): Promise<any> {
|
||||
options.method = method;
|
||||
|
||||
if (params) {
|
||||
// post和put使用json格式传参
|
||||
if (method === 'post' || method === 'put') {
|
||||
options.body = JSON.stringify(params);
|
||||
} else {
|
||||
const searchParam = new URLSearchParams();
|
||||
Object.keys(params).forEach((key) => {
|
||||
const val = params[key];
|
||||
if (val) {
|
||||
searchParam.append(key, val);
|
||||
}
|
||||
});
|
||||
url = `${url}?${searchParam.toString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Part 1: Add headers and attach auth token
|
||||
const headers = new Headers(options.headers || {});
|
||||
|
||||
const token = getToken();
|
||||
if (token) {
|
||||
headers.set('Authorization', token);
|
||||
headers.set('ClientId', getClientId());
|
||||
}
|
||||
options.headers = headers;
|
||||
|
||||
try {
|
||||
const res: Response = await fetch(`${baseUrl}${url}`, options);
|
||||
if (!res.ok) {
|
||||
throw new Error(`请求响应错误: 状态码=${res.status}`);
|
||||
}
|
||||
|
||||
const jsonRes = await res.json();
|
||||
// 获取请求返回结果
|
||||
const result: Result = jsonRes;
|
||||
return parseResult(result);
|
||||
} catch (e: any) {
|
||||
const rejectPromise = Promise.reject(e);
|
||||
|
||||
if (e?.name == 'AbortError') {
|
||||
console.log('请求已取消');
|
||||
return rejectPromise;
|
||||
}
|
||||
|
||||
if (e.message) {
|
||||
notifyErrorMsg(e.message);
|
||||
return rejectPromise;
|
||||
}
|
||||
|
||||
notifyErrorMsg('网络请求错误');
|
||||
console.error(e);
|
||||
return rejectPromise;
|
||||
}
|
||||
}
|
||||
|
||||
function parseResult(result: Result) {
|
||||
if (result.code === ResultEnum.SUCCESS) {
|
||||
return result.data;
|
||||
|
||||
134
mayfly_go_web/src/common/useRequest.ts
Normal file
134
mayfly_go_web/src/common/useRequest.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
import router from '../router';
|
||||
import { getClientId, getToken } from './utils/storage';
|
||||
import { templateResolve } from './utils/string';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { createFetch } from '@vueuse/core';
|
||||
import Api from './Api';
|
||||
import { Result, ResultEnum } from './request';
|
||||
import config from './config';
|
||||
import { unref } from 'vue';
|
||||
|
||||
const baseUrl: string = config.baseApiUrl;
|
||||
|
||||
const useCustomFetch = createFetch({
|
||||
baseUrl: baseUrl,
|
||||
combination: 'chain',
|
||||
options: {
|
||||
immediate: false,
|
||||
timeout: 60000,
|
||||
// beforeFetch in pre-configured instance will only run when the newly spawned instance do not pass beforeFetch
|
||||
async beforeFetch({ options }) {
|
||||
const token = getToken();
|
||||
|
||||
const headers = new Headers(options.headers || {});
|
||||
if (token) {
|
||||
headers.set('Authorization', token);
|
||||
headers.set('ClientId', getClientId());
|
||||
}
|
||||
options.headers = headers;
|
||||
|
||||
return { options };
|
||||
},
|
||||
async afterFetch(ctx) {
|
||||
const result: Result = await ctx.response.json();
|
||||
ctx.data = result;
|
||||
return ctx;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function useApiFetch<T>(api: Api, params: any = null, reqOptions: RequestInit = {}) {
|
||||
const uaf = useCustomFetch<T>(api.url, {
|
||||
beforeFetch({ url, options }) {
|
||||
options.method = api.method;
|
||||
if (!params) {
|
||||
return;
|
||||
}
|
||||
|
||||
let paramsValue = unref(params);
|
||||
if (api.beforeHandler) {
|
||||
paramsValue = api.beforeHandler(paramsValue);
|
||||
}
|
||||
|
||||
let apiUrl = url;
|
||||
// 简单判断该url是否是restful风格
|
||||
if (apiUrl.indexOf('{') != -1) {
|
||||
apiUrl = templateResolve(apiUrl, paramsValue);
|
||||
}
|
||||
|
||||
if (paramsValue) {
|
||||
const method = options.method?.toLowerCase();
|
||||
// post和put使用json格式传参
|
||||
if (method === 'post' || method === 'put') {
|
||||
options.body = JSON.stringify(paramsValue);
|
||||
} else {
|
||||
const searchParam = new URLSearchParams();
|
||||
Object.keys(paramsValue).forEach((key) => {
|
||||
const val = paramsValue[key];
|
||||
if (val) {
|
||||
searchParam.append(key, val);
|
||||
}
|
||||
});
|
||||
apiUrl = `${apiUrl}?${searchParam.toString()}`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
url: apiUrl,
|
||||
options: {
|
||||
...options,
|
||||
...reqOptions,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
execute: async function () {
|
||||
try {
|
||||
await uaf.execute(true);
|
||||
} catch (e: any) {
|
||||
const rejectPromise = Promise.reject(e);
|
||||
|
||||
if (e?.name == 'AbortError') {
|
||||
console.log('请求已取消');
|
||||
return rejectPromise;
|
||||
}
|
||||
|
||||
console.error(e);
|
||||
ElMessage.error('网络请求错误');
|
||||
return rejectPromise;
|
||||
}
|
||||
|
||||
const result: Result = uaf.data.value as any;
|
||||
if (!result) {
|
||||
ElMessage.error('网络请求失败');
|
||||
return Promise.reject(result);
|
||||
}
|
||||
|
||||
// 如果返回为成功结果,则将结果的data赋值给响应式data
|
||||
if (result.code === ResultEnum.SUCCESS) {
|
||||
uaf.data.value = result.data;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果提示没有权限,则移除token,使其重新登录
|
||||
if (result.code === ResultEnum.NO_PERMISSION) {
|
||||
router.push({
|
||||
path: '/401',
|
||||
});
|
||||
}
|
||||
|
||||
// 如果返回的code不为成功,则会返回对应的错误msg,则直接统一通知即可。忽略登录超时或没有权限的提示(直接跳转至401页面)
|
||||
if (result.msg && result?.code != ResultEnum.NO_PERMISSION) {
|
||||
ElMessage.error(result.msg);
|
||||
uaf.error.value = new Error(result.msg);
|
||||
}
|
||||
|
||||
return Promise.reject(result);
|
||||
},
|
||||
isFetching: uaf.isFetching,
|
||||
data: uaf.data,
|
||||
abort: uaf.abort,
|
||||
};
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="query" ref="queryRef">
|
||||
<div>
|
||||
<div v-if="props.query.length > 0">
|
||||
<el-form :model="props.queryForm" label-width="auto" :size="props.size">
|
||||
<el-form :model="queryForm_" label-width="auto" :size="props.size">
|
||||
<el-row
|
||||
v-for="i in Math.ceil((props.query.length + 1) / (defaultQueryCount + 1))"
|
||||
:key="i"
|
||||
@@ -104,9 +104,9 @@
|
||||
v-bind="$attrs"
|
||||
:max-height="tableMaxHeight"
|
||||
@selection-change="handleSelectionChange"
|
||||
:data="props.data"
|
||||
:data="state.data"
|
||||
highlight-current-row
|
||||
v-loading="loadingData"
|
||||
v-loading="state.loading"
|
||||
:size="props.size"
|
||||
>
|
||||
<el-table-column v-if="props.showSelection" type="selection" width="40" />
|
||||
@@ -171,9 +171,9 @@
|
||||
@size-change="handleSizeChange"
|
||||
style="text-align: right"
|
||||
layout="prev, pager, next, total, sizes, jumper"
|
||||
:total="props.total"
|
||||
v-model:current-page="state.pageNum"
|
||||
v-model:page-size="state.pageSize"
|
||||
:total="state.total"
|
||||
v-model:current-page="queryForm_.pageNum"
|
||||
v-model:page-size="queryForm_.pageSize"
|
||||
:page-sizes="pageSizes"
|
||||
/>
|
||||
</el-row>
|
||||
@@ -182,11 +182,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { toRefs, watch, reactive, onMounted } from 'vue';
|
||||
import { toRefs, watch, reactive, onMounted, Ref } from 'vue';
|
||||
import { TableColumn, TableQuery } from './index';
|
||||
import EnumTag from '@/components/enumtag/EnumTag.vue';
|
||||
import { useThemeConfig } from '@/store/themeConfig';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useVModel } from '@vueuse/core';
|
||||
import Api from '@/common/Api';
|
||||
|
||||
const emit = defineEmits(['update:queryForm', 'update:pageNum', 'update:pageSize', 'update:selectionData', 'pageChange']);
|
||||
|
||||
@@ -216,22 +218,19 @@ const props = defineProps({
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// 表格数据
|
||||
data: {
|
||||
type: Array,
|
||||
// 调用分页数据的api
|
||||
pageApi: {
|
||||
type: Api,
|
||||
required: true,
|
||||
},
|
||||
total: {
|
||||
type: [Number],
|
||||
default: 0,
|
||||
// 数据处理回调函数,用于将请求回来的数据二次加工处理等
|
||||
dataHandlerFn: {
|
||||
type: Function,
|
||||
},
|
||||
pageNum: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
pageSize: {
|
||||
type: [Number],
|
||||
default: 10,
|
||||
// 懒加载,即需要手动调用search方法才可调接口获取数据,不会在mounted的时候调用。
|
||||
lazy: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 查询条件配置
|
||||
query: {
|
||||
@@ -244,7 +243,10 @@ const props = defineProps({
|
||||
queryForm: {
|
||||
type: Object,
|
||||
default: function () {
|
||||
return {};
|
||||
return {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -253,56 +255,36 @@ const { themeConfig } = storeToRefs(useThemeConfig());
|
||||
|
||||
const state = reactive({
|
||||
pageSizes: [] as any, // 可选每页显示的数据量
|
||||
pageSize: 10,
|
||||
pageNum: 1,
|
||||
isOpenMoreQuery: false,
|
||||
defaultQueryCount: 2, // 默认显示的查询参数个数,展开后每行显示查询条件个数为该值加1。第一行用最后一列来占用按钮
|
||||
queryForm_: {} as any,
|
||||
loadingData: false,
|
||||
loading: false,
|
||||
data: [],
|
||||
total: 0,
|
||||
// 输入框宽度
|
||||
inputWidth_: '200px' as any,
|
||||
formatVal: '', // 格式化后的值
|
||||
tableMaxHeight: window.innerHeight - 240 + 'px',
|
||||
});
|
||||
|
||||
const { pageSizes, isOpenMoreQuery, defaultQueryCount, queryForm_, inputWidth_, formatVal, loadingData, tableMaxHeight } = toRefs(state);
|
||||
const { pageSizes, isOpenMoreQuery, defaultQueryCount, inputWidth_, formatVal, tableMaxHeight } = toRefs(state);
|
||||
|
||||
const queryForm_: Ref<any> = useVModel(props, 'queryForm', emit);
|
||||
|
||||
watch(
|
||||
() => props.queryForm,
|
||||
(newValue: any) => {
|
||||
state.queryForm_ = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.pageNum,
|
||||
(newValue: any) => {
|
||||
state.pageNum = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.pageSize,
|
||||
(newValue: any) => {
|
||||
state.pageSize = newValue;
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
() => state.data,
|
||||
(newValue: any) => {
|
||||
if (newValue && newValue.length > 0) {
|
||||
props.columns.forEach((item) => {
|
||||
if (item.autoWidth && item.show) {
|
||||
item.autoCalculateMinWidth(props.data);
|
||||
item.autoCalculateMinWidth(state.data);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
let pageSize = props.pageSize;
|
||||
onMounted(async () => {
|
||||
let pageSize = queryForm_.value.pageSize;
|
||||
|
||||
// 如果pageSize设为0,则使用系统全局配置的pageSize
|
||||
if (!pageSize) {
|
||||
@@ -311,12 +293,10 @@ onMounted(() => {
|
||||
if (!pageSize) {
|
||||
pageSize = 10;
|
||||
}
|
||||
emit('update:pageSize', pageSize);
|
||||
}
|
||||
|
||||
state.pageNum = props.pageNum;
|
||||
state.pageSize = pageSize;
|
||||
state.queryForm_ = props.queryForm;
|
||||
queryForm_.value.pageNum = 1;
|
||||
queryForm_.value.pageSize = pageSize;
|
||||
state.pageSizes = [pageSize, pageSize * 2, pageSize * 3, pageSize * 4, pageSize * 5];
|
||||
|
||||
// 如果没传输入框宽度,则根据组件size设置默认宽度
|
||||
@@ -329,6 +309,10 @@ onMounted(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
calcuTableHeight();
|
||||
});
|
||||
|
||||
if (!props.lazy) {
|
||||
await reqPageApi();
|
||||
}
|
||||
});
|
||||
|
||||
const calcuTableHeight = () => {
|
||||
@@ -360,14 +344,28 @@ const handleSelectionChange = (val: any) => {
|
||||
emit('update:selectionData', val);
|
||||
};
|
||||
|
||||
const handlePageChange = () => {
|
||||
emit('update:pageNum', state.pageNum);
|
||||
const reqPageApi = async () => {
|
||||
try {
|
||||
state.loading = true;
|
||||
const res = await props.pageApi?.request(queryForm_.value);
|
||||
if (props.dataHandlerFn) {
|
||||
state.data = await props.dataHandlerFn(res.list);
|
||||
} else {
|
||||
state.data = res.list;
|
||||
}
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
state.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePageChange = (val: number) => {
|
||||
queryForm_.value.pageNum = val;
|
||||
execQuery();
|
||||
};
|
||||
|
||||
const handleSizeChange = () => {
|
||||
changePageNum(1);
|
||||
emit('update:pageSize', state.pageSize);
|
||||
execQuery();
|
||||
};
|
||||
|
||||
@@ -379,31 +377,24 @@ const queryData = () => {
|
||||
const reset = () => {
|
||||
// 将查询参数绑定的值置空,并重新粗发查询接口
|
||||
for (let qi of props.query) {
|
||||
state.queryForm_[qi.prop] = null;
|
||||
queryForm_.value[qi.prop] = null;
|
||||
}
|
||||
|
||||
changePageNum(1);
|
||||
emit('update:queryForm', state.queryForm_);
|
||||
execQuery();
|
||||
};
|
||||
|
||||
const changePageNum = (pageNum: number) => {
|
||||
state.pageNum = pageNum;
|
||||
emit('update:pageNum', state.pageNum);
|
||||
queryForm_.value.pageNum = pageNum;
|
||||
};
|
||||
|
||||
const execQuery = () => {
|
||||
emit('pageChange');
|
||||
const execQuery = async () => {
|
||||
await reqPageApi();
|
||||
};
|
||||
|
||||
/**
|
||||
* 是否正在加载数据
|
||||
*/
|
||||
const loading = (loading: boolean) => {
|
||||
state.loadingData = loading;
|
||||
};
|
||||
|
||||
defineExpose({ loading });
|
||||
defineExpose({
|
||||
search: execQuery,
|
||||
});
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.page-table {
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -155,11 +155,12 @@ const state = reactive({
|
||||
remark: '',
|
||||
instanceId: null as any,
|
||||
},
|
||||
btnLoading: false,
|
||||
instances: [] as any,
|
||||
});
|
||||
|
||||
const { dialogVisible, allDatabases, databaseList, form, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, allDatabases, form, databaseList } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveDbExec } = dbApi.saveDb.useApi(form);
|
||||
|
||||
watch(props, async (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -216,22 +217,15 @@ const open = async () => {
|
||||
|
||||
const btnOk = async () => {
|
||||
dbForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
const reqForm = { ...state.form };
|
||||
dbApi.saveDb.request(reqForm).then(() => {
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
|
||||
cancel();
|
||||
});
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
await saveDbExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div class="db-list">
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="dbApi.dbs"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="state.selectionData"
|
||||
:data="datas"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #tagPathSelect>
|
||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" filterable clearable style="width: 200px">
|
||||
@@ -140,7 +136,7 @@
|
||||
|
||||
<el-dialog v-model="infoDialog.visible" :before-close="onBeforeCloseInfoDialog" :close-on-click-modal="false">
|
||||
<el-descriptions title="详情" :column="3" border>
|
||||
<el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data?.tagPath }}</el-descriptions-item>
|
||||
<!-- <el-descriptions-item :span="3" label="标签路径">{{ infoDialog.data?.tagPath }}</el-descriptions-item> -->
|
||||
<el-descriptions-item :span="2" label="名称">{{ infoDialog.data?.name }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="1" label="id">{{ infoDialog.data?.id }}</el-descriptions-item>
|
||||
<el-descriptions-item :span="3" label="数据库">{{ infoDialog.data?.database }}</el-descriptions-item>
|
||||
@@ -158,12 +154,12 @@
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
|
||||
<db-edit @val-change="valChange" :title="dbEditDialog.title" v-model:visible="dbEditDialog.visible" v-model:db="dbEditDialog.data"></db-edit>
|
||||
<db-edit @val-change="search" :title="dbEditDialog.title" v-model:visible="dbEditDialog.visible" v-model:db="dbEditDialog.data"></db-edit>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { dbApi } from './api';
|
||||
import config from '@/common/config';
|
||||
@@ -206,8 +202,7 @@ const actionBtns = hasPerms([perms.base, perms.saveDb]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(220).fixedRight().alignCenter();
|
||||
|
||||
const route = useRoute();
|
||||
const pageTableRef: any = ref(null);
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const state = reactive({
|
||||
row: {} as any,
|
||||
dbId: 0,
|
||||
@@ -227,8 +222,6 @@ const state = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
},
|
||||
datas: [],
|
||||
total: 0,
|
||||
infoDialog: {
|
||||
visible: false,
|
||||
data: null as any,
|
||||
@@ -265,33 +258,19 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { db, tags, selectionData, query, datas, total, infoDialog, sqlExecLogDialog, exportDialog, dbEditDialog } = toRefs(state);
|
||||
const { db, tags, selectionData, query, infoDialog, sqlExecLogDialog, exportDialog, dbEditDialog } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
columns.value.push(actionColumn);
|
||||
}
|
||||
search();
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
let res: any = await dbApi.dbs.request(state.query);
|
||||
// 切割数据库
|
||||
res.list?.forEach((e: any) => {
|
||||
e.popoverSelectDbVisible = false;
|
||||
e.dbs = e.database.split(' ');
|
||||
});
|
||||
state.datas = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showInfo = async (info: any) => {
|
||||
@@ -352,10 +331,6 @@ const editDb = async (data: any) => {
|
||||
state.dbEditDialog.visible = true;
|
||||
};
|
||||
|
||||
const valChange = () => {
|
||||
search();
|
||||
};
|
||||
|
||||
const deleteDb = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除【${state.selectionData.map((x: any) => x.name).join(', ')}】库?`, '提示', {
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
<template>
|
||||
<div class="db-sql-exec-log">
|
||||
<page-table
|
||||
height="100%"
|
||||
ref="sqlExecDialogPageTableRef"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="searchSqlExecLog()"
|
||||
>
|
||||
<page-table ref="pageTableRef" :page-api="dbApi.getSqlExecs" height="100%" :query="queryConfig" v-model:query-form="query" :columns="columns">
|
||||
<template #dbSelect>
|
||||
<el-select v-model="query.db" placeholder="请选择数据库" style="width: 200px" filterable clearable>
|
||||
<el-option v-for="item in dbs" :key="item" :label="`${item}`" :value="item"> </el-option>
|
||||
@@ -39,7 +28,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { toRefs, watch, reactive, onMounted } from 'vue';
|
||||
import { toRefs, watch, reactive, onMounted, Ref, ref } from 'vue';
|
||||
import { dbApi } from './api';
|
||||
import { DbSqlExecTypeEnum } from './enums';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
@@ -74,9 +63,9 @@ const columns = [
|
||||
TableColumn.new('action', '操作').isSlot().setMinWidth(90).fixedRight().alignCenter(),
|
||||
];
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
data: [],
|
||||
total: 0,
|
||||
dbs: [],
|
||||
query: {
|
||||
dbId: 0,
|
||||
@@ -97,21 +86,18 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { data, query, total, rollbackSqlDialog } = toRefs(state);
|
||||
const { query, rollbackSqlDialog } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
searchSqlExecLog();
|
||||
});
|
||||
onMounted(async () => {});
|
||||
|
||||
watch(props, async () => {
|
||||
state.query.dbId = props.dbId;
|
||||
state.query.pageNum = 1;
|
||||
await searchSqlExecLog();
|
||||
});
|
||||
|
||||
const searchSqlExecLog = async () => {
|
||||
state.query.dbId = props.dbId;
|
||||
const res = await dbApi.getSqlExecs.request(state.query);
|
||||
state.data = res.list;
|
||||
state.total = res.total;
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const onShowRollbackSql = async (sqlExecLog: any) => {
|
||||
|
||||
@@ -71,9 +71,9 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="testConn" :loading="state.testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="testConn" :loading="testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -168,15 +168,17 @@ const state = reactive({
|
||||
remark: '',
|
||||
sshTunnelMachineId: null as any,
|
||||
},
|
||||
subimtForm: {},
|
||||
// 原密码
|
||||
pwd: '',
|
||||
// 原用户名
|
||||
oldUserName: null,
|
||||
btnLoading: false,
|
||||
testConnBtnLoading: false,
|
||||
});
|
||||
|
||||
const { dialogVisible, tabActiveName, form, pwd, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, tabActiveName, form, subimtForm, pwd } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveInstanceExec } = dbApi.saveInstance.useApi(subimtForm);
|
||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = dbApi.testConn.useApi(subimtForm);
|
||||
|
||||
watch(props, (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -214,18 +216,14 @@ const getReqForm = async () => {
|
||||
|
||||
const testConn = async () => {
|
||||
dbForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
state.testConnBtnLoading = true;
|
||||
try {
|
||||
await dbApi.testConn.request(await getReqForm());
|
||||
ElMessage.success('连接成功');
|
||||
} finally {
|
||||
state.testConnBtnLoading = false;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.subimtForm = await getReqForm();
|
||||
await testConnExec();
|
||||
ElMessage.success('连接成功');
|
||||
});
|
||||
};
|
||||
|
||||
@@ -237,21 +235,16 @@ const btnOk = async () => {
|
||||
}
|
||||
|
||||
dbForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
dbApi.saveInstance.request(await getReqForm()).then(() => {
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
|
||||
cancel();
|
||||
});
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.subimtForm = await getReqForm();
|
||||
await saveInstanceExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div class="db-list">
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="dbApi.instances"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="state.selectionData"
|
||||
:data="datas"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="perms.saveInstance" type="primary" icon="plus" @click="editInstance(false)">添加</el-button>
|
||||
@@ -56,7 +52,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<instance-edit
|
||||
@val-change="valChange"
|
||||
@val-change="search"
|
||||
:title="instanceEditDialog.title"
|
||||
v-model:visible="instanceEditDialog.visible"
|
||||
v-model:data="instanceEditDialog.data"
|
||||
@@ -65,7 +61,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { dbApi } from './api';
|
||||
import { dateFormat } from '@/common/utils/date';
|
||||
@@ -96,8 +92,7 @@ const columns = ref([
|
||||
// 该用户拥有的的操作列按钮权限
|
||||
const actionBtns = hasPerms([perms.saveInstance]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(110).fixedRight().alignCenter();
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
row: {},
|
||||
@@ -115,8 +110,6 @@ const state = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
},
|
||||
datas: [],
|
||||
total: 0,
|
||||
infoDialog: {
|
||||
visible: false,
|
||||
data: null as any,
|
||||
@@ -128,24 +121,16 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { selectionData, query, datas, total, infoDialog, instanceEditDialog } = toRefs(state);
|
||||
const { selectionData, query, infoDialog, instanceEditDialog } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
columns.value.push(actionColumn);
|
||||
}
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
let res: any = await dbApi.instances.request(state.query);
|
||||
state.datas = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
const search = () => {
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showInfo = (info: any) => {
|
||||
@@ -164,10 +149,6 @@ const editInstance = async (data: any) => {
|
||||
state.instanceEditDialog.visible = true;
|
||||
};
|
||||
|
||||
const valChange = () => {
|
||||
search();
|
||||
};
|
||||
|
||||
const deleteInstance = async () => {
|
||||
try {
|
||||
await ElMessageBox.confirm(`确定删除数据库实例【${state.selectionData.map((x: any) => x.name).join(', ')}】?`, '提示', {
|
||||
|
||||
@@ -20,6 +20,7 @@ export const dbApi = {
|
||||
if (param.sql) {
|
||||
param.sql = Base64.encode(param.sql);
|
||||
}
|
||||
return param;
|
||||
}),
|
||||
// 保存sql
|
||||
saveSql: Api.newPost('/dbs/{id}/sql'),
|
||||
|
||||
@@ -111,7 +111,7 @@
|
||||
:table="dt.table"
|
||||
:columns="dt.tableColumn"
|
||||
:loading="dt.loading"
|
||||
:loading-key="dt.loadingKey"
|
||||
:abort-fn="dt.abortFn"
|
||||
:height="tableDataHeight"
|
||||
empty-text="tips: select *开头的单表查询或点击表名默认查询的数据,可双击数据在线修改"
|
||||
@change-updated-field="changeUpdatedField($event, dt)"
|
||||
@@ -128,7 +128,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, nextTick, onMounted, reactive, toRefs, ref, onBeforeUnmount } from 'vue';
|
||||
import { h, nextTick, onMounted, reactive, toRefs, ref } from 'vue';
|
||||
import { getToken } from '@/common/utils/storage';
|
||||
import { notBlank } from '@/common/assert';
|
||||
import { format as sqlFormatter } from 'sql-formatter';
|
||||
@@ -151,7 +151,6 @@ import syssocket from '@/common/syssocket';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import { getDbDialect } from '../../dialect';
|
||||
import { Splitpanes, Pane } from 'splitpanes';
|
||||
import Api from '@/common/Api';
|
||||
|
||||
const emits = defineEmits(['saveSqlSuccess']);
|
||||
|
||||
@@ -178,12 +177,15 @@ class ExecResTab {
|
||||
*/
|
||||
sql: string;
|
||||
|
||||
loading: boolean;
|
||||
|
||||
loadingKey: string;
|
||||
/**
|
||||
* 响应式loading
|
||||
*/
|
||||
loading: any;
|
||||
|
||||
dbTableRef: any;
|
||||
|
||||
abortFn: Function;
|
||||
|
||||
tableColumn: any[] = [];
|
||||
|
||||
data: any[] = [];
|
||||
@@ -252,12 +254,6 @@ onMounted(async () => {
|
||||
await getNowDbInst().loadDbHints(props.dbName);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
state.execResTabs.forEach((x: ExecResTab) => {
|
||||
Api.removeAbortKey(x.loadingKey);
|
||||
});
|
||||
});
|
||||
|
||||
const onRemoveTab = (targetId: number) => {
|
||||
let activeTab = state.activeTab;
|
||||
const tabs = [...state.execResTabs];
|
||||
@@ -339,7 +335,7 @@ const onRunSql = async (newTab = false) => {
|
||||
// 不是新建tab执行,则在当前激活的tab上执行sql
|
||||
i = state.execResTabs.findIndex((x) => x.id == state.activeTab);
|
||||
execRes = state.execResTabs[i];
|
||||
if (execRes.loading) {
|
||||
if (execRes.loading?.value) {
|
||||
ElMessage.error('当前结果集tab正在执行, 请使用新标签执行');
|
||||
return;
|
||||
}
|
||||
@@ -349,18 +345,19 @@ const onRunSql = async (newTab = false) => {
|
||||
state.activeTab = id;
|
||||
const startTime = new Date().getTime();
|
||||
try {
|
||||
execRes.loading = true;
|
||||
execRes.errorMsg = '';
|
||||
execRes.sql = '';
|
||||
|
||||
// 用于取消执行
|
||||
const loadingKey = Api.genAbortKey(execRes.loadingKey);
|
||||
execRes.loadingKey = loadingKey;
|
||||
const { data, execute, isFetching, abort } = getNowDbInst().execSql(props.dbName, sql, execRemark);
|
||||
execRes.loading = isFetching;
|
||||
execRes.abortFn = abort;
|
||||
|
||||
const colAndData: any = await getNowDbInst().runSql(props.dbName, sql, execRemark, loadingKey);
|
||||
await execute();
|
||||
const colAndData: any = data.value;
|
||||
if (!colAndData.res || colAndData.res.length === 0) {
|
||||
ElMessage.warning('未查询到结果集');
|
||||
}
|
||||
|
||||
// 要实时响应,故需要用索引改变数据才生效
|
||||
state.execResTabs[i].data = colAndData.res;
|
||||
// 兼容表格字段配置
|
||||
@@ -378,7 +375,6 @@ const onRunSql = async (newTab = false) => {
|
||||
execRes.errorMsg = e.msg;
|
||||
return;
|
||||
} finally {
|
||||
state.execResTabs[i].loading = false;
|
||||
execRes.sql = sql;
|
||||
execRes.execTime = new Date().getTime() - startTime;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
<SvgIcon class="is-loading" name="loading" color="var(--el-color-primary)" :size="28" />
|
||||
<el-text class="ml5" tag="b">执行时间 - {{ state.execTime.toFixed(1) }}s</el-text>
|
||||
</div>
|
||||
<div v-if="loadingKey" class="mt10">
|
||||
<div v-if="loading && abortFn" class="mt10">
|
||||
<el-button @click="cancelLoading" type="info" size="small" plain>取 消</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -133,7 +133,6 @@ import { ContextmenuItem, Contextmenu } from '@/components/contextmenu';
|
||||
import SvgIcon from '@/components/svgIcon/index.vue';
|
||||
import { exportCsv, exportFile } from '@/common/utils/export';
|
||||
import { dateStrFormat } from '@/common/utils/date';
|
||||
import Api from '@/common/Api';
|
||||
import { useIntervalFn } from '@vueuse/core';
|
||||
|
||||
const emits = defineEmits(['dataDelete', 'sortChange', 'deleteData', 'selectionChange', 'changeUpdatedField']);
|
||||
@@ -165,8 +164,8 @@ const props = defineProps({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
loadingKey: {
|
||||
type: String,
|
||||
abortFn: {
|
||||
type: Function,
|
||||
},
|
||||
emptyText: {
|
||||
type: String,
|
||||
@@ -441,10 +440,8 @@ const endLoading = () => {
|
||||
};
|
||||
|
||||
const cancelLoading = async () => {
|
||||
if (props.loadingKey) {
|
||||
Api.cancelReq(props.loadingKey);
|
||||
endLoading();
|
||||
}
|
||||
props.abortFn && props.abortFn();
|
||||
endLoading();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -196,16 +196,7 @@ export class DbInst {
|
||||
* @param sql sql
|
||||
* @param remark 执行备注
|
||||
*/
|
||||
async runSql(dbName: string, sql: string, remark: string = '', key: string = '') {
|
||||
if (key) {
|
||||
return await dbApi.sqlExec.allowCancelReq(key, {
|
||||
id: this.id,
|
||||
db: dbName,
|
||||
sql: sql.trim(),
|
||||
remark,
|
||||
});
|
||||
}
|
||||
|
||||
async runSql(dbName: string, sql: string, remark: string = '') {
|
||||
return await dbApi.sqlExec.request({
|
||||
id: this.id,
|
||||
db: dbName,
|
||||
@@ -214,6 +205,22 @@ export class DbInst {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行sql(可取消的)
|
||||
*
|
||||
* @param sql sql
|
||||
* @param remark 执行备注
|
||||
*/
|
||||
execSql(dbName: string, sql: string, remark: string = '') {
|
||||
let dbId = this.id;
|
||||
return dbApi.sqlExec.useApi({
|
||||
id: dbId,
|
||||
db: dbName,
|
||||
sql: sql.trim(),
|
||||
remark,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取count sql
|
||||
* @param table 表名
|
||||
|
||||
@@ -118,6 +118,9 @@ let postgresDialect = new PostgresqlDialect();
|
||||
let dmDialect = new DMDialect();
|
||||
|
||||
export const getDbDialect = (dbType: string | undefined): DbDialect => {
|
||||
if (!dbType) {
|
||||
return mysqlDialect;
|
||||
}
|
||||
if (dbType === DbType.mysql) {
|
||||
return mysqlDialect;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<div>
|
||||
<el-button @click="testConn" :loading="testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -164,12 +164,14 @@ const state = reactive({
|
||||
sshTunnelMachineId: null as any,
|
||||
enableRecorder: -1,
|
||||
},
|
||||
submitForm: {},
|
||||
pwd: '',
|
||||
testConnBtnLoading: false,
|
||||
btnLoading: false,
|
||||
});
|
||||
|
||||
const { dialogVisible, tabActiveName, form, testConnBtnLoading, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, tabActiveName, form, submitForm } = toRefs(state);
|
||||
|
||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = machineApi.testConn.useApi(submitForm);
|
||||
const { isFetching: saveBtnLoading, execute: saveMachineExec } = machineApi.saveMachine.useApi(submitForm);
|
||||
|
||||
watch(props, async (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -205,45 +207,29 @@ const changeAuthMethod = (val: any) => {
|
||||
|
||||
const testConn = async () => {
|
||||
machineForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
const form = getReqForm();
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
state.testConnBtnLoading = true;
|
||||
try {
|
||||
await machineApi.testConn.request(form);
|
||||
ElMessage.success('连接成功');
|
||||
} finally {
|
||||
state.testConnBtnLoading = false;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.submitForm = getReqForm();
|
||||
await testConnExec();
|
||||
ElMessage.success('连接成功');
|
||||
});
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
machineForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
const form = getReqForm();
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
state.btnLoading = true;
|
||||
try {
|
||||
await machineApi.saveMachine.request(form);
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', form);
|
||||
cancel();
|
||||
} finally {
|
||||
state.btnLoading = false;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.submitForm = getReqForm();
|
||||
await saveMachineExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', submitForm);
|
||||
cancel();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="machineApi.list"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="params"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="state.selectionData"
|
||||
:data="data.list"
|
||||
:columns="columns"
|
||||
:total="data.total"
|
||||
v-model:page-size="params.pageSize"
|
||||
v-model:page-num="params.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #tagPathSelect>
|
||||
<el-select @focus="getTags" v-model="params.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
||||
@@ -186,7 +182,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent, Ref } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { machineApi, getMachineTerminalSocketUrl } from './api';
|
||||
@@ -210,8 +206,8 @@ const ProcessList = defineAsyncComponent(() => import('./ProcessList.vue'));
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const pageTableRef: any = ref(null);
|
||||
const terminalDialogRef: any = ref(null);
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const perms = {
|
||||
addMachine: 'machine:add',
|
||||
@@ -247,11 +243,6 @@ const state = reactive({
|
||||
name: null,
|
||||
tagPath: '',
|
||||
},
|
||||
// 列表数据
|
||||
data: {
|
||||
list: [],
|
||||
total: 10,
|
||||
},
|
||||
infoDialog: {
|
||||
visible: false,
|
||||
data: null as any,
|
||||
@@ -290,11 +281,13 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { tags, params, data, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } =
|
||||
const { tags, params, infoDialog, selectionData, serviceDialog, processDialog, fileDialog, machineStatsDialog, machineEditDialog, machineRecDialog } =
|
||||
toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
search();
|
||||
if (route.query.tagPath) {
|
||||
state.params.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
});
|
||||
|
||||
const handleCommand = (commond: any) => {
|
||||
@@ -421,6 +414,10 @@ const showMachineStats = async (machine: any) => {
|
||||
state.machineStatsDialog.visible = true;
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const submitSuccess = () => {
|
||||
search();
|
||||
};
|
||||
@@ -431,19 +428,6 @@ const showFileManage = (selectionData: any) => {
|
||||
state.fileDialog.title = `${selectionData.name} => ${selectionData.ip}`;
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
if (route.query.tagPath) {
|
||||
state.params.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
const res = await machineApi.list.request(state.params);
|
||||
state.data = res;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const getStatsFontClass = (availavle: number, total: number) => {
|
||||
const p = availavle / total;
|
||||
if (p < 0.1) {
|
||||
|
||||
@@ -11,14 +11,11 @@
|
||||
>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="machineApi.scripts"
|
||||
:lazy="true"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:data="scriptTable"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="getScripts()"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
>
|
||||
@@ -88,7 +85,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, watch } from 'vue';
|
||||
import { ref, toRefs, reactive, watch, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import TerminalBody from '@/components/terminal/TerminalBody.vue';
|
||||
import { getMachineTerminalSocketUrl, machineApi } from './api';
|
||||
@@ -107,7 +104,7 @@ const props = defineProps({
|
||||
const emit = defineEmits(['update:visible', 'cancel', 'update:machineId']);
|
||||
|
||||
const paramsForm: any = ref(null);
|
||||
const pageTableRef: any = ref(null);
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
@@ -150,24 +147,15 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { dialogVisible, queryConfig, columns, selectionData, query, editDialog, total, scriptTable, scriptParamsDialog, resultDialog, terminalDialog } =
|
||||
toRefs(state);
|
||||
const { dialogVisible, queryConfig, columns, selectionData, query, editDialog, scriptParamsDialog, resultDialog, terminalDialog } = toRefs(state);
|
||||
|
||||
watch(props, async (newValue) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
});
|
||||
|
||||
const getScripts = async () => {
|
||||
try {
|
||||
// 通过open事件才开获取到pageTableRef值
|
||||
pageTableRef.value.loading(true);
|
||||
state.query.machineId = state.query.type == ScriptTypeEnum.Private.value ? props.machineId : 9999999;
|
||||
const res = await machineApi.scripts.request(state.query);
|
||||
state.scriptTable = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
state.query.machineId = state.query.type == ScriptTypeEnum.Private.value ? props.machineId : 9999999;
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const runScript = async (script: any) => {
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="authCertApi.list"
|
||||
:query="state.queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="authcerts"
|
||||
:columns="state.columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button type="primary" icon="plus" @click="edit(false)">添加</el-button>
|
||||
@@ -27,7 +24,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { toRefs, reactive, onMounted } from 'vue';
|
||||
import { toRefs, reactive, onMounted, ref, Ref } from 'vue';
|
||||
import AuthCertEdit from './AuthCertEdit.vue';
|
||||
import { authCertApi } from '../api';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
@@ -35,6 +32,7 @@ import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
import { AuthMethodEnum } from '../enums';
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const state = reactive({
|
||||
query: {
|
||||
pageNum: 1,
|
||||
@@ -68,16 +66,12 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { query, total, authcerts, selectionData, editor } = toRefs(state);
|
||||
const { query, selectionData, editor } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
onMounted(() => {});
|
||||
|
||||
const search = async () => {
|
||||
let res = await authCertApi.list.request(state.query);
|
||||
state.authcerts = res.list;
|
||||
state.total = res.total;
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const editChange = () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-dialog
|
||||
@open="search()"
|
||||
:title="title"
|
||||
v-model="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
@@ -11,14 +12,13 @@
|
||||
>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="cronJobApi.execList"
|
||||
:lazy="true"
|
||||
:data-handler-fn="parseData"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="params"
|
||||
:data="state.data.list"
|
||||
:columns="columns"
|
||||
:total="state.data.total"
|
||||
v-model:page-size="params.pageSize"
|
||||
v-model:page-num="params.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #machineSelect>
|
||||
<el-select v-model="params.machineId" filterable placeholder="选择机器查询" style="width: 200px" clearable>
|
||||
@@ -35,7 +35,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { watch, ref, toRefs, reactive } from 'vue';
|
||||
import { watch, ref, toRefs, reactive, Ref } from 'vue';
|
||||
import { cronJobApi, machineApi } from '../api';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
@@ -68,6 +68,8 @@ const columns = ref([
|
||||
TableColumn.new('execTime', '执行时间').isTime().setMinWidth(150),
|
||||
]);
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
dialogVisible: false,
|
||||
tags: [] as any,
|
||||
@@ -108,17 +110,15 @@ watch(props, async (newValue: any) => {
|
||||
});
|
||||
|
||||
state.params.cronJobId = props.data?.id;
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
const res = await cronJobApi.execList.request(state.params);
|
||||
if (!res.list) {
|
||||
return;
|
||||
}
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const parseData = async (dataList: any) => {
|
||||
// 填充机器信息
|
||||
for (let x of res.list) {
|
||||
for (let x of dataList) {
|
||||
const machineId = x.machineId;
|
||||
let machine = machineMap.get(machineId);
|
||||
// 如果未找到,则可能被移除,则调接口查询机器信息
|
||||
@@ -139,8 +139,7 @@ const search = async () => {
|
||||
x.machineIp = machine?.ip;
|
||||
x.machineName = machine?.name;
|
||||
}
|
||||
|
||||
state.data = res;
|
||||
return dataList;
|
||||
};
|
||||
|
||||
const cancel = () => {
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="cronJobApi.list"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="params"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="state.selectionData"
|
||||
:data="data.list"
|
||||
:columns="columns"
|
||||
:total="data.total"
|
||||
v-model:page-size="params.pageSize"
|
||||
v-model:page-num="params.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="perms.saveCronJob" type="primary" icon="plus" @click="openFormDialog(false)" plain>添加 </el-button>
|
||||
@@ -38,7 +34,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, defineAsyncComponent, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { cronJobApi } from '../api';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
@@ -48,8 +44,6 @@ import { CronJobStatusEnum, CronJobSaveExecResTypeEnum } from '../enums';
|
||||
const CronJobEdit = defineAsyncComponent(() => import('./CronJobEdit.vue'));
|
||||
const CronJobExecList = defineAsyncComponent(() => import('./CronJobExecList.vue'));
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
|
||||
const perms = {
|
||||
saveCronJob: 'machine:cronjob:save',
|
||||
delCronJob: 'machine:cronjob:del',
|
||||
@@ -69,6 +63,8 @@ const columns = ref([
|
||||
TableColumn.new('action', '操作').isSlot().setMinWidth(180).fixedRight().alignCenter(),
|
||||
]);
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
params: {
|
||||
pageNum: 1,
|
||||
@@ -76,11 +72,6 @@ const state = reactive({
|
||||
ip: null,
|
||||
name: null,
|
||||
},
|
||||
// 列表数据
|
||||
data: {
|
||||
list: [],
|
||||
total: 10,
|
||||
},
|
||||
selectionData: [],
|
||||
execDialog: {
|
||||
visible: false,
|
||||
@@ -94,11 +85,9 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { selectionData, params, data, execDialog, cronJobEdit } = toRefs(state);
|
||||
const { selectionData, params, execDialog, cronJobEdit } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
search();
|
||||
});
|
||||
onMounted(async () => {});
|
||||
|
||||
const openFormDialog = async (data: any) => {
|
||||
let dialogTitle;
|
||||
@@ -143,13 +132,7 @@ const showExec = async (data: any) => {
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
const res = await cronJobApi.list.request(state.params);
|
||||
state.data = res;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -639,7 +639,7 @@ function uploadFolder(e: any) {
|
||||
|
||||
// 上传操作
|
||||
machineApi.uploadFile
|
||||
.request(form, {
|
||||
.xhrReq(form, {
|
||||
url: `${config.baseApiUrl}/machines/${props.machineId}/files/${props.fileId}/upload-folder?${joinClientParams()}`,
|
||||
headers: { 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryF1uyUD0tWdqmJqpl' },
|
||||
onUploadProgress: onUploadProgress,
|
||||
@@ -680,7 +680,7 @@ const uploadFile = (content: any) => {
|
||||
params.append('fileId', props.fileId as any);
|
||||
params.append('token', token);
|
||||
machineApi.uploadFile
|
||||
.request(params, {
|
||||
.xhrReq(params, {
|
||||
url: `${config.baseApiUrl}/machines/${props.machineId}/files/${props.fileId}/upload?${joinClientParams()}`,
|
||||
headers: { 'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryF1uyUD0tWdqmJqpl' },
|
||||
onUploadProgress: onUploadProgress,
|
||||
|
||||
@@ -110,6 +110,9 @@ const getFileType = (path: string) => {
|
||||
if (path.endsWith('xml') || path.endsWith('html')) {
|
||||
return 'html';
|
||||
}
|
||||
if (path.endsWith('py')) {
|
||||
return 'python';
|
||||
}
|
||||
return 'text';
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -43,9 +43,9 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="testConn" :loading="state.testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="testConn" :loading="testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -113,11 +113,13 @@ const state = reactive({
|
||||
sshTunnelMachineId: null as any,
|
||||
tagId: [],
|
||||
},
|
||||
btnLoading: false,
|
||||
testConnBtnLoading: false,
|
||||
submitForm: {},
|
||||
});
|
||||
|
||||
const { dialogVisible, tabActiveName, form, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, tabActiveName, form, submitForm } = toRefs(state);
|
||||
|
||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = mongoApi.testConn.useApi(submitForm);
|
||||
const { isFetching: saveBtnLoading, execute: saveMongoExec } = mongoApi.saveMongo.useApi(submitForm);
|
||||
|
||||
watch(props, async (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -142,38 +144,28 @@ const getReqForm = () => {
|
||||
|
||||
const testConn = async () => {
|
||||
mongoForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
state.testConnBtnLoading = true;
|
||||
try {
|
||||
await mongoApi.testConn.request(getReqForm());
|
||||
ElMessage.success('连接成功');
|
||||
} finally {
|
||||
state.testConnBtnLoading = false;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.submitForm = getReqForm();
|
||||
await testConnExec();
|
||||
ElMessage.success('连接成功');
|
||||
});
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
mongoForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
mongoApi.saveMongo.request(getReqForm()).then(() => {
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
|
||||
cancel();
|
||||
});
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
state.submitForm = getReqForm();
|
||||
await saveMongoExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="mongoApi.mongoList"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="list"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #tagPathSelect>
|
||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
||||
@@ -42,7 +38,7 @@
|
||||
<mongo-run-command v-model:visible="usersVisible" :id="state.dbOps.dbId" />
|
||||
|
||||
<mongo-edit
|
||||
@val-change="valChange"
|
||||
@val-change="search"
|
||||
:title="mongoEditDialog.title"
|
||||
v-model:visible="mongoEditDialog.visible"
|
||||
v-model:mongo="mongoEditDialog.data"
|
||||
@@ -52,7 +48,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { mongoApi } from './api';
|
||||
import { defineAsyncComponent, ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { defineAsyncComponent, ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import ResourceTag from '../component/ResourceTag.vue';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
@@ -65,8 +61,8 @@ const MongoEdit = defineAsyncComponent(() => import('./MongoEdit.vue'));
|
||||
const MongoDbs = defineAsyncComponent(() => import('./MongoDbs.vue'));
|
||||
const MongoRunCommand = defineAsyncComponent(() => import('./MongoRunCommand.vue'));
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
const route = useRoute();
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
||||
const columns = ref([
|
||||
@@ -84,8 +80,6 @@ const state = reactive({
|
||||
dbId: 0,
|
||||
db: '',
|
||||
},
|
||||
list: [],
|
||||
total: 0,
|
||||
selectionData: [],
|
||||
query: {
|
||||
pageNum: 1,
|
||||
@@ -101,10 +95,12 @@ const state = reactive({
|
||||
usersVisible: false,
|
||||
});
|
||||
|
||||
const { tags, list, total, selectionData, query, mongoEditDialog, dbsVisible, usersVisible } = toRefs(state);
|
||||
const { tags, selectionData, query, mongoEditDialog, dbsVisible, usersVisible } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
search();
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
});
|
||||
|
||||
const showDatabases = async (id: number) => {
|
||||
@@ -133,19 +129,7 @@ const deleteMongo = async () => {
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
|
||||
const res = await mongoApi.mongoList.request(state.query);
|
||||
state.list = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const getTags = async () => {
|
||||
@@ -162,10 +146,6 @@ const editMongo = async (data: any) => {
|
||||
}
|
||||
state.mongoEditDialog.visible = true;
|
||||
};
|
||||
|
||||
const valChange = () => {
|
||||
search();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
||||
@@ -84,9 +84,9 @@
|
||||
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="testConn" :loading="state.testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="testConn" :loading="testConnBtnLoading" type="success">测试连接</el-button>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -173,13 +173,15 @@ const state = reactive({
|
||||
remark: '',
|
||||
sshTunnelMachineId: -1,
|
||||
},
|
||||
submitForm: {} as any,
|
||||
dbList: [0],
|
||||
pwd: '',
|
||||
btnLoading: false,
|
||||
testConnBtnLoading: false,
|
||||
});
|
||||
|
||||
const { dialogVisible, tabActiveName, form, dbList, pwd, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, tabActiveName, form, submitForm, dbList, pwd } = toRefs(state);
|
||||
|
||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = redisApi.testConn.useApi(submitForm);
|
||||
const { isFetching: saveBtnLoading, execute: saveRedisExec } = redisApi.saveRedis.useApi(submitForm);
|
||||
|
||||
watch(props, async (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -226,38 +228,28 @@ const getReqForm = async () => {
|
||||
|
||||
const testConn = async () => {
|
||||
redisForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
state.testConnBtnLoading = true;
|
||||
try {
|
||||
await redisApi.testConn.request(await getReqForm());
|
||||
ElMessage.success('连接成功');
|
||||
} finally {
|
||||
state.testConnBtnLoading = false;
|
||||
}
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
|
||||
state.submitForm = await getReqForm();
|
||||
await testConnExec();
|
||||
ElMessage.success('连接成功');
|
||||
});
|
||||
};
|
||||
|
||||
const btnOk = async () => {
|
||||
redisForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
redisApi.saveRedis.request(await getReqForm()).then(() => {
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
|
||||
cancel();
|
||||
});
|
||||
} else {
|
||||
if (!valid) {
|
||||
ElMessage.error('请正确填写信息');
|
||||
return false;
|
||||
}
|
||||
state.submitForm = await getReqForm();
|
||||
await saveRedisExec();
|
||||
ElMessage.success('保存成功');
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="redisApi.redisList"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="redisTable"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #tagPathSelect>
|
||||
<el-select @focus="getTags" v-model="query.tagPath" placeholder="请选择标签" @clear="search" filterable clearable style="width: 200px">
|
||||
@@ -148,7 +144,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<redis-edit
|
||||
@val-change="valChange"
|
||||
@val-change="search"
|
||||
:tags="tags"
|
||||
:title="redisEditDialog.title"
|
||||
v-model:visible="redisEditDialog.visible"
|
||||
@@ -160,7 +156,7 @@
|
||||
<script lang="ts" setup>
|
||||
import Info from './Info.vue';
|
||||
import { redisApi } from './api';
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import RedisEdit from './RedisEdit.vue';
|
||||
import { dateFormat } from '@/common/utils/date';
|
||||
@@ -171,8 +167,8 @@ import { tagApi } from '../tag/api';
|
||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
const route = useRoute();
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const queryConfig = [TableQuery.slot('tagPath', '标签', 'tagPathSelect')];
|
||||
const columns = ref([
|
||||
@@ -186,8 +182,6 @@ const columns = ref([
|
||||
|
||||
const state = reactive({
|
||||
tags: [],
|
||||
redisTable: [],
|
||||
total: 0,
|
||||
selectionData: [],
|
||||
query: {
|
||||
tagPath: '',
|
||||
@@ -222,10 +216,12 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { tags, redisTable, total, selectionData, query, detailDialog, clusterInfoDialog, infoDialog, redisEditDialog } = toRefs(state);
|
||||
const { tags, selectionData, query, detailDialog, clusterInfoDialog, infoDialog, redisEditDialog } = toRefs(state);
|
||||
|
||||
onMounted(async () => {
|
||||
search();
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
});
|
||||
|
||||
const showDetail = (detail: any) => {
|
||||
@@ -267,20 +263,8 @@ const onShowClusterInfo = async (redis: any) => {
|
||||
state.clusterInfoDialog.visible = true;
|
||||
};
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
|
||||
if (route.query.tagPath) {
|
||||
state.query.tagPath = route.query.tagPath as string;
|
||||
}
|
||||
|
||||
const res = await redisApi.redisList.request(state.query);
|
||||
state.redisTable = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
const search = () => {
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const getTags = async () => {
|
||||
@@ -297,10 +281,6 @@ const editRedis = async (data: any) => {
|
||||
}
|
||||
state.redisEditDialog.visible = true;
|
||||
};
|
||||
|
||||
const valChange = () => {
|
||||
search();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="tagApi.getTeams"
|
||||
:query="state.queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="data"
|
||||
:columns="state.columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="'team:save'" type="primary" icon="plus" @click="showSaveTeamDialog(false)">添加</el-button>
|
||||
@@ -89,16 +86,14 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog width="50%" :title="showMemDialog.title" v-model="showMemDialog.visible">
|
||||
<el-dialog @open="setMemebers" width="50%" :title="showMemDialog.title" v-model="showMemDialog.visible">
|
||||
<page-table
|
||||
ref="showMemPageTableRef"
|
||||
:page-api="tagApi.getTeamMem"
|
||||
:lazy="true"
|
||||
:query="showMemDialog.queryConfig"
|
||||
v-model:query-form="showMemDialog.query"
|
||||
:data="showMemDialog.members.list"
|
||||
:columns="showMemDialog.columns"
|
||||
:total="showMemDialog.members.total"
|
||||
v-model:page-size="showMemDialog.query.pageSize"
|
||||
v-model:page-num="showMemDialog.query.pageNum"
|
||||
@pageChange="setMemebers()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="'team:member:save'" @click="showAddMemberDialog()" type="primary" icon="plus">添加</el-button>
|
||||
@@ -138,7 +133,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import { tagApi } from './api';
|
||||
import { accountApi } from '../../system/api';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
@@ -148,6 +143,9 @@ import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
|
||||
const teamForm: any = ref(null);
|
||||
const tagTreeRef: any = ref(null);
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const showMemPageTableRef: Ref<any> = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
currentEditPermissions: false,
|
||||
addTeamDialog: {
|
||||
@@ -168,8 +166,6 @@ const state = reactive({
|
||||
TableColumn.new('creator', '创建人'),
|
||||
TableColumn.new('action', '操作').isSlot().setMinWidth(120).fixedRight().alignCenter(),
|
||||
],
|
||||
total: 0,
|
||||
data: [],
|
||||
selectionData: [],
|
||||
showMemDialog: {
|
||||
queryConfig: [TableQuery.text('username', '用户名')],
|
||||
@@ -213,16 +209,12 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { query, addTeamDialog, total, data, selectionData, showMemDialog, showTagDialog } = toRefs(state);
|
||||
const { query, addTeamDialog, selectionData, showMemDialog, showTagDialog } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
onMounted(() => {});
|
||||
|
||||
const search = async () => {
|
||||
let res = await tagApi.getTeams.request(state.query);
|
||||
state.data = res.list;
|
||||
state.total = res.total;
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showSaveTeamDialog = (data: any) => {
|
||||
@@ -270,7 +262,6 @@ const deleteTeam = () => {
|
||||
const showMembers = async (team: any) => {
|
||||
state.showMemDialog.query.teamId = team.id;
|
||||
state.showMemDialog.visible = true;
|
||||
await setMemebers();
|
||||
state.showMemDialog.title = `[${team.name}] 成员信息`;
|
||||
};
|
||||
|
||||
@@ -293,9 +284,7 @@ const deleteMember = async (data: any) => {
|
||||
* 设置成员列表信息
|
||||
*/
|
||||
const setMemebers = async () => {
|
||||
const res = await tagApi.getTeamMem.request(state.showMemDialog.query);
|
||||
state.showMemDialog.members.list = res.list;
|
||||
state.showMemDialog.members.total = res.total;
|
||||
showMemPageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showAddMemberDialog = () => {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -84,10 +84,11 @@ const state = reactive({
|
||||
password: null,
|
||||
repassword: null,
|
||||
},
|
||||
btnLoading: false,
|
||||
});
|
||||
|
||||
const { dialogVisible, edit, form, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, edit, form } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveAccountExec } = accountApi.save.useApi(form);
|
||||
|
||||
watch(props, (newValue: any) => {
|
||||
if (newValue.account) {
|
||||
@@ -101,23 +102,18 @@ watch(props, (newValue: any) => {
|
||||
});
|
||||
|
||||
const btnOk = async () => {
|
||||
accountForm.value.validate((valid: boolean) => {
|
||||
if (valid) {
|
||||
accountApi.save.request(state.form).then(() => {
|
||||
ElMessage.success('操作成功');
|
||||
emit('val-change', state.form);
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
//重置表单域
|
||||
accountForm.value.resetFields();
|
||||
state.form = {} as any;
|
||||
});
|
||||
} else {
|
||||
accountForm.value.validate(async (valid: boolean) => {
|
||||
if (!valid) {
|
||||
ElMessage.error('表单填写有误');
|
||||
return false;
|
||||
}
|
||||
|
||||
await saveAccountExec();
|
||||
ElMessage.success('操作成功');
|
||||
emit('val-change', state.form);
|
||||
//重置表单域
|
||||
accountForm.value.resetFields();
|
||||
state.form = {} as any;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -2,16 +2,12 @@
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:page-api="accountApi.list"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="datas"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="perms.addAccount" type="primary" icon="plus" @click="editAccount(false)">添加</el-button>
|
||||
@@ -81,7 +77,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import RoleEdit from './RoleEdit.vue';
|
||||
import AccountEdit from './AccountEdit.vue';
|
||||
import { AccountStatusEnum, ResourceTypeEnum } from '../enums';
|
||||
@@ -92,8 +88,6 @@ import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
import { hasPerms } from '@/components/auth/auth';
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
|
||||
const perms = {
|
||||
addAccount: 'account:add',
|
||||
delAccount: 'account:del',
|
||||
@@ -118,6 +112,7 @@ const columns = ref([
|
||||
const actionBtns = hasPerms([perms.addAccount, perms.saveAccountRole, perms.changeAccountStatus]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(260).noShowOverflowTooltip().alignCenter();
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const state = reactive({
|
||||
/**
|
||||
* 选中的数据
|
||||
@@ -131,8 +126,6 @@ const state = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
},
|
||||
datas: [],
|
||||
total: 0,
|
||||
showRoleDialog: {
|
||||
title: '',
|
||||
visible: false,
|
||||
@@ -158,24 +151,16 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { selectionData, query, datas, total, showRoleDialog, showResourceDialog, roleDialog, accountDialog } = toRefs(state);
|
||||
const { selectionData, query, showRoleDialog, showResourceDialog, roleDialog, accountDialog } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
columns.value.push(actionColumn);
|
||||
}
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
let res: any = await accountApi.list.request(state.query);
|
||||
state.datas = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showResources = async (row: any) => {
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -76,10 +76,11 @@ const state = reactive({
|
||||
remark: '',
|
||||
permission: '',
|
||||
},
|
||||
btnLoading: false,
|
||||
});
|
||||
|
||||
const { dvisible, params, form, btnLoading } = toRefs(state);
|
||||
const { dvisible, params, form } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveConfigExec } = configApi.save.useApi(form);
|
||||
|
||||
watch(props, (newValue: any) => {
|
||||
state.dvisible = newValue.visible;
|
||||
@@ -134,13 +135,10 @@ const btnOk = async () => {
|
||||
} else {
|
||||
state.form.permission = 'all';
|
||||
}
|
||||
await configApi.save.request(state.form);
|
||||
|
||||
await saveConfigExec();
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<page-table
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="configs"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<page-table ref="pageTableRef" :page-api="configApi.list" v-model:selection-data="selectionData" :columns="columns">
|
||||
<template #queryRight>
|
||||
<el-button v-auth="perms.saveConfig" type="primary" icon="plus" @click="editConfig(false)">添加</el-button>
|
||||
</template>
|
||||
@@ -52,7 +43,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import ConfigEdit from './ConfigEdit.vue';
|
||||
import { configApi } from '../api';
|
||||
import { ElMessage } from 'element-plus';
|
||||
@@ -75,15 +66,15 @@ const columns = ref([
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().fixedRight().setMinWidth(130).noShowOverflowTooltip().alignCenter();
|
||||
const actionBtns = hasPerms([perms.saveConfig]);
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const paramsFormRef: any = ref(null);
|
||||
|
||||
const state = reactive({
|
||||
query: {
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
name: null,
|
||||
},
|
||||
total: 0,
|
||||
configs: [],
|
||||
selectionData: [],
|
||||
paramsDialog: {
|
||||
visible: false,
|
||||
@@ -98,19 +89,16 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { query, total, configs, selectionData, paramsDialog, configEdit } = toRefs(state);
|
||||
const { selectionData, paramsDialog, configEdit } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
columns.value.push(actionColumn);
|
||||
}
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
let res = await configApi.list.request(state.query);
|
||||
state.configs = res.list;
|
||||
state.total = res.total;
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const showSetConfigDialog = (row: any) => {
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -222,10 +222,12 @@ const state = reactive({
|
||||
link: '',
|
||||
},
|
||||
},
|
||||
btnLoading: false,
|
||||
submitForm: {},
|
||||
});
|
||||
|
||||
const { dialogVisible, form, btnLoading } = toRefs(state);
|
||||
const { dialogVisible, form, submitForm } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveResouceExec } = resourceApi.save.useApi(submitForm);
|
||||
|
||||
watch(props, (newValue: any) => {
|
||||
state.dialogVisible = newValue.visible;
|
||||
@@ -264,20 +266,15 @@ const btnOk = () => {
|
||||
} else {
|
||||
submitForm.meta = null as any;
|
||||
}
|
||||
menuForm.value.validate((valid: any) => {
|
||||
if (valid) {
|
||||
resourceApi.save.request(submitForm).then(() => {
|
||||
emit('val-change', submitForm);
|
||||
state.btnLoading = true;
|
||||
ElMessage.success('保存成功');
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
|
||||
cancel();
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
menuForm.value.validate(async (valid: any) => {
|
||||
if (valid) {
|
||||
state.submitForm = submitForm;
|
||||
await saveResouceExec();
|
||||
|
||||
emit('val-change', submitForm);
|
||||
ElMessage.success('保存成功');
|
||||
cancel();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -223,8 +223,7 @@ const deleteMenu = (data: any) => {
|
||||
.request({
|
||||
id: data.id,
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
.then(() => {
|
||||
ElMessage.success('删除成功!');
|
||||
search();
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<template #footer>
|
||||
<div class="dialog-footer">
|
||||
<el-button @click="cancel()">取 消</el-button>
|
||||
<el-button type="primary" :loading="btnLoading" @click="btnOk">确 定</el-button>
|
||||
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@@ -57,10 +57,11 @@ const state = reactive({
|
||||
status: 1,
|
||||
remark: '',
|
||||
},
|
||||
btnLoading: false,
|
||||
});
|
||||
|
||||
const { dvisible, form, btnLoading } = toRefs(state);
|
||||
const { dvisible, form } = toRefs(state);
|
||||
|
||||
const { isFetching: saveBtnLoading, execute: saveRoleExec } = roleApi.save.useApi(form);
|
||||
|
||||
watch(props, (newValue: any) => {
|
||||
state.dvisible = newValue.visible;
|
||||
@@ -81,13 +82,9 @@ const cancel = () => {
|
||||
const btnOk = async () => {
|
||||
roleForm.value.validate(async (valid: boolean) => {
|
||||
if (valid) {
|
||||
await roleApi.save.request(state.form);
|
||||
await saveRoleExec();
|
||||
emit('val-change', state.form);
|
||||
cancel();
|
||||
state.btnLoading = true;
|
||||
setTimeout(() => {
|
||||
state.btnLoading = false;
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<template>
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:query="queryConfig"
|
||||
v-model:query-form="query"
|
||||
:show-selection="true"
|
||||
v-model:selection-data="selectionData"
|
||||
:data="roles"
|
||||
:columns="columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
:page-api="roleApi.list"
|
||||
ref="pageTableRef"
|
||||
>
|
||||
<template #queryRight>
|
||||
<el-button v-auth="perms.addRole" type="primary" icon="plus" @click="editRole(false)">添加</el-button>
|
||||
@@ -40,7 +36,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { ref, toRefs, reactive, onMounted, Ref } from 'vue';
|
||||
import RoleEdit from './RoleEdit.vue';
|
||||
import ResourceEdit from './ResourceEdit.vue';
|
||||
import ShowResource from './ShowResource.vue';
|
||||
@@ -51,8 +47,6 @@ import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
import { hasPerms } from '@/components/auth/auth';
|
||||
import { RoleStatusEnum } from '../enums';
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
|
||||
const perms = {
|
||||
addRole: 'role:add',
|
||||
delRole: 'role:del',
|
||||
@@ -75,14 +69,13 @@ const columns = ref([
|
||||
const actionBtns = hasPerms([perms.updateRole, perms.saveRoleResource]);
|
||||
const actionColumn = TableColumn.new('action', '操作').isSlot().setMinWidth(260).fixedRight().alignCenter();
|
||||
|
||||
const pageTableRef: Ref<any> = ref(null);
|
||||
const state = reactive({
|
||||
query: {
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
name: null,
|
||||
},
|
||||
total: 0,
|
||||
roles: [],
|
||||
selectionData: [],
|
||||
resourceDialog: {
|
||||
visible: false,
|
||||
@@ -102,24 +95,16 @@ const state = reactive({
|
||||
},
|
||||
});
|
||||
|
||||
const { query, total, roles, selectionData, resourceDialog, roleEditDialog, showResourceDialog } = toRefs(state);
|
||||
const { query, selectionData, resourceDialog, roleEditDialog, showResourceDialog } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
if (Object.keys(actionBtns).length > 0) {
|
||||
columns.value.push(actionColumn);
|
||||
}
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
let res = await roleApi.list.request(state.query);
|
||||
state.roles = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
const search = () => {
|
||||
pageTableRef.value.search();
|
||||
};
|
||||
|
||||
const roleEditChange = () => {
|
||||
|
||||
@@ -1,16 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<page-table
|
||||
ref="pageTableRef"
|
||||
:query="state.queryConfig"
|
||||
v-model:query-form="query"
|
||||
:data="logs"
|
||||
:columns="state.columns"
|
||||
:total="total"
|
||||
v-model:page-size="query.pageSize"
|
||||
v-model:page-num="query.pageNum"
|
||||
@pageChange="search()"
|
||||
>
|
||||
<page-table :query="queryConfig" v-model:query-form="query" :columns="columns" :page-api="logApi.list">
|
||||
<template #selectAccount>
|
||||
<el-select
|
||||
style="width: 200px"
|
||||
@@ -29,13 +19,26 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, toRefs, reactive, onMounted } from 'vue';
|
||||
import { toRefs, reactive } from 'vue';
|
||||
import { logApi, accountApi } from '../api';
|
||||
import PageTable from '@/components/pagetable/PageTable.vue';
|
||||
import { TableColumn, TableQuery } from '@/components/pagetable';
|
||||
import { LogTypeEnum } from '../enums';
|
||||
|
||||
const pageTableRef: any = ref(null);
|
||||
const queryConfig = [
|
||||
TableQuery.slot('creatorId', '操作人', 'selectAccount'),
|
||||
TableQuery.select('type', '操作结果').setOptions(Object.values(LogTypeEnum)),
|
||||
TableQuery.text('description', '描述'),
|
||||
];
|
||||
|
||||
const columns = [
|
||||
TableColumn.new('creator', '操作人'),
|
||||
TableColumn.new('createTime', '操作时间').isTime(),
|
||||
TableColumn.new('type', '结果').typeTag(LogTypeEnum),
|
||||
TableColumn.new('description', '描述'),
|
||||
TableColumn.new('reqParam', '操作信息').canBeautify(),
|
||||
TableColumn.new('resp', '响应信息'),
|
||||
];
|
||||
|
||||
const state = reactive({
|
||||
query: {
|
||||
@@ -45,40 +48,10 @@ const state = reactive({
|
||||
pageNum: 1,
|
||||
pageSize: 0,
|
||||
},
|
||||
queryConfig: [
|
||||
TableQuery.slot('creatorId', '操作人', 'selectAccount'),
|
||||
TableQuery.select('type', '操作结果').setOptions(Object.values(LogTypeEnum)),
|
||||
TableQuery.text('description', '描述'),
|
||||
],
|
||||
columns: [
|
||||
TableColumn.new('creator', '操作人'),
|
||||
TableColumn.new('createTime', '操作时间').isTime(),
|
||||
TableColumn.new('type', '结果').typeTag(LogTypeEnum),
|
||||
TableColumn.new('description', '描述'),
|
||||
TableColumn.new('reqParam', '操作信息').canBeautify(),
|
||||
TableColumn.new('resp', '响应信息'),
|
||||
],
|
||||
total: 0,
|
||||
logs: [],
|
||||
accounts: [] as any,
|
||||
});
|
||||
|
||||
const { query, total, logs, accounts } = toRefs(state);
|
||||
|
||||
onMounted(() => {
|
||||
search();
|
||||
});
|
||||
|
||||
const search = async () => {
|
||||
try {
|
||||
pageTableRef.value.loading(true);
|
||||
let res = await logApi.list.request(state.query);
|
||||
state.logs = res.list;
|
||||
state.total = res.total;
|
||||
} finally {
|
||||
pageTableRef.value.loading(false);
|
||||
}
|
||||
};
|
||||
const { query, accounts } = toRefs(state);
|
||||
|
||||
const getAccount = (username: any) => {
|
||||
accountApi.list.request({ username }).then((res) => {
|
||||
|
||||
@@ -62,9 +62,11 @@ func (app *instanceAppImpl) Save(ctx context.Context, instanceEntity *entity.DbI
|
||||
instanceEntity.Network = instanceEntity.GetNetwork()
|
||||
|
||||
// 查找是否存在该库
|
||||
oldInstance := &entity.DbInstance{Host: instanceEntity.Host, Port: instanceEntity.Port, Username: instanceEntity.Username}
|
||||
if instanceEntity.SshTunnelMachineId > 0 {
|
||||
oldInstance.SshTunnelMachineId = instanceEntity.SshTunnelMachineId
|
||||
oldInstance := &entity.DbInstance{
|
||||
Host: instanceEntity.Host,
|
||||
Port: instanceEntity.Port,
|
||||
Username: instanceEntity.Username,
|
||||
SshTunnelMachineId: instanceEntity.SshTunnelMachineId,
|
||||
}
|
||||
|
||||
err := app.GetBy(oldInstance)
|
||||
|
||||
@@ -74,10 +74,13 @@ func (m *machineAppImpl) GetMachineList(condition *entity.MachineQuery, pagePara
|
||||
}
|
||||
|
||||
func (m *machineAppImpl) Save(ctx context.Context, me *entity.Machine, tagIds ...uint64) error {
|
||||
oldMachine := &entity.Machine{Ip: me.Ip, Port: me.Port, Username: me.Username}
|
||||
if me.SshTunnelMachineId > 0 {
|
||||
oldMachine.SshTunnelMachineId = me.SshTunnelMachineId
|
||||
oldMachine := &entity.Machine{
|
||||
Ip: me.Ip,
|
||||
Port: me.Port,
|
||||
Username: me.Username,
|
||||
SshTunnelMachineId: me.SshTunnelMachineId,
|
||||
}
|
||||
|
||||
err := m.GetBy(oldMachine)
|
||||
|
||||
me.PwdEncrypt()
|
||||
|
||||
@@ -70,9 +70,9 @@ func (r *redisAppImpl) TestConn(re *entity.Redis) error {
|
||||
|
||||
func (r *redisAppImpl) Save(ctx context.Context, re *entity.Redis, tagIds ...uint64) error {
|
||||
// 查找是否存在该库
|
||||
oldRedis := &entity.Redis{Host: re.Host}
|
||||
if re.SshTunnelMachineId > 0 {
|
||||
oldRedis.SshTunnelMachineId = re.SshTunnelMachineId
|
||||
oldRedis := &entity.Redis{
|
||||
Host: re.Host,
|
||||
SshTunnelMachineId: re.SshTunnelMachineId,
|
||||
}
|
||||
err := r.GetBy(oldRedis)
|
||||
|
||||
|
||||
@@ -160,37 +160,35 @@ func (p *tagTreeAppImpl) RelateResource(ctx context.Context, resourceCode string
|
||||
addTagIds, delTagIds, _ = collx.ArrayCompare[uint64](tagIds, oldTagIds, func(u1, u2 uint64) bool { return u1 == u2 })
|
||||
}
|
||||
|
||||
return p.Tx(ctx, func(ctx context.Context) error {
|
||||
if len(addTagIds) > 0 {
|
||||
addTagResource := make([]*entity.TagResource, 0)
|
||||
for _, tagId := range addTagIds {
|
||||
tag, err := p.GetById(new(entity.TagTree), tagId)
|
||||
if err != nil {
|
||||
return errorx.NewBiz("存在错误标签id")
|
||||
}
|
||||
addTagResource = append(addTagResource, &entity.TagResource{
|
||||
ResourceCode: resourceCode,
|
||||
ResourceType: resourceType,
|
||||
TagId: tagId,
|
||||
TagPath: tag.CodePath,
|
||||
})
|
||||
if len(addTagIds) > 0 {
|
||||
addTagResource := make([]*entity.TagResource, 0)
|
||||
for _, tagId := range addTagIds {
|
||||
tag, err := p.GetById(new(entity.TagTree), tagId)
|
||||
if err != nil {
|
||||
return errorx.NewBiz("存在错误标签id")
|
||||
}
|
||||
if err := p.tagResourceApp.BatchInsert(ctx, addTagResource); err != nil {
|
||||
addTagResource = append(addTagResource, &entity.TagResource{
|
||||
ResourceCode: resourceCode,
|
||||
ResourceType: resourceType,
|
||||
TagId: tagId,
|
||||
TagPath: tag.CodePath,
|
||||
})
|
||||
}
|
||||
if err := p.tagResourceApp.BatchInsert(ctx, addTagResource); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(delTagIds) > 0 {
|
||||
for _, tagId := range delTagIds {
|
||||
cond := &entity.TagResource{ResourceCode: resourceCode, ResourceType: resourceType, TagId: tagId}
|
||||
if err := p.tagResourceApp.DeleteByCond(ctx, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(delTagIds) > 0 {
|
||||
for _, tagId := range delTagIds {
|
||||
cond := &entity.TagResource{ResourceCode: resourceCode, ResourceType: resourceType, TagId: tagId}
|
||||
if err := p.tagResourceApp.DeleteByCond(ctx, cond); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *tagTreeAppImpl) ListTagPathByResource(resourceType int8, resourceCode string) []string {
|
||||
|
||||
Reference in New Issue
Block a user