✨ 双击终端会话 tab 复制.
This commit is contained in:
@@ -7,8 +7,11 @@
|
|||||||
🐞 修复 SFTP 加载失败后一直 loading
|
🐞 修复 SFTP 加载失败后一直 loading
|
||||||
🐞 修复 SSH 配置未启用还可以连接
|
🐞 修复 SSH 配置未启用还可以连接
|
||||||
🐞 修复 主机配置保存后无法修改状态
|
🐞 修复 主机配置保存后无法修改状态
|
||||||
|
🐞 修复 添加快捷命令时编辑器无代码提示
|
||||||
🔨 修改 菜单路由命名逻辑修改
|
🔨 修改 菜单路由命名逻辑修改
|
||||||
🔨 优化 前端组件命名规范化
|
🔨 优化 前端组件命名规范化
|
||||||
|
🌈 新增 双击终端会话 Tab 快速复制
|
||||||
|
🌈 新增 执行模板功能
|
||||||
|
|
||||||
[如何升级](/about/update.md?id=_v102)
|
[如何升级](/about/update.md?id=_v102)
|
||||||
|
|
||||||
|
|||||||
@@ -37,3 +37,38 @@
|
|||||||
> SFTP
|
> SFTP
|
||||||
|
|
||||||
* 预览: 默认只能预览 2MB 以内的普通文件, 这个大小可以在前端 env 文件中修改 `VITE_SFTP_PREVIEW_MB`
|
* 预览: 默认只能预览 2MB 以内的普通文件, 这个大小可以在前端 env 文件中修改 `VITE_SFTP_PREVIEW_MB`
|
||||||
|
|
||||||
|
> 终端面板
|
||||||
|
|
||||||
|
⭐ 双击终端标签可快速复制会话
|
||||||
|
|
||||||
|
### 执行模板
|
||||||
|
|
||||||
|
用来维护批量执行的命令模板, 支持动态参数, 使用 `@{{ xxx }}` 来替换命令参数。
|
||||||
|
|
||||||
|
* 新增: 新增执行模板
|
||||||
|
* 执行: 使用此命令模板批量执行主机命令
|
||||||
|
* 修改: 修改执行模板
|
||||||
|
* 删除: 删除执行模板
|
||||||
|
|
||||||
|
> 内置参数
|
||||||
|
|
||||||
|
| 参数 | 描述 |
|
||||||
|
|:----------------|:-------------------------|
|
||||||
|
| hostId | 执行主机id |
|
||||||
|
| hostName | 执行主机名称 |
|
||||||
|
| hostCode | 执行主机编码 |
|
||||||
|
| hostAddress | 执行主机地址 |
|
||||||
|
| userId | 执行用户id |
|
||||||
|
| username | 执行用户名 |
|
||||||
|
| execId | 执行记录id |
|
||||||
|
| execHostId | 执行主机记录id |
|
||||||
|
| uuid | 生成任务维度 uuid |
|
||||||
|
| uuidShort | 生成任务维度 uuid 无 '-' |
|
||||||
|
| hostUuid | 生成机器维度 uuid |
|
||||||
|
| hostUuidShort | 生成机器维度 uuid 无 '-' |
|
||||||
|
| timestampMillis | 时间戳毫秒 |
|
||||||
|
| timestamp | 时间戳 |
|
||||||
|
| date | 执行时间 yyyy-MM-dd |
|
||||||
|
| datetime | 执行时间 yyyy-MM-dd HH:mm:ss |
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
#end
|
#end
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -154,6 +155,7 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
|||||||
// 转换
|
// 转换
|
||||||
return list.stream()
|
return list.stream()
|
||||||
.map(${type}Convert.MAPPER::to)
|
.map(${type}Convert.MAPPER::to)
|
||||||
|
.sorted(Comparator.comparing(${type}VO::getId).reversed())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +278,8 @@ public class ${table.serviceImplName} implements ${table.serviceName} {
|
|||||||
#foreach($field in ${table.fields})
|
#foreach($field in ${table.fields})
|
||||||
.eq(${type}DO::get${field.capitalName}, searchValue)#if($foreach.hasNext).or()#end
|
.eq(${type}DO::get${field.capitalName}, searchValue)#if($foreach.hasNext).or()#end
|
||||||
#end
|
#end
|
||||||
);
|
)
|
||||||
|
.orderByDesc(${type}DO::getId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,8 +134,6 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['openAdd', 'openUpdate']);
|
const emits = defineEmits(['openAdd', 'openUpdate']);
|
||||||
|
|
||||||
const list = ref<${vue.featureEntity}QueryResponse[]>([]);
|
|
||||||
|
|
||||||
const cardColLayout = useColLayout();
|
const cardColLayout = useColLayout();
|
||||||
const pagination = usePagination();
|
const pagination = usePagination();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
@@ -143,6 +141,7 @@
|
|||||||
const { toOptions, getDictValue } = useDictStore();
|
const { toOptions, getDictValue } = useDictStore();
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
const list = ref<${vue.featureEntity}QueryResponse[]>([]);
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formModel = reactive<${vue.featureEntity}QueryRequest>({
|
const formModel = reactive<${vue.featureEntity}QueryRequest>({
|
||||||
searchValue: undefined,
|
searchValue: undefined,
|
||||||
|
|||||||
@@ -70,6 +70,8 @@
|
|||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
const emits = defineEmits(['added', 'updated']);
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
#if($dictMap.entrySet().size() > 0)
|
#if($dictMap.entrySet().size() > 0)
|
||||||
@@ -78,6 +80,8 @@
|
|||||||
|
|
||||||
const title = ref<string>();
|
const title = ref<string>();
|
||||||
const isAddHandle = ref<boolean>(true);
|
const isAddHandle = ref<boolean>(true);
|
||||||
|
const formRef = ref<any>();
|
||||||
|
const formModel = ref<${vue.featureEntity}UpdateRequest>({});
|
||||||
|
|
||||||
const defaultForm = (): ${vue.featureEntity}UpdateRequest => {
|
const defaultForm = (): ${vue.featureEntity}UpdateRequest => {
|
||||||
return {
|
return {
|
||||||
@@ -87,11 +91,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const formRef = ref<any>();
|
|
||||||
const formModel = ref<${vue.featureEntity}UpdateRequest>({});
|
|
||||||
|
|
||||||
const emits = defineEmits(['added', 'updated']);
|
|
||||||
|
|
||||||
// 打开新增
|
// 打开新增
|
||||||
const openAdd = () => {
|
const openAdd = () => {
|
||||||
title.value = '添加${table.comment}';
|
title.value = '添加${table.comment}';
|
||||||
|
|||||||
@@ -74,6 +74,8 @@
|
|||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
const emits = defineEmits(['added', 'updated']);
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
#if($dictMap.entrySet().size() > 0)
|
#if($dictMap.entrySet().size() > 0)
|
||||||
@@ -82,6 +84,8 @@
|
|||||||
|
|
||||||
const title = ref<string>();
|
const title = ref<string>();
|
||||||
const isAddHandle = ref<boolean>(true);
|
const isAddHandle = ref<boolean>(true);
|
||||||
|
const formRef = ref<any>();
|
||||||
|
const formModel = ref<${vue.featureEntity}UpdateRequest>({});
|
||||||
|
|
||||||
const defaultForm = (): ${vue.featureEntity}UpdateRequest => {
|
const defaultForm = (): ${vue.featureEntity}UpdateRequest => {
|
||||||
return {
|
return {
|
||||||
@@ -91,11 +95,6 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const formRef = ref<any>();
|
|
||||||
const formModel = ref<${vue.featureEntity}UpdateRequest>({});
|
|
||||||
|
|
||||||
const emits = defineEmits(['added', 'updated']);
|
|
||||||
|
|
||||||
// 打开新增
|
// 打开新增
|
||||||
const openAdd = () => {
|
const openAdd = () => {
|
||||||
title.value = '添加${table.comment}';
|
title.value = '添加${table.comment}';
|
||||||
|
|||||||
@@ -157,11 +157,6 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['openAdd', 'openUpdate']);
|
const emits = defineEmits(['openAdd', 'openUpdate']);
|
||||||
|
|
||||||
#if($vue.enableRowSelection)
|
|
||||||
const selectedKeys = ref<number[]>([]);
|
|
||||||
#end
|
|
||||||
const tableRenderData = ref<${vue.featureEntity}QueryResponse[]>([]);
|
|
||||||
|
|
||||||
const pagination = usePagination();
|
const pagination = usePagination();
|
||||||
#if($vue.enableRowSelection)
|
#if($vue.enableRowSelection)
|
||||||
const rowSelection = useRowSelection();
|
const rowSelection = useRowSelection();
|
||||||
@@ -171,6 +166,10 @@
|
|||||||
const { toOptions, getDictValue } = useDictStore();
|
const { toOptions, getDictValue } = useDictStore();
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
#if($vue.enableRowSelection)
|
||||||
|
const selectedKeys = ref<number[]>([]);
|
||||||
|
#end
|
||||||
|
const tableRenderData = ref<${vue.featureEntity}QueryResponse[]>([]);
|
||||||
const formModel = reactive<${vue.featureEntity}QueryRequest>({
|
const formModel = reactive<${vue.featureEntity}QueryRequest>({
|
||||||
#foreach($field in ${table.fields})
|
#foreach($field in ${table.fields})
|
||||||
${field.propertyName}: undefined,
|
${field.propertyName}: undefined,
|
||||||
|
|||||||
@@ -62,6 +62,13 @@
|
|||||||
#else
|
#else
|
||||||
import ${vue.featureEntity}FormModal from './components/${vue.feature}-form-modal.vue';
|
import ${vue.featureEntity}FormModal from './components/${vue.feature}-form-modal.vue';
|
||||||
#end
|
#end
|
||||||
|
#if($vue.enableCardView)
|
||||||
|
|
||||||
|
const appStore = useAppStore();
|
||||||
|
|
||||||
|
// FIXME 这里需要修改一下字段名称 并且在 appStore 定义该字段
|
||||||
|
const renderTable = computed(() => appStore.${vue.featureEntityFirstLower}View === 'table');
|
||||||
|
#end
|
||||||
|
|
||||||
const render = ref(false);
|
const render = ref(false);
|
||||||
const table = ref();
|
const table = ref();
|
||||||
@@ -73,12 +80,6 @@
|
|||||||
#else
|
#else
|
||||||
const modal = ref();
|
const modal = ref();
|
||||||
#end
|
#end
|
||||||
#if($vue.enableCardView)
|
|
||||||
const appStore = useAppStore();
|
|
||||||
|
|
||||||
// FIXME 这里需要修改一下字段名称 并且在 appStore 定义该字段
|
|
||||||
const renderTable = computed(() => appStore.${vue.featureEntityFirstLower}View === 'table');
|
|
||||||
#end
|
|
||||||
|
|
||||||
// 添加回调
|
// 添加回调
|
||||||
const modalAddCallback = () => {
|
const modalAddCallback = () => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -99,6 +100,7 @@ public class ExecTemplateServiceImpl implements ExecTemplateService {
|
|||||||
// 转换
|
// 转换
|
||||||
return list.stream()
|
return list.stream()
|
||||||
.map(ExecTemplateConvert.MAPPER::to)
|
.map(ExecTemplateConvert.MAPPER::to)
|
||||||
|
.sorted(Comparator.comparing(ExecTemplateVO::getId).reversed())
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +155,8 @@ public class ExecTemplateServiceImpl implements ExecTemplateService {
|
|||||||
return execTemplateDAO.wrapper()
|
return execTemplateDAO.wrapper()
|
||||||
.eq(ExecTemplateDO::getId, request.getId())
|
.eq(ExecTemplateDO::getId, request.getId())
|
||||||
.like(ExecTemplateDO::getName, request.getName())
|
.like(ExecTemplateDO::getName, request.getName())
|
||||||
.like(ExecTemplateDO::getCommand, request.getCommand());
|
.like(ExecTemplateDO::getCommand, request.getCommand())
|
||||||
|
.orderByDesc(ExecTemplateDO::getId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,39 +9,51 @@ export interface TemplateParam {
|
|||||||
export const builtinsParams: Array<TemplateParam> = [
|
export const builtinsParams: Array<TemplateParam> = [
|
||||||
{
|
{
|
||||||
name: 'hostId',
|
name: 'hostId',
|
||||||
desc: '主机id'
|
desc: '执行主机id'
|
||||||
}, {
|
}, {
|
||||||
name: 'hostName',
|
name: 'hostName',
|
||||||
desc: '主机名称'
|
desc: '执行主机名称'
|
||||||
}, {
|
}, {
|
||||||
name: 'hostCode',
|
name: 'hostCode',
|
||||||
desc: '主机编码'
|
desc: '执行主机编码'
|
||||||
|
}, {
|
||||||
|
name: 'hostAddress',
|
||||||
|
desc: '执行主机地址'
|
||||||
}, {
|
}, {
|
||||||
name: 'userId',
|
name: 'userId',
|
||||||
desc: '执行用户id'
|
desc: '执行用户id'
|
||||||
}, {
|
}, {
|
||||||
name: 'username',
|
name: 'username',
|
||||||
desc: '执行用户名称'
|
desc: '执行用户名'
|
||||||
}, {
|
}, {
|
||||||
name: 'execId',
|
name: 'execId',
|
||||||
desc: '执行id'
|
desc: '执行记录id'
|
||||||
|
}, {
|
||||||
|
name: 'execHostId',
|
||||||
|
desc: '执行主机记录id'
|
||||||
}, {
|
}, {
|
||||||
name: 'uuid',
|
name: 'uuid',
|
||||||
desc: 'uuid'
|
desc: '生成任务维度 uuid'
|
||||||
}, {
|
}, {
|
||||||
name: 'uuidShort',
|
name: 'uuidShort',
|
||||||
desc: 'uuid 无 \'-\''
|
desc: '生成任务维度 uuid 无 \'-\''
|
||||||
}, {
|
}, {
|
||||||
name: 'timeMillis',
|
name: 'hostUuid',
|
||||||
|
desc: '生成机器维度 uuid'
|
||||||
|
}, {
|
||||||
|
name: 'hostUuidShort',
|
||||||
|
desc: '生成机器维度 uuid 无 \'-\''
|
||||||
|
}, {
|
||||||
|
name: 'timestampMillis',
|
||||||
desc: '时间戳毫秒'
|
desc: '时间戳毫秒'
|
||||||
}, {
|
}, {
|
||||||
name: 'timestamp',
|
name: 'timestamp',
|
||||||
desc: '时间戳'
|
desc: '时间戳'
|
||||||
}, {
|
}, {
|
||||||
name: 'date',
|
name: 'date',
|
||||||
desc: '时间 yyyy-MM-dd'
|
desc: '执行时间 yyyy-MM-dd'
|
||||||
}, {
|
}, {
|
||||||
name: 'datetime',
|
name: 'datetime',
|
||||||
desc: '时间 yyyy-MM-dd HH:mm:ss'
|
desc: '执行时间 yyyy-MM-dd HH:mm:ss'
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -21,8 +21,9 @@
|
|||||||
:key="tab.key">
|
:key="tab.key">
|
||||||
<!-- 标题 -->
|
<!-- 标题 -->
|
||||||
<template #title>
|
<template #title>
|
||||||
<span class="tab-title-wrapper"
|
<span class="tab-title-wrapper usn"
|
||||||
:style="{ 'border-bottom': `2px ${tab.color || 'transparent'} solid` }">
|
:style="{ 'border-bottom': `2px ${tab.color || 'transparent'} solid` }"
|
||||||
|
@dblclick="copySession(tab, index)">
|
||||||
<span class="tab-title-icon">
|
<span class="tab-title-icon">
|
||||||
<component :is="tab.icon" />
|
<component :is="tab.icon" />
|
||||||
</span>
|
</span>
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['close', 'openNewConnect']);
|
const emits = defineEmits(['close', 'openNewConnect']);
|
||||||
|
|
||||||
const { sessionManager } = useTerminalStore();
|
const { sessionManager, copySession } = useTerminalStore();
|
||||||
|
|
||||||
// 监听 tab 切换
|
// 监听 tab 切换
|
||||||
watch(() => props.panel.active, (active, before) => {
|
watch(() => props.panel.active, (active, before) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user