refactor: 标签资源重构

This commit is contained in:
meilin.huang
2024-04-06 18:19:17 +08:00
parent 582d879a77
commit 408bac09a1
52 changed files with 476 additions and 347 deletions

View File

@@ -22,6 +22,8 @@ export class EnumValue {
*/
tag: EnumValueTag;
extra: any;
constructor(value: any, label: string) {
this.value = value;
this.label = label;
@@ -53,6 +55,11 @@ export class EnumValue {
return this;
}
setExtra(extra: any): EnumValue {
this.extra = extra;
return this;
}
public static of(value: any, label: string): EnumValue {
return new EnumValue(value, label);
}
@@ -60,11 +67,12 @@ export class EnumValue {
/**
* 根据枚举值获取指定枚举值对象
*
* @param enumValues 所有枚举值
* @param enums 枚举对象
* @param value 需要匹配的枚举值
* @returns 枚举值对象
*/
static getEnumByValue(enumValues: EnumValue[], value: any): EnumValue | null {
static getEnumByValue(enums: any, value: any): EnumValue | null {
const enumValues = Object.values(enums) as any;
for (let enumValue of enumValues) {
if (enumValue.value == value) {
return enumValue;

View File

@@ -2,8 +2,9 @@ import EnumValue from './Enum';
// 标签关联的资源类型
export const TagResourceTypeEnum = {
Machine: EnumValue.of(1, '机器'),
Db: EnumValue.of(2, '数据库'),
Redis: EnumValue.of(3, 'redis'),
Mongo: EnumValue.of(4, 'mongo'),
Tag: EnumValue.of(-1, '标签').setExtra({ icon: 'CollectionTag' }),
Machine: EnumValue.of(1, '机器').setExtra({ icon: 'Monitor' }),
Db: EnumValue.of(2, '数据库').setExtra({ icon: 'Coin' }),
Redis: EnumValue.of(3, 'redis').setExtra({ icon: 'iconfont icon-redis' }),
Mongo: EnumValue.of(4, 'mongo').setExtra({ icon: 'iconfont icon-mongo' }),
};

View File

@@ -2,3 +2,8 @@ export const AccountUsernamePattern = {
pattern: /^[a-zA-Z0-9_]{5,20}$/g,
message: '只允许输入5-20位大小写字母、数字、下划线',
};
export const ResourceCodePattern = {
pattern: /^[a-zA-Z0-9_]{1,32}$/g,
message: '只允许输入1-32位大小写字母、数字、下划线',
};

View File

@@ -40,7 +40,7 @@ onMounted(() => {
});
const convert = (value: any) => {
const enumValue = EnumValue.getEnumByValue(Object.values(props.enums as any) as any, value) as any;
const enumValue = EnumValue.getEnumByValue(props.enums, value) as any;
if (!enumValue) {
state.enumLabel = '-';
state.type = 'danger';

View File

@@ -58,7 +58,7 @@ onMounted(async () => {
state.selectTags = props.selectTags;
}
state.tags = await tagApi.getTagTrees.request(null);
state.tags = await tagApi.getTagTrees.request({ type: -1 });
});
const changeTag = () => {

View File

@@ -47,6 +47,14 @@
</el-select>
</el-form-item>
<el-form-item prop="code" label="编号" required>
<el-input
:disabled="form.id"
v-model.trim="form.code"
placeholder="请输入机器编号 (数字字母下划线), 不可修改"
auto-complete="off"
></el-input>
</el-form-item>
<el-form-item prop="name" label="别名" required>
<el-input v-model.trim="form.name" placeholder="请输入数据库别名" auto-complete="off"></el-input>
</el-form-item>
@@ -96,6 +104,7 @@ import TagTreeSelect from '../component/TagTreeSelect.vue';
import type { CheckboxValueType } from 'element-plus';
import ProcdefSelectFormItem from '@/views/flow/components/ProcdefSelectFormItem.vue';
import { DbType } from '@/views/ops/db/dialect';
import { ResourceCodePattern } from '@/common/pattern';
const props = defineProps({
visible: {
@@ -128,7 +137,18 @@ const rules = {
trigger: ['change', 'blur'],
},
],
code: [
{
required: true,
message: '请输入编码',
trigger: ['change', 'blur'],
},
{
pattern: ResourceCodePattern.pattern,
message: ResourceCodePattern.message,
trigger: ['blur'],
},
],
name: [
{
required: true,

View File

@@ -239,10 +239,15 @@ const perms = {
restoreDb: 'db:restore',
};
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Db.value), SearchItem.slot('instanceId', '实例', 'instanceSelect')];
const searchItems = [
getTagPathSearchItem(TagResourceTypeEnum.Db.value),
SearchItem.slot('instanceId', '实例', 'instanceSelect'),
SearchItem.input('code', '编号'),
];
const columns = ref([
TableColumn.new('tags[0].tagPath', '关联标签').isSlot('tagPath').setAddWidth(20),
TableColumn.new('code', '编号'),
TableColumn.new('name', '名称'),
TableColumn.new('type', '类型').isSlot().setAddWidth(-15).alignCenter(),
TableColumn.new('instanceName', '实例名'),

View File

@@ -1,6 +1,10 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :close-on-click-modal="false" :destroy-on-close="true" :before-close="cancel" width="650px">
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false">
<template #header>
<DrawerHeader :header="title" :back="cancel" />
</template>
<el-form :model="form" ref="machineForm" :rules="rules" label-width="auto">
<el-tabs v-model="tabActiveName">
<el-tab-pane label="基础信息" name="basic">
@@ -18,19 +22,25 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item prop="protocol" label="机器类型" required>
<el-radio-group v-model="form.protocol" @change="handleChangeProtocol">
<el-radio :value="1">SSH</el-radio>
<el-radio :value="2">RDP</el-radio>
<!-- <el-radio :value="3">VNC</el-radio> -->
</el-radio-group>
<el-form-item prop="code" label="编号" required>
<el-input
:disabled="form.id"
v-model.trim="form.code"
placeholder="请输入机器编号 (数字字母下划线), 不可修改"
auto-complete="off"
></el-input>
</el-form-item>
<el-form-item prop="name" label="名称" required>
<el-input v-model.trim="form.name" placeholder="请输入机器别名" auto-complete="off"></el-input>
</el-form-item>
<el-form-item prop="ip" label="ip" req uired>
<el-form-item prop="protocol" label="协议" required>
<el-radio-group v-model="form.protocol" @change="handleChangeProtocol">
<el-radio v-for="item in MachineProtocolEnum" :key="item.value" :label="item.label" :value="item.value"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item prop="ip" label="ip" required>
<el-col :span="18">
<el-input :disabled="form.id" v-model.trim="form.ip" placeholder="主机ip" auto-complete="off"> </el-input>
<el-input v-model.trim="form.ip" placeholder="主机ip" auto-complete="off"> </el-input>
</el-col>
<el-col style="text-align: center" :span="1">:</el-col>
<el-col :span="5">
@@ -81,7 +91,7 @@
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
</div>
</template>
</el-dialog>
</el-drawer>
</div>
</template>
@@ -92,6 +102,9 @@ import { ElMessage } from 'element-plus';
import TagTreeSelect from '../component/TagTreeSelect.vue';
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
import AuthCertSelect from './authcert/AuthCertSelect.vue';
import { MachineProtocolEnum } from './enums';
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
import { ResourceCodePattern } from '@/common/pattern';
const props = defineProps({
visible: {
@@ -116,6 +129,18 @@ const rules = {
trigger: ['change'],
},
],
code: [
{
required: true,
message: '请输入编码',
trigger: ['change', 'blur'],
},
{
pattern: ResourceCodePattern.pattern,
message: ResourceCodePattern.message,
trigger: ['blur'],
},
],
name: [
{
required: true,
@@ -134,7 +159,7 @@ const rules = {
{
required: true,
message: '请输入主机ip和端口',
trigger: ['change', 'blur'],
trigger: ['blur'],
},
],
authCertId: [
@@ -263,11 +288,11 @@ const getReqForm = () => {
};
const handleChangeProtocol = (val: any) => {
if (val == 1) {
if (val == MachineProtocolEnum.Ssh.value) {
state.form.port = 22;
} else if (val == 2) {
} else if (val == MachineProtocolEnum.Rdp.value) {
state.form.port = 3389;
} else if (val == 3) {
} else {
state.form.port = 5901;
}
};

View File

@@ -251,10 +251,16 @@ const perms = {
terminal: 'machine:terminal',
};
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Machine.value), SearchItem.input('ip', 'IP'), SearchItem.input('name', '名称')];
const searchItems = [
getTagPathSearchItem(TagResourceTypeEnum.Machine.value),
SearchItem.input('code', '编号'),
SearchItem.input('ip', 'IP'),
SearchItem.input('name', '名称'),
];
const columns = [
TableColumn.new('tags[0].tagPath', '关联标签').isSlot('tagPath').setAddWidth(20),
TableColumn.new('code', '编号'),
TableColumn.new('name', '名称'),
TableColumn.new('ipPort', 'ip:port').isSlot().setAddWidth(50),
TableColumn.new('stat', '运行状态').isSlot().setAddWidth(55),

View File

@@ -1,5 +1,10 @@
import { EnumValue } from '@/common/Enum';
export const MachineProtocolEnum = {
Ssh: EnumValue.of(1, 'SSH'),
Rdp: EnumValue.of(2, 'RDP'),
};
// 脚本执行结果类型
export const ScriptResultEnum = {
Result: EnumValue.of(1, '有结果'),

View File

@@ -17,7 +17,14 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item prop="code" label="编号" required>
<el-input
:disabled="form.id"
v-model.trim="form.code"
placeholder="请输入机器编号 (数字字母下划线), 不可修改"
auto-complete="off"
></el-input>
</el-form-item>
<el-form-item prop="name" label="名称" required>
<el-input v-model.trim="form.name" placeholder="请输入名称" auto-complete="off"></el-input>
</el-form-item>
@@ -57,6 +64,7 @@ import { mongoApi } from './api';
import { ElMessage } from 'element-plus';
import TagTreeSelect from '../component/TagTreeSelect.vue';
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
import { ResourceCodePattern } from '@/common/pattern';
const props = defineProps({
visible: {
@@ -81,6 +89,18 @@ const rules = {
trigger: ['change', 'blur'],
},
],
code: [
{
required: true,
message: '请输入编码',
trigger: ['change', 'blur'],
},
{
pattern: ResourceCodePattern.pattern,
message: ResourceCodePattern.message,
trigger: ['blur'],
},
],
name: [
{
required: true,

View File

@@ -52,6 +52,7 @@ import { TableColumn } from '@/components/pagetable';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import { useRoute } from 'vue-router';
import { getTagPathSearchItem } from '../component/tag';
import { SearchItem } from '@/components/SearchForm';
const MongoEdit = defineAsyncComponent(() => import('./MongoEdit.vue'));
const MongoDbs = defineAsyncComponent(() => import('./MongoDbs.vue'));
@@ -67,10 +68,11 @@ const props = defineProps({
const route = useRoute();
const pageTableRef: Ref<any> = ref(null);
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Mongo.value)];
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Mongo.value), SearchItem.input('code', '编号')];
const columns = [
TableColumn.new('tags[0].tagPath', '关联标签').isSlot('tagPath').setAddWidth(20),
TableColumn.new('code', '编号'),
TableColumn.new('name', '名称'),
TableColumn.new('uri', '连接uri'),
TableColumn.new('createTime', '创建时间').isTime(),

View File

@@ -1,6 +1,10 @@
<template>
<div>
<el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" :destroy-on-close="true" width="38%">
<el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false">
<template #header>
<DrawerHeader :header="title" :back="cancel" />
</template>
<el-form :model="form" ref="redisForm" :rules="rules" label-width="auto">
<el-tabs v-model="tabActiveName">
<el-tab-pane label="基础信息" name="basic">
@@ -17,6 +21,14 @@
style="width: 100%"
/>
</el-form-item>
<el-form-item prop="code" label="编号" required>
<el-input
:disabled="form.id"
v-model.trim="form.code"
placeholder="请输入机器编号 (数字字母下划线), 不可修改"
auto-complete="off"
></el-input>
</el-form-item>
<el-form-item prop="name" label="名称" required>
<el-input v-model.trim="form.name" placeholder="请输入redis名称" auto-complete="off"></el-input>
</el-form-item>
@@ -90,7 +102,7 @@
<el-button type="primary" :loading="saveBtnLoading" @click="btnOk">确 定</el-button>
</div>
</template>
</el-dialog>
</el-drawer>
</div>
</template>
@@ -102,6 +114,8 @@ import { RsaEncrypt } from '@/common/rsa';
import TagTreeSelect from '../component/TagTreeSelect.vue';
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
import ProcdefSelectFormItem from '@/views/flow/components/ProcdefSelectFormItem.vue';
import { ResourceCodePattern } from '@/common/pattern';
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
const props = defineProps({
visible: {
@@ -125,6 +139,18 @@ const rules = {
trigger: ['blur', 'change'],
},
],
code: [
{
required: true,
message: '请输入编码',
trigger: ['change', 'blur'],
},
{
pattern: ResourceCodePattern.pattern,
message: ResourceCodePattern.message,
trigger: ['blur'],
},
],
name: [
{
required: true,

View File

@@ -161,6 +161,7 @@ import { TableColumn } from '@/components/pagetable';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import { useRoute } from 'vue-router';
import { getTagPathSearchItem } from '../component/tag';
import { SearchItem } from '@/components/SearchForm';
const props = defineProps({
lazy: {
@@ -172,10 +173,11 @@ const props = defineProps({
const route = useRoute();
const pageTableRef: Ref<any> = ref(null);
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Redis.value)];
const searchItems = [getTagPathSearchItem(TagResourceTypeEnum.Redis.value), SearchItem.input('code', '编号')];
const columns = ref([
TableColumn.new('tags[0].tagPath', '关联标签').isSlot('tagPath').setAddWidth(20),
TableColumn.new('code', '编号'),
TableColumn.new('name', '名称'),
TableColumn.new('host', 'host:port'),
TableColumn.new('mode', 'mode'),

View File

@@ -43,7 +43,9 @@
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px">
<SvgIcon :name="EnumValue.getEnumByValue(TagResourceTypeEnum, data.type)?.extra.icon" />
<span class="ml5">
{{ data.code }}
<span style="color: #3c8dbc"></span>
{{ data.name }}
@@ -61,6 +63,10 @@
<el-tabs @tab-change="tabChange" v-model="state.activeTabName" v-if="currentTag">
<el-tab-pane label="标签详情" :name="TagDetail">
<el-descriptions :column="2" border>
<el-descriptions-item label="类型">
<EnumTag :enums="TagResourceTypeEnum" :value="currentTag.type" />
</el-descriptions-item>
<el-descriptions-item label="code">{{ currentTag.code }}</el-descriptions-item>
<el-descriptions-item label="code路径">{{ currentTag.codePath }}</el-descriptions-item>
<el-descriptions-item label="名称">{{ currentTag.name }}</el-descriptions-item>
@@ -73,19 +79,19 @@
</el-descriptions>
</el-tab-pane>
<el-tab-pane :label="`机器 (${resourceCount.machine})`" :name="MachineTag">
<el-tab-pane v-if="currentTag.type == TagResourceTypeEnum.Tag.value" :label="`机器 (${resourceCount.machine})`" :name="MachineTag">
<MachineList lazy ref="machineListRef" />
</el-tab-pane>
<el-tab-pane :label="`数据库 (${resourceCount.db})`" :name="DbTag">
<el-tab-pane v-if="currentTag.type == TagResourceTypeEnum.Tag.value" :label="`数据库 (${resourceCount.db})`" :name="DbTag">
<DbList lazy ref="dbListRef" />
</el-tab-pane>
<el-tab-pane :label="`Redis (${resourceCount.redis})`" :name="RedisTag">
<el-tab-pane v-if="currentTag.type == TagResourceTypeEnum.Tag.value" :label="`Redis (${resourceCount.redis})`" :name="RedisTag">
<RedisList lazy ref="redisListRef" />
</el-tab-pane>
<el-tab-pane :label="`Mongo (${resourceCount.mongo})`" :name="MongoTag">
<el-tab-pane v-if="currentTag.type == TagResourceTypeEnum.Tag.value" :label="`Mongo (${resourceCount.mongo})`" :name="MongoTag">
<MongoList lazy ref="mongoListRef" />
</el-tab-pane>
</el-tabs>
@@ -129,6 +135,9 @@ import MachineList from '../machine/MachineList.vue';
import RedisList from '../redis/RedisList.vue';
import MongoList from '../mongo/MongoList.vue';
import DbList from '../db/DbList.vue';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import EnumTag from '@/components/enumtag/EnumTag.vue';
import EnumValue from '@/common/Enum';
interface Tree {
id: number;
@@ -155,6 +164,10 @@ const MongoTag = 'mongoTag';
const contextmenuAdd = new ContextmenuItem('addTag', '添加子标签')
.withIcon('circle-plus')
.withPermission('tag:save')
.withHideFunc((data: any) => {
// 非标签类型不可添加子标签
return data.type != -1;
})
.withOnClick((data: any) => showSaveTagDialog(data));
const contextmenuEdit = new ContextmenuItem('edit', '编辑')
@@ -167,7 +180,7 @@ const contextmenuDel = new ContextmenuItem('delete', '删除')
.withPermission('tag:del')
.withHideFunc((data: any) => {
// 存在子标签,则不允许删除
return data.children;
return data.children || data.type != -1;
})
.withOnClick((data: any) => deleteTag(data));

View File

@@ -66,7 +66,9 @@
>
<template #default="{ data }">
<span class="custom-tree-node">
<span style="font-size: 13px">
<SvgIcon :name="EnumValue.getEnumByValue(TagResourceTypeEnum, data.type)?.extra.icon" />
<span class="font13 ml5">
{{ data.code }}
<span style="color: #3c8dbc"></span>
{{ data.name }}
@@ -128,6 +130,8 @@ import PageTable from '@/components/pagetable/PageTable.vue';
import { TableColumn } from '@/components/pagetable';
import { SearchItem } from '@/components/SearchForm';
import AccountSelectFormItem from '@/views/system/account/components/AccountSelectFormItem.vue';
import { TagResourceTypeEnum } from '@/common/commonEnum';
import EnumValue from '@/common/Enum';
const teamForm: any = ref(null);
const tagTreeRef: any = ref(null);

View File

@@ -7,7 +7,6 @@ export const tagApi = {
delTagTree: Api.newDelete('/tag-trees/{id}'),
getResourceTagPaths: Api.newGet('/tag-trees/resources/{resourceType}/tag-paths'),
getTagResources: Api.newGet('/tag-trees/resources'),
countTagResource: Api.newGet('/tag-trees/resources/count'),
getTeams: Api.newGet('/teams'),

View File

@@ -9,11 +9,6 @@ server:
enable: false
key-file: ./default.key
cert-file: ./default.pem
machine:
# 如果需要添加rdp服务器需要安装guacd服务docker跑一个就行 docker run --name guacd -d -p 4822:4822 guacamole/guacd
# 如果连接频繁中断重启一下guacd
guacd-host: 127.0.0.1
guacd-port: 4822
jwt:
# jwt key不设置默认使用随机字符串
key:

View File

@@ -31,7 +31,7 @@ require (
github.com/sijms/go-ora/v2 v2.8.10
github.com/stretchr/testify v1.8.4
go.mongodb.org/mongo-driver v1.14.0 // mongo
golang.org/x/crypto v0.21.0 // ssh
golang.org/x/crypto v0.22.0 // ssh
golang.org/x/oauth2 v0.18.0
golang.org/x/sync v0.6.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
@@ -89,7 +89,7 @@ require (
golang.org/x/exp v0.0.0-20230519143937-03e91628a987 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230131230820-1c016267d619 // indirect

View File

@@ -2,6 +2,7 @@ package form
type DbForm struct {
Id uint64 `json:"id"`
Code string `binding:"required" json:"code"`
Name string `binding:"required" json:"name"`
Database string `json:"database"`
Remark string `json:"remark"`

View File

@@ -14,7 +14,6 @@ import (
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/stringx"
"mayfly-go/pkg/utils/structx"
"sort"
"strings"
@@ -79,13 +78,18 @@ func (d *dbAppImpl) SaveDb(ctx context.Context, dbEntity *entity.Db, tagIds ...u
return errorx.NewBiz("该实例下数据库名已存在")
}
resouceCode := stringx.Rand(16)
dbEntity.Code = resouceCode
if d.CountByCond(&entity.Db{Code: dbEntity.Code}) > 0 {
return errorx.NewBiz("该编码已存在")
}
return d.Tx(ctx, func(ctx context.Context) error {
return d.Insert(ctx, dbEntity)
}, func(ctx context.Context) error {
return d.tagApp.RelateResource(ctx, resouceCode, consts.TagResourceTypeDb, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: dbEntity.Code,
ResourceType: consts.TagResourceTypeDb,
TagIds: tagIds,
})
})
}
@@ -116,10 +120,16 @@ func (d *dbAppImpl) SaveDb(ctx context.Context, dbEntity *entity.Db, tagIds ...u
d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: dbId, Db: v})
}
// 防止误传修改
dbEntity.Code = ""
return d.Tx(ctx, func(ctx context.Context) error {
return d.UpdateById(ctx, dbEntity)
}, func(ctx context.Context) error {
return d.tagApp.RelateResource(ctx, old.Code, consts.TagResourceTypeDb, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: old.Code,
ResourceType: consts.TagResourceTypeDb,
TagIds: tagIds,
})
})
}
@@ -142,8 +152,10 @@ func (d *dbAppImpl) Delete(ctx context.Context, id uint64) error {
// 删除该库下用户保存的所有sql信息
return d.dbSqlRepo.DeleteByCond(ctx, &entity.DbSql{DbId: id})
}, func(ctx context.Context) error {
var tagIds []uint64
return d.tagApp.RelateResource(ctx, db.Code, consts.TagResourceTypeDb, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: db.Code,
ResourceType: consts.TagResourceTypeDb,
})
})
}

View File

@@ -24,8 +24,8 @@ type DbTransferLogQuery struct {
// 数据库查询实体,不与数据库表字段一一对应
type DbQuery struct {
Id uint64 `form:"id"`
Id uint64 `form:"id"`
Code string `json:"code" form:"code"`
Name string `orm:"column(name)" json:"name"`
Database string `orm:"column(database)" json:"database"`
Remark string `json:"remark"`

View File

@@ -24,6 +24,7 @@ func (d *dbRepoImpl) GetDbList(condition *entity.DbQuery, pageParam *model.PageP
Eq("db.instance_id", condition.InstanceId).
Eq("db.id", condition.Id).
Like("db.database", condition.Database).
Eq("db.code", condition.Code).
In("db.code", condition.Codes).
Eq0("db."+model.DeletedColumn, model.ModelUndeleted).
Eq0("inst."+model.DeletedColumn, model.ModelUndeleted)
@@ -39,5 +40,8 @@ func (d *dbRepoImpl) Count(condition *entity.DbQuery) int64 {
if condition.InstanceId > 0 {
where["instance_id"] = condition.InstanceId
}
if condition.Code != "" {
where["code"] = condition.Code
}
return d.CountByCond(where)
}

View File

@@ -3,6 +3,7 @@ package form
type MachineForm struct {
Id uint64 `json:"id"`
Protocol int `json:"protocol" binding:"required"`
Code string `json:"code" binding:"required"`
Name string `json:"name" binding:"required"`
Ip string `json:"ip" binding:"required"` // IP地址
Port int `json:"port" binding:"required"` // 端口号

View File

@@ -16,7 +16,6 @@ import (
"mayfly-go/pkg/logx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/scheduler"
"mayfly-go/pkg/utils/stringx"
"time"
)
@@ -88,15 +87,21 @@ func (m *machineAppImpl) SaveMachine(ctx context.Context, me *entity.Machine, ta
if err == nil {
return errorx.NewBiz("该机器信息已存在")
}
resouceCode := stringx.Rand(16)
me.Code = resouceCode
if m.CountByCond(&entity.Machine{Code: me.Code}) > 0 {
return errorx.NewBiz("该编码已存在")
}
// 新增机器,默认启用状态
me.Status = entity.MachineStatusEnable
return m.Tx(ctx, func(ctx context.Context) error {
return m.Insert(ctx, me)
}, func(ctx context.Context) error {
return m.tagApp.RelateResource(ctx, resouceCode, consts.TagResourceTypeMachine, tagIds)
return m.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: me.Code,
ResourceType: consts.TagResourceTypeMachine,
TagIds: tagIds,
})
})
}
@@ -111,10 +116,16 @@ func (m *machineAppImpl) SaveMachine(ctx context.Context, me *entity.Machine, ta
// 关闭连接
mcm.DeleteCli(me.Id)
// 防止误传修改
me.Code = ""
return m.Tx(ctx, func(ctx context.Context) error {
return m.UpdateById(ctx, me)
}, func(ctx context.Context) error {
return m.tagApp.RelateResource(ctx, oldMachine.Code, consts.TagResourceTypeMachine, tagIds)
return m.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: oldMachine.Code,
ResourceType: consts.TagResourceTypeMachine,
TagIds: tagIds,
})
})
}
@@ -158,8 +169,10 @@ func (m *machineAppImpl) Delete(ctx context.Context, id uint64) error {
func(ctx context.Context) error {
return m.DeleteById(ctx, id)
}, func(ctx context.Context) error {
var tagIds []uint64
return m.tagApp.RelateResource(ctx, machine.Code, consts.TagResourceTypeMachine, tagIds)
return m.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceCode: machine.Code,
ResourceType: consts.TagResourceTypeMachine,
})
})
}

View File

@@ -48,7 +48,7 @@ func GetMachine() *Machine {
mc.UploadMaxFileSize = uploadMaxFileSize
mc.TermOpSaveDays = cast.ToIntD(jm["termOpSaveDays"], 30)
// guacd
mc.GuacdHost = cast.ToStringD(jm["guacdHost"], "127.0.0.1")
mc.GuacdHost = cast.ToString(jm["guacdHost"])
mc.GuacdPort = cast.ToIntD(jm["guacdPort"], 4822)
mc.GuacdFilePath = cast.ToStringD(jm["guacdFilePath"], "")
mc.GuacdRecPath = cast.ToStringD(jm["guacdRecPath"], "")

View File

@@ -4,6 +4,7 @@ import "time"
type MachineQuery struct {
Ids string `json:"ids" form:"ids"`
Code string `json:"code" form:"code"`
Name string `json:"name" form:"name"`
Status int8 `json:"status" form:"status"`
Ip string `json:"ip" form:"ip"` // IP地址

View File

@@ -4,13 +4,15 @@ import (
"bytes"
"errors"
"fmt"
"github.com/gorilla/websocket"
"io"
"mayfly-go/internal/machine/config"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
"net"
"net/url"
"strconv"
"github.com/gorilla/websocket"
)
// creates the tunnel to the remote machine (via guacd)
@@ -62,7 +64,12 @@ func DoConnect(query url.Values, parameters map[string]string, machineId uint64)
conf.ImageMimetypes = []string{"image/jpeg", "image/png", "image/webp"}
logx.Debug("Connecting to guacd")
guacdAddr := fmt.Sprintf("%v:%v", config.GetMachine().GuacdHost, config.GetMachine().GuacdPort)
machineConfig := config.GetMachine()
if machineConfig.GuacdHost == "" {
return nil, errorx.NewBiz("请前往'系统配置-机器配置'中配置guacd相关信息")
}
guacdAddr := fmt.Sprintf("%v:%v", machineConfig.GuacdHost, machineConfig.GuacdPort)
addr, err := net.ResolveTCPAddr("tcp", guacdAddr)
if err != nil {
logx.Error("error resolving guacd address", err)

View File

@@ -27,7 +27,8 @@ func (m *machineRepoImpl) GetMachineList(condition *entity.MachineQuery, pagePar
Eq("status", condition.Status).
Like("ip", condition.Ip).
Like("name", condition.Name).
In("code", condition.Codes)
In("code", condition.Codes).
Eq("code", condition.Code)
// 只查询ssh服务器
if condition.Ssh == entity.MachineProtocolSsh {

View File

@@ -2,6 +2,7 @@ package form
type Mongo struct {
Id uint64 `json:"id"`
Code uint64 `json:"code" binding:"required"`
Uri string `binding:"required" json:"uri"`
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
Name string `binding:"required" json:"name"`

View File

@@ -10,7 +10,6 @@ import (
"mayfly-go/pkg/base"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils/stringx"
)
type Mongo interface {
@@ -59,8 +58,10 @@ func (d *mongoAppImpl) Delete(ctx context.Context, id uint64) error {
return d.DeleteById(ctx, id)
},
func(ctx context.Context) error {
var tagIds []uint64
return d.tagApp.RelateResource(ctx, mongoEntity.Code, consts.TagResourceTypeMongo, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeMongo,
ResourceCode: mongoEntity.Code,
})
})
}
@@ -81,14 +82,18 @@ func (d *mongoAppImpl) SaveMongo(ctx context.Context, m *entity.Mongo, tagIds ..
if err == nil {
return errorx.NewBiz("该名称已存在")
}
resouceCode := stringx.Rand(16)
m.Code = resouceCode
if d.CountByCond(&entity.Mongo{Code: m.Code}) > 0 {
return errorx.NewBiz("该编码已存在")
}
return d.Tx(ctx, func(ctx context.Context) error {
return d.Insert(ctx, m)
}, func(ctx context.Context) error {
return d.tagApp.RelateResource(ctx, resouceCode, consts.TagResourceTypeMongo, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeMongo,
ResourceCode: m.Code,
TagIds: tagIds,
})
})
}
@@ -103,10 +108,15 @@ func (d *mongoAppImpl) SaveMongo(ctx context.Context, m *entity.Mongo, tagIds ..
// 先关闭连接
mgm.CloseConn(m.Id)
m.Code = ""
return d.Tx(ctx, func(ctx context.Context) error {
return d.UpdateById(ctx, m)
}, func(ctx context.Context) error {
return d.tagApp.RelateResource(ctx, oldMongo.Code, consts.TagResourceTypeMongo, tagIds)
return d.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeMongo,
ResourceCode: oldMongo.Code,
TagIds: tagIds,
})
})
}

View File

@@ -5,6 +5,7 @@ import "mayfly-go/pkg/model"
type MongoQuery struct {
model.Model
Code string `json:"code" form:"code"`
Name string
Uri string
SshTunnelMachineId uint64 // ssh隧道机器id

View File

@@ -20,6 +20,7 @@ func newMongoRepo() repository.Mongo {
func (d *mongoRepoImpl) GetList(condition *entity.MongoQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
qd := gormx.NewQuery(new(entity.Mongo)).
Like("name", condition.Name).
Eq("code", condition.Code).
In("code", condition.Codes)
return gormx.PageQuery(qd, pageParam, toEntity)
}

View File

@@ -2,6 +2,7 @@ package form
type Redis struct {
Id uint64 `json:"id"`
Code string `json:"code" binding:"required"`
Name string `json:"name"`
Host string `json:"host" binding:"required"`
Username string `json:"username"`

View File

@@ -95,17 +95,22 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, re *entity.Redis, tagIds .
if err == nil {
return errorx.NewBiz("该实例已存在")
}
if r.CountByCond(&entity.Redis{Code: re.Code}) > 0 {
return errorx.NewBiz("该编码已存在")
}
if errEnc := re.PwdEncrypt(); errEnc != nil {
return errorx.NewBiz(errEnc.Error())
}
resouceCode := stringx.Rand(16)
re.Code = resouceCode
return r.Tx(ctx, func(ctx context.Context) error {
return r.Insert(ctx, re)
}, func(ctx context.Context) error {
return r.tagApp.RelateResource(ctx, resouceCode, consts.TagResourceTypeRedis, tagIds)
return r.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeRedis,
ResourceCode: re.Code,
TagIds: tagIds,
})
})
}
@@ -128,10 +133,15 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, re *entity.Redis, tagIds .
if errEnc := re.PwdEncrypt(); errEnc != nil {
return errorx.NewBiz(errEnc.Error())
}
re.Code = ""
return r.Tx(ctx, func(ctx context.Context) error {
return r.UpdateById(ctx, re)
}, func(ctx context.Context) error {
return r.tagApp.RelateResource(ctx, oldRedis.Code, consts.TagResourceTypeRedis, tagIds)
return r.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeRedis,
ResourceCode: oldRedis.Code,
TagIds: tagIds,
})
})
}
@@ -150,8 +160,10 @@ func (r *redisAppImpl) Delete(ctx context.Context, id uint64) error {
return r.Tx(ctx, func(ctx context.Context) error {
return r.DeleteById(ctx, id)
}, func(ctx context.Context) error {
var tagIds []uint64
return r.tagApp.RelateResource(ctx, re.Code, consts.TagResourceTypeRedis, tagIds)
return r.tagApp.SaveResource(ctx, &tagapp.SaveResourceTagParam{
ResourceType: consts.TagResourceTypeRedis,
ResourceCode: re.Code,
})
})
}

View File

@@ -2,6 +2,7 @@ package entity
type RedisQuery struct {
Id uint64 `form:"id"`
Code string `json:"code" form:"code"`
Name string `orm:"column(name)" json:"name" form:"name"`
Host string `orm:"column(host)" json:"host" form:"host"`

View File

@@ -16,11 +16,12 @@ func newRedisRepo() repository.Redis {
return &redisRepoImpl{base.RepoImpl[*entity.Redis]{M: new(entity.Redis)}}
}
// 分页获取机器信息列表
// 分页获取redis信息列表
func (r *redisRepoImpl) GetRedisList(condition *entity.RedisQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
qd := gormx.NewQuery(new(entity.Redis)).
Eq("id", condition.Id).
Like("host", condition.Host).
Eq("code", condition.Code).
In("code", condition.Codes)
return gormx.PageQuery(qd, pageParam, toEntity)
}

View File

@@ -14,15 +14,15 @@ import (
)
type TagTree struct {
TagTreeApp application.TagTree `inject:""`
TagResourceApp application.TagResource `inject:""`
TagTreeApp application.TagTree `inject:""`
}
func (p *TagTree) GetTagTree(rc *req.Ctx) {
tagType := rc.QueryInt("type")
// 超管返回所有标签树
if rc.GetLoginAccount().Id == consts.AdminId {
var tagTrees vo.TagTreeVOS
p.TagTreeApp.ListByQuery(new(entity.TagTreeQuery), &tagTrees)
p.TagTreeApp.ListByQuery(&entity.TagTreeQuery{Type: int8(tagType)}, &tagTrees)
rc.ResData = tagTrees.ToTrees(0)
return
}
@@ -36,11 +36,12 @@ func (p *TagTree) GetTagTree(rc *req.Ctx) {
tags := rootTag[root]
tags = append(tags, accountTagPath)
rootTag[root] = tags
}
// 获取所有以root标签开头的子标签
tags := p.TagTreeApp.ListTagByPath(collx.MapKeys(rootTag)...)
var tags []*entity.TagTree
p.TagTreeApp.ListByQuery(&entity.TagTreeQuery{CodePathLikes: collx.MapKeys(rootTag), Type: int8(tagType)}, &tags)
tagTrees := make(vo.TagTreeVOS, 0)
for _, tag := range tags {
tagPath := tag.CodePath
@@ -84,8 +85,8 @@ func (p *TagTree) DelTagTree(rc *req.Ctx) {
func (p *TagTree) TagResources(rc *req.Ctx) {
resourceType := int8(rc.PathParamInt("rtype"))
tagResources := p.TagTreeApp.GetAccountTagResources(rc.GetLoginAccount().Id, resourceType, "")
tagPath2Resource := collx.ArrayToMap[entity.TagResource, string](tagResources, func(tagResource entity.TagResource) string {
return tagResource.TagPath
tagPath2Resource := collx.ArrayToMap[entity.TagTree, string](tagResources, func(tagResource entity.TagTree) string {
return tagResource.GetParentPath()
})
tagPaths := collx.MapKeys(tagPath2Resource)
@@ -104,10 +105,3 @@ func (p *TagTree) CountTagResource(rc *req.Ctx) {
"mongo": len(p.TagTreeApp.GetAccountResourceCodes(accountId, consts.TagResourceTypeMongo, tagPath)),
}
}
// 资源标签关联信息查询
func (p *TagTree) QueryTagResources(rc *req.Ctx) {
var trs []*entity.TagResource
p.TagResourceApp.ListByQuery(req.BindQuery(rc, new(entity.TagResourceQuery)), &trs)
rc.ResData = trs
}

View File

@@ -7,5 +7,4 @@ import (
func InitIoc() {
ioc.Register(new(tagTreeAppImpl), ioc.WithComponentName("TagTreeApp"))
ioc.Register(new(teamAppImpl), ioc.WithComponentName("TeamApp"))
ioc.Register(new(tagResourceAppImpl), ioc.WithComponentName("TagResourceApp"))
}

View File

@@ -1,26 +0,0 @@
package application
import (
"mayfly-go/internal/tag/domain/entity"
"mayfly-go/internal/tag/domain/repository"
"mayfly-go/pkg/base"
)
type TagResource interface {
base.App[*entity.TagResource]
ListByQuery(condition *entity.TagResourceQuery, toEntity any)
}
type tagResourceAppImpl struct {
base.AppImpl[*entity.TagResource, repository.TagResource]
}
// 注入TagResourceRepo
func (tr *tagResourceAppImpl) InjectTagResourceRepo(repo repository.TagResource) {
tr.Repo = repo
}
func (tr *tagResourceAppImpl) ListByQuery(condition *entity.TagResourceQuery, toEntity any) {
tr.Repo.SelectByCondition(condition, toEntity)
}

View File

@@ -12,6 +12,15 @@ import (
"strings"
)
// 保存资源标签参数
type SaveResourceTagParam struct {
ResourceCode string
ResourceName string
ResourceType int8
TagIds []uint64 // 关联标签,相当于父标签 pid
}
type TagTree interface {
base.App[*entity.TagTree]
@@ -25,23 +34,17 @@ type TagTree interface {
// @param accountId 账号id
// @param resourceType 资源类型
// @param tagPath 访问指定的标签路径下关联的资源
GetAccountTagResources(accountId uint64, resourceType int8, tagPath string) []entity.TagResource
GetAccountTagResources(accountId uint64, resourceType int8, tagPath string) []entity.TagTree
// 获取指定账号有权限操作的资源codes
GetAccountResourceCodes(accountId uint64, resourceType int8, tagPath string) []string
// 关联资源
// @resourceCode 资源唯一编号
// @resourceType 资源类型
// @tagIds 资源关联的标签
RelateResource(ctx context.Context, resourceCode string, resourceType int8, tagIds []uint64) error
// SaveResource 保存资源标签
SaveResource(ctx context.Context, req *SaveResourceTagParam) error
// 根据资源信息获取对应的标签路径列表
ListTagPathByResource(resourceType int8, resourceCode string) []string
// 根据tagPath获取自身及其所有子标签信息
ListTagByPath(tagPath ...string) []*entity.TagTree
// 根据账号id获取其可访问标签信息
ListTagByAccountId(accountId uint64) []string
@@ -56,7 +59,6 @@ type tagTreeAppImpl struct {
base.AppImpl[*entity.TagTree, repository.TagTree]
tagTreeTeamRepo repository.TagTreeTeam `inject:"TagTreeTeamRepo"`
tagResourceApp TagResource `inject:"TagResourceApp"`
}
// 注入TagTreeRepo
@@ -76,9 +78,9 @@ func (p *tagTreeAppImpl) Save(ctx context.Context, tag *entity.TagTree) error {
if err != nil {
return errorx.NewBiz("父节点不存在")
}
if p.tagResourceApp.CountByCond(&entity.TagResource{TagId: tag.Pid}) > 0 {
return errorx.NewBiz("该父标签已关联资源, 无法添加子标签")
}
// if p.tagResourceApp.CountByCond(&entity.TagResource{TagId: tag.Pid}) > 0 {
// return errorx.NewBiz("该父标签已关联资源, 无法添加子标签")
// }
tag.CodePath = parentTag.CodePath + tag.Code + entity.CodePathSeparator
} else {
@@ -98,6 +100,8 @@ func (p *tagTreeAppImpl) Save(ctx context.Context, tag *entity.TagTree) error {
return errorx.NewBiz("已存在该标签路径开头的标签, 请修改该标识code")
}
// 普通标签类型
tag.Type = -1
return p.Insert(ctx, tag)
}
@@ -111,12 +115,12 @@ func (p *tagTreeAppImpl) ListByQuery(condition *entity.TagTreeQuery, toEntity an
p.GetRepo().SelectByCondition(condition, toEntity)
}
func (p *tagTreeAppImpl) GetAccountTagResources(accountId uint64, resourceType int8, tagPath string) []entity.TagResource {
tagResourceQuery := &entity.TagResourceQuery{
ResourceType: resourceType,
func (p *tagTreeAppImpl) GetAccountTagResources(accountId uint64, resourceType int8, tagPath string) []entity.TagTree {
tagResourceQuery := &entity.TagTreeQuery{
Type: resourceType,
}
var tagResources []entity.TagResource
var tagResources []entity.TagTree
var accountTagPaths []string
if accountId != consts.AdminId {
@@ -127,70 +131,82 @@ func (p *tagTreeAppImpl) GetAccountTagResources(accountId uint64, resourceType i
}
}
tagResourceQuery.TagPathLike = tagPath
tagResourceQuery.TagPathLikes = accountTagPaths
p.tagResourceApp.ListByQuery(tagResourceQuery, &tagResources)
tagResourceQuery.CodePathLike = tagPath
tagResourceQuery.CodePathLikes = accountTagPaths
p.ListByQuery(tagResourceQuery, &tagResources)
return tagResources
}
func (p *tagTreeAppImpl) GetAccountResourceCodes(accountId uint64, resourceType int8, tagPath string) []string {
tagResources := p.GetAccountTagResources(accountId, resourceType, tagPath)
// resouce code去重
code2Resource := collx.ArrayToMap[entity.TagResource, string](tagResources, func(val entity.TagResource) string {
return val.ResourceCode
code2Resource := collx.ArrayToMap[entity.TagTree, string](tagResources, func(val entity.TagTree) string {
return val.Code
})
return collx.MapKeys(code2Resource)
}
func (p *tagTreeAppImpl) RelateResource(ctx context.Context, resourceCode string, resourceType int8, tagIds []uint64) error {
func (p *tagTreeAppImpl) SaveResource(ctx context.Context, req *SaveResourceTagParam) error {
resourceCode := req.ResourceCode
resourceType := req.ResourceType
resourceName := req.ResourceName
tagIds := req.TagIds
if resourceCode == "" {
return errorx.NewBiz("资源编号不能为空")
}
// 如果tagIds为空数组则为解绑该标签资源关联关系
if len(tagIds) == 0 {
return p.tagResourceApp.DeleteByCond(ctx, &entity.TagResource{
ResourceCode: resourceCode,
ResourceType: resourceType,
})
if resourceType == 0 {
return errorx.NewBiz("资源类型不能为空")
}
var oldTagResources []*entity.TagResource
p.tagResourceApp.ListByQuery(&entity.TagResourceQuery{ResourceType: resourceType, ResourceCode: resourceCode}, &oldTagResources)
// 如果tagIds为空数组则为删除该资源标签
if len(tagIds) == 0 {
return p.DeleteByCond(ctx, &entity.TagTree{Code: resourceCode, Type: resourceType})
}
if resourceName == "" {
resourceName = resourceCode
}
// 该资源对应的旧资源标签信息
var oldTagTree []*entity.TagTree
p.ListByCond(&entity.TagTree{Type: resourceType, Code: resourceCode}, &oldTagTree)
var addTagIds, delTagIds []uint64
if len(oldTagResources) == 0 {
if len(oldTagTree) == 0 {
addTagIds = tagIds
} else {
oldTagIds := collx.ArrayMap[*entity.TagResource, uint64](oldTagResources, func(tr *entity.TagResource) uint64 {
return tr.TagId
oldTagIds := collx.ArrayMap(oldTagTree, func(tag *entity.TagTree) uint64 {
return tag.Pid
})
addTagIds, delTagIds, _ = collx.ArrayCompare[uint64](tagIds, oldTagIds)
}
if len(addTagIds) > 0 {
addTagResource := make([]*entity.TagResource, 0)
addTagResource := make([]*entity.TagTree, 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,
addTagResource = append(addTagResource, &entity.TagTree{
Pid: tagId,
Code: resourceCode,
Type: resourceType,
Name: resourceName,
CodePath: tag.CodePath + resourceCode + entity.CodePathSeparator,
})
}
if err := p.tagResourceApp.BatchInsert(ctx, addTagResource); err != nil {
if err := p.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 {
cond := &entity.TagTree{Code: resourceCode, Type: resourceType, Pid: tagId}
if err := p.DeleteByCond(ctx, cond); err != nil {
return err
}
}
@@ -200,19 +216,13 @@ func (p *tagTreeAppImpl) RelateResource(ctx context.Context, resourceCode string
}
func (p *tagTreeAppImpl) ListTagPathByResource(resourceType int8, resourceCode string) []string {
var trs []*entity.TagResource
p.tagResourceApp.ListByQuery(&entity.TagResourceQuery{ResourceType: resourceType, ResourceCode: resourceCode}, &trs)
return collx.ArrayMap(trs, func(tr *entity.TagResource) string {
return tr.TagPath
var trs []*entity.TagTree
p.ListByCond(&entity.TagTree{Type: resourceType, Code: resourceCode}, &trs)
return collx.ArrayMap(trs, func(tr *entity.TagTree) string {
return tr.CodePath
})
}
func (p *tagTreeAppImpl) ListTagByPath(tagPaths ...string) []*entity.TagTree {
var tags []*entity.TagTree
p.GetRepo().SelectByCondition(&entity.TagTreeQuery{CodePathLikes: tagPaths}, &tags)
return tags
}
func (p *tagTreeAppImpl) ListTagByAccountId(accountId uint64) []string {
return p.tagTreeTeamRepo.SelectTagPathsByAccountId(accountId)
}
@@ -245,12 +255,12 @@ func (p *tagTreeAppImpl) FillTagInfo(resources ...entity.ITagResource) {
})
// 获取所有资源code关联的标签列表信息
var tagResources []*entity.TagResource
p.tagResourceApp.ListByQuery(&entity.TagResourceQuery{ResourceCodes: collx.MapKeys(resourceCode2Resouce)}, &tagResources)
var tagResources []*entity.TagTree
p.ListByQuery(&entity.TagTreeQuery{Codes: collx.MapKeys(resourceCode2Resouce)}, &tagResources)
for _, tr := range tagResources {
// 赋值标签信息
resourceCode2Resouce[tr.ResourceCode].SetTagInfo(entity.ResourceTag{TagId: tr.TagId, TagPath: tr.TagPath})
resourceCode2Resouce[tr.Code].SetTagInfo(entity.ResourceTag{TagId: tr.Pid, TagPath: tr.GetParentPath()})
}
}
@@ -264,7 +274,7 @@ func (p *tagTreeAppImpl) Delete(ctx context.Context, id uint64) error {
return errorx.NewBiz("您无权删除该标签")
}
if p.tagResourceApp.CountByCond(&entity.TagResource{TagId: id}) > 0 {
if p.CountByCond(&entity.TagTree{Pid: id}) > 0 {
return errorx.NewBiz("请先移除该标签关联的资源")
}

View File

@@ -6,7 +6,9 @@ type TagTreeQuery struct {
model.Model
Pid uint64
Code string `json:"code"` // 标识
Type int8 `json:"type"`
Code string `json:"code"` // 标识
Codes []string
CodePath string `json:"codePath"` // 标识路径
CodePaths []string
Name string `json:"name"` // 名称
@@ -14,19 +16,6 @@ type TagTreeQuery struct {
CodePathLikes []string
}
type TagResourceQuery struct {
model.Model
TagPath string `json:"string"` // 标签路径
TagId uint64 `json:"tagId" form:"tagId"`
ResourceType int8 `json:"resourceType" form:"resourceType"` // 资源编码
ResourceCode string `json:"resourceCode" form:"resourceCode"` // 资源编码
ResourceCodes []string // 资源编码列表
TagPathLike string // 标签路径模糊查询
TagPathLikes []string
}
type TeamQuery struct {
model.Model

View File

@@ -1,47 +0,0 @@
package entity
import (
"mayfly-go/pkg/model"
)
// 标签资源关联
type TagResource struct {
model.Model
TagId uint64 `json:"tagId"`
TagPath string `json:"tagPath"` // 标签路径
ResourceCode string `json:"resourceCode"` // 资源标识
ResourceType int8 `json:"resourceType"` // 资源类型
}
// 标签接口资源,如果要实现资源结构体填充标签信息,则资源结构体需要实现该接口
type ITagResource interface {
// 获取资源code
GetCode() string
// 赋值标签基本信息
SetTagInfo(rt ResourceTag)
}
// 资源关联的标签信息
type ResourceTag struct {
TagId uint64 `json:"tagId" gorm:"-"`
TagPath string `json:"tagPath" gorm:"-"` // 标签路径
}
func (r *ResourceTag) SetTagInfo(rt ResourceTag) {
r.TagId = rt.TagId
r.TagPath = rt.TagPath
}
// 资源标签列表
type ResourceTags struct {
Tags []ResourceTag `json:"tags" gorm:"-"`
}
func (r *ResourceTags) SetTagInfo(rt ResourceTag) {
if r.Tags == nil {
r.Tags = make([]ResourceTag, 0)
}
r.Tags = append(r.Tags, rt)
}

View File

@@ -10,7 +10,8 @@ type TagTree struct {
model.Model
Pid uint64 `json:"pid"`
Code string `json:"code"` // 标识
Type int8 `json:"type"` // 类型: -1.普通标签; 其他值则为对应的资源类型
Code string `json:"code"` // 标识编码, 若类型不为-1则为对应资源编码
CodePath string `json:"codePath"` // 标识路径
Name string `json:"name"` // 名称
Remark string `json:"remark"` // 备注说明
@@ -21,7 +22,54 @@ const (
CodePathSeparator = "/"
)
// 获取根路径信息
// GetRootCode 获取根路径信息
func (pt *TagTree) GetRootCode() string {
return strings.Split(pt.CodePath, CodePathSeparator)[0]
}
// GetParentPath 获取父标签路径, 如CodePath = test/test1/test2/ -> test/test1/
func (pt *TagTree) GetParentPath() string {
// 去掉末尾的分隔符
input := strings.TrimRight(pt.CodePath, CodePathSeparator)
// 查找倒数第二个连字符位置
lastHyphenIndex := strings.LastIndex(input, CodePathSeparator)
if lastHyphenIndex == -1 {
return ""
}
// 截取字符串
return input[:lastHyphenIndex+1]
}
// 标签接口资源,如果要实现资源结构体填充标签信息,则资源结构体需要实现该接口
type ITagResource interface {
// 获取资源code
GetCode() string
// 赋值标签基本信息
SetTagInfo(rt ResourceTag)
}
// 资源关联的标签信息
type ResourceTag struct {
TagId uint64 `json:"tagId" gorm:"-"`
TagPath string `json:"tagPath" gorm:"-"` // 标签路径
}
func (r *ResourceTag) SetTagInfo(rt ResourceTag) {
r.TagId = rt.TagId
r.TagPath = rt.TagPath
}
// 资源标签列表
type ResourceTags struct {
Tags []ResourceTag `json:"tags" gorm:"-"`
}
func (r *ResourceTags) SetTagInfo(rt ResourceTag) {
if r.Tags == nil {
r.Tags = make([]ResourceTag, 0)
}
r.Tags = append(r.Tags, rt)
}

View File

@@ -1,12 +0,0 @@
package repository
import (
"mayfly-go/internal/tag/domain/entity"
"mayfly-go/pkg/base"
)
type TagResource interface {
base.Repo[*entity.TagResource]
SelectByCondition(condition *entity.TagResourceQuery, toEntity any, orderBy ...string)
}

View File

@@ -7,7 +7,6 @@ import (
func InitIoc() {
ioc.Register(newTagTreeRepo(), ioc.WithComponentName("TagTreeRepo"))
ioc.Register(newTagTreeTeamRepo(), ioc.WithComponentName("TagTreeTeamRepo"))
ioc.Register(newTagResourceRepo(), ioc.WithComponentName("TagResourceRepo"))
ioc.Register(newTeamRepo(), ioc.WithComponentName("TeamRepo"))
ioc.Register(newTeamMemberRepo(), ioc.WithComponentName("TeamMemberRepo"))
}

View File

@@ -1,65 +0,0 @@
package persistence
import (
"mayfly-go/internal/tag/domain/entity"
"mayfly-go/internal/tag/domain/repository"
"mayfly-go/pkg/base"
"mayfly-go/pkg/gormx"
)
type tagResourceRepoImpl struct {
base.RepoImpl[*entity.TagResource]
}
func newTagResourceRepo() repository.TagResource {
return &tagResourceRepoImpl{base.RepoImpl[*entity.TagResource]{M: new(entity.TagResource)}}
}
func (p *tagResourceRepoImpl) SelectByCondition(condition *entity.TagResourceQuery, toEntity any, orderBy ...string) {
sql := "SELECT tr.resource_type, tr.resource_code, tr.tag_id, tr.tag_path FROM t_tag_resource tr WHERE tr.is_deleted = 0 "
params := make([]any, 0)
if condition.ResourceType != 0 {
sql = sql + " AND tr.resource_type = ?"
params = append(params, condition.ResourceType)
}
if condition.ResourceCode != "" {
sql = sql + " AND tr.resource_code = ?"
params = append(params, condition.ResourceCode)
}
if len(condition.ResourceCodes) > 0 {
sql = sql + " AND tr.resource_code IN (?)"
params = append(params, condition.ResourceCodes)
}
if condition.TagId != 0 {
sql = sql + " AND tr.tag_id = ?"
params = append(params, condition.TagId)
}
if condition.TagPath != "" {
sql = sql + " AND tr.tag_path = ?"
params = append(params, condition.TagPath)
}
if condition.TagPathLike != "" {
sql = sql + " AND tr.tag_path LIKE ?"
params = append(params, condition.TagPathLike+"%")
}
if len(condition.TagPathLikes) > 0 {
sql = sql + " AND ("
for i, v := range condition.TagPathLikes {
if i == 0 {
sql = sql + "tr.tag_path LIKE ?"
} else {
sql = sql + " OR tr.tag_path LIKE ?"
}
params = append(params, v+"%")
}
sql = sql + ")"
}
sql = sql + " ORDER BY tr.tag_path"
gormx.GetListBySql2Model(sql, toEntity, params...)
}

View File

@@ -16,7 +16,7 @@ func newTagTreeRepo() repository.TagTree {
}
func (p *tagTreeRepoImpl) SelectByCondition(condition *entity.TagTreeQuery, toEntity any, orderBy ...string) {
sql := "SELECT DISTINCT(p.id), p.pid, p.code, p.code_path, p.name, p.remark, p.create_time, p.creator, p.update_time, p.modifier FROM t_tag_tree p WHERE p.is_deleted = 0 "
sql := "SELECT DISTINCT(p.id), p.pid, p.type, p.code, p.code_path, p.name, p.remark, p.create_time, p.creator, p.update_time, p.modifier FROM t_tag_tree p WHERE p.is_deleted = 0 "
params := make([]any, 0)
if condition.Name != "" {
@@ -27,6 +27,10 @@ func (p *tagTreeRepoImpl) SelectByCondition(condition *entity.TagTreeQuery, toEn
sql = sql + " AND p.code_path = ?"
params = append(params, condition.CodePath)
}
if len(condition.Codes) > 0 {
sql = sql + " AND p.code IN (?)"
params = append(params, condition.Codes)
}
if len(condition.CodePaths) > 0 {
sql = sql + " AND p.code_path IN (?)"
params = append(params, condition.CodePaths)
@@ -39,6 +43,10 @@ func (p *tagTreeRepoImpl) SelectByCondition(condition *entity.TagTreeQuery, toEn
sql = sql + " AND p.pid = ?"
params = append(params, condition.Pid)
}
if condition.Type != 0 {
sql = sql + " AND p.type = ?"
params = append(params, condition.Type)
}
if len(condition.CodePathLikes) > 0 {
sql = sql + " AND ("
for i, v := range condition.CodePathLikes {
@@ -51,6 +59,6 @@ func (p *tagTreeRepoImpl) SelectByCondition(condition *entity.TagTreeQuery, toEn
}
sql = sql + ")"
}
sql = sql + " ORDER BY p.code_path"
sql = sql + " ORDER BY p.type, p.code_path"
gormx.GetListBySql2Model(sql, toEntity, params...)
}

View File

@@ -29,8 +29,6 @@ func InitTagTreeRouter(router *gin.RouterGroup) {
req.NewGet("/resources/:rtype/tag-paths", m.TagResources),
req.NewGet("/resources/count", m.CountTagResource),
req.NewGet("/resources", m.QueryTagResources),
}
req.BatchSetGroup(tagTree, reqs[:])

View File

@@ -1,6 +1,8 @@
package model
import (
"database/sql/driver"
"encoding/json"
"time"
)
@@ -125,3 +127,14 @@ func GetIdByGenType(genType IdGenType) uint64 {
}
return 0
}
type Map[K comparable, V any] map[K]V
func (m *Map[K, V]) Scan(value any) error {
return json.Unmarshal(value.([]byte), m)
}
func (m Map[K, V]) Value() (driver.Value, error) {
return json.Marshal(m)
}

View File

@@ -334,6 +334,7 @@ CREATE TABLE `t_machine` (
`name` varchar(32) DEFAULT NULL,
`ip` varchar(50) NOT NULL,
`port` int(12) NOT NULL,
`protocol` tinyint(2) NULL COMMENT '协议 1、SSH 2、RDP',
`username` varchar(12) NOT NULL,
`auth_method` tinyint(2) DEFAULT NULL COMMENT '1.密码登录2.publickey登录',
`password` varchar(100) DEFAULT NULL,
@@ -634,7 +635,7 @@ INSERT INTO `t_sys_config` (name, `key`, params, value, remark, create_time, cre
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('oauth2登录配置', 'Oauth2Login', '[{"name":"是否启用","model":"enable","placeholder":"是否启用oauth2登录","options":"true,false"},{"name":"名称","model":"name","placeholder":"oauth2名称"},{"name":"Client ID","model":"clientId","placeholder":"Client ID"},{"name":"Client Secret","model":"clientSecret","placeholder":"Client Secret"},{"name":"Authorization URL","model":"authorizationURL","placeholder":"Authorization URL"},{"name":"AccessToken URL","model":"accessTokenURL","placeholder":"AccessToken URL"},{"name":"Redirect URL","model":"redirectURL","placeholder":"本系统地址"},{"name":"Scopes","model":"scopes","placeholder":"Scopes"},{"name":"Resource URL","model":"resourceURL","placeholder":"获取用户信息资源地址"},{"name":"UserIdentifier","model":"userIdentifier","placeholder":"用户唯一标识字段;格式为type:fieldPath(string:username)"},{"name":"是否自动注册","model":"autoRegister","placeholder":"","options":"true,false"}]', '', 'oauth2登录相关配置信息', 'admin,', '2023-07-22 13:58:51', 1, 'admin', '2023-07-22 19:34:37', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('ldap登录配置', 'LdapLogin', '[{"name":"是否启用","model":"enable","placeholder":"是否启用","options":"true,false"},{"name":"host","model":"host","placeholder":"host"},{"name":"port","model":"port","placeholder":"port"},{"name":"bindDN","model":"bindDN","placeholder":"LDAP 服务的管理员账号,如: \\"cn=admin,dc=example,dc=com\\""},{"name":"bindPwd","model":"bindPwd","placeholder":"LDAP 服务的管理员密码"},{"name":"baseDN","model":"baseDN","placeholder":"用户所在的 base DN, 如: \\"ou=users,dc=example,dc=com\\""},{"name":"userFilter","model":"userFilter","placeholder":"过滤用户的方式, 如: \\"(uid=%s)、(&(objectClass=organizationalPerson)(uid=%s))\\""},{"name":"uidMap","model":"uidMap","placeholder":"用户id和 LDAP 字段名之间的映射关系,如: cn"},{"name":"udnMap","model":"udnMap","placeholder":"用户姓名(dispalyName)和 LDAP 字段名之间的映射关系,如: displayName"},{"name":"emailMap","model":"emailMap","placeholder":"用户email和 LDAP 字段名之间的映射关系"},{"name":"skipTLSVerify","model":"skipTLSVerify","placeholder":"客户端是否跳过 TLS 证书验证","options":"true,false"},{"name":"安全协议","model":"securityProtocol","placeholder":"安全协议为Null不使用安全协议如: StartTLS, LDAPS","options":"Null,StartTLS,LDAPS"}]', '', 'ldap登录相关配置', 'admin,', '2023-08-25 21:47:20', 1, 'admin', '2023-08-25 22:56:07', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('系统全局样式设置', 'SysStyleConfig', '[{"model":"logoIcon","name":"logo图标","placeholder":"系统logo图标base64编码, 建议svg格式不超过10k","required":false},{"model":"title","name":"菜单栏标题","placeholder":"系统菜单栏标题展示","required":false},{"model":"viceTitle","name":"登录页标题","placeholder":"登录页标题展示","required":false},{"model":"useWatermark","name":"是否启用水印","placeholder":"是否启用系统水印","options":"true,false","required":false},{"model":"watermarkContent","name":"水印补充信息","placeholder":"额外水印信息","required":false}]', '{"title":"mayfly-go","viceTitle":"mayfly-go","logoIcon":"","useWatermark":"true","watermarkContent":""}', '系统icon、标题、水印信息等配置', 'all', '2024-01-04 15:17:18', 1, 'admin', '2024-01-05 09:40:44', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB\\2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"100MB"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-01-15 16:30:22', 1, 'admin', 0, NULL);
INSERT INTO t_sys_config ( name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"},{"model":"guacdHost","name":"guacd服务ip","placeholder":"guacd服务ip默认 127.0.0.1","required":false},{"name":"guacd服务端口","model":"guacdPort","placeholder":"guacd服务端口默认 4822","required":false},{"model":"guacdFilePath","name":"guacd服务文件存储位置","placeholder":"guacd服务文件存储位置用于挂载RDP文件夹"},{"name":"guacd服务记录存储位置","model":"guacdRecPath","placeholder":"guacd服务记录存储位置用于记录rdp操作记录"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"1000MB","termOpSaveDays":"30","guacdHost":"","guacdPort":"","guacdFilePath":"./guacd/rdp-file","guacdRecPath":"./guacd/rdp-rec"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-04-06 12:25:03', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('数据库备份恢复', 'DbBackupRestore', '[{"model":"backupPath","name":"备份路径","placeholder":"备份文件存储路径"}]', '{"backupPath":"./db/backup"}', '', 'admin,', '2023-12-29 09:55:26', 1, 'admin', '2023-12-29 15:45:24', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('Mysql可执行文件', 'MysqlBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mysql/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);
INSERT INTO `t_sys_config` (`name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES('MariaDB可执行文件', 'MariadbBin', '[{"model":"path","name":"路径","placeholder":"可执行文件路径","required":true},{"model":"mysql","name":"mysql","placeholder":"mysql命令路径(空则为 路径/mysql)","required":false},{"model":"mysqldump","name":"mysqldump","placeholder":"mysqldump命令路径(空则为 路径/mysqldump)","required":false},{"model":"mysqlbinlog","name":"mysqlbinlog","placeholder":"mysqlbinlog命令路径(空则为 路径/mysqlbinlog)","required":false}]', '{"mysql":"","mysqldump":"","mysqlbinlog":"","path":"./db/mariadb/bin"}', '', 'admin,', '2023-12-29 10:01:33', 1, 'admin', '2023-12-29 13:34:40', 1, 'admin', 0, NULL);
@@ -936,26 +937,6 @@ CREATE TABLE `t_tag_tree_team` (
KEY `idx_tag_id` (`tag_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='标签树团队关联信息';
DROP TABLE IF EXISTS `t_tag_resource`;
CREATE TABLE `t_tag_resource` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`tag_id` bigint NOT NULL,
`tag_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL COMMENT '标签路径',
`resource_code` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT NULL COMMENT '资源编码',
`resource_type` tinyint NOT NULL COMMENT '资源类型',
`create_time` datetime NOT NULL,
`creator_id` bigint NOT NULL,
`creator` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`update_time` datetime NOT NULL,
`modifier_id` bigint NOT NULL,
`modifier` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
`is_deleted` tinyint DEFAULT '0',
`delete_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_tag_path` (`tag_path`(100)) USING BTREE,
KEY `idx_resource_code` (`resource_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='标签资源关联表';
-- ----------------------------
-- Records of t_tag_tree_team
-- ----------------------------

View File

@@ -50,7 +50,43 @@ ALTER TABLE t_sys_log ADD extra varchar(5000) NULL;
ALTER TABLE t_sys_log MODIFY COLUMN resp text NULL;
-- rdp相关
ALTER TABLE `t_machine` ADD COLUMN `protocol` tinyint(2) NULL COMMENT '机器类型 1、SSH 2、RDP' AFTER `name`;
ALTER TABLE `t_machine` ADD COLUMN `protocol` tinyint(2) NULL COMMENT '协议 1、SSH 2、RDP' AFTER `name`;
update `t_machine` set `protocol` = 1 where `protocol` is NULL;
delete from `t_sys_config` where `key` = 'MachineConfig';
INSERT INTO `t_sys_config` (`id`, `name`, `key`, `params`, `value`, `remark`, `permission`, `create_time`, `creator_id`, `creator`, `update_time`, `modifier_id`, `modifier`, `is_deleted`, `delete_time`) VALUES (12, '机器相关配置', 'MachineConfig', '[{\"name\":\"终端回放存储路径\",\"model\":\"terminalRecPath\",\"placeholder\":\"终端回放存储路径\"},{\"name\":\"uploadMaxFileSize\",\"model\":\"uploadMaxFileSize\",\"placeholder\":\"允许上传的最大文件大小(1MB、2GB等)\"},{\"model\":\"termOpSaveDays\",\"name\":\"终端记录保存时间\",\"placeholder\":\"终端记录保存时间(单位天)\"},{\"model\":\"guacdHost\",\"name\":\"guacd服务ip\",\"placeholder\":\"guacd服务ip默认 127.0.0.1\"},{\"name\":\"guacd服务端口\",\"model\":\"guacdPort\",\"placeholder\":\"guacd服务端口默认 4822\"},{\"model\":\"guacdFilePath\",\"name\":\"guacd服务文件存储位置\",\"placeholder\":\"guacd服务文件存储位置用于挂载RDP文件夹\"},{\"name\":\"guacd服务记录存储位置\",\"model\":\"guacdRecPath\",\"placeholder\":\"guacd服务记录存储位置用于记录rdp操作记录\"}]', '{\"terminalRecPath\":\"./rec\",\"uploadMaxFileSize\":\"1000MB\",\"termOpSaveDays\":\"30\",\"guacdHost\":\"127.0.0.1\",\"guacdPort\":\"4822\",\"guacdFilePath\":\"/Users/leozy/Desktop/developer/service/guacd/rdp-file\",\"guacdRecPath\":\"/Users/leozy/Desktop/developer/service/guacd/rdp-rec\"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-04-04 13:11:52', 12, 'liuzongyang', 0, NULL);
INSERT INTO t_sys_config ( name, `key`, params, value, remark, permission, create_time, creator_id, creator, update_time, modifier_id, modifier, is_deleted, delete_time) VALUES('机器相关配置', 'MachineConfig', '[{"name":"终端回放存储路径","model":"terminalRecPath","placeholder":"终端回放存储路径"},{"name":"uploadMaxFileSize","model":"uploadMaxFileSize","placeholder":"允许上传的最大文件大小(1MB、2GB等)"},{"model":"termOpSaveDays","name":"终端记录保存时间","placeholder":"终端记录保存时间(单位天)"},{"model":"guacdHost","name":"guacd服务ip","placeholder":"guacd服务ip默认 127.0.0.1","required":false},{"name":"guacd服务端口","model":"guacdPort","placeholder":"guacd服务端口默认 4822","required":false},{"model":"guacdFilePath","name":"guacd服务文件存储位置","placeholder":"guacd服务文件存储位置用于挂载RDP文件夹"},{"name":"guacd服务记录存储位置","model":"guacdRecPath","placeholder":"guacd服务记录存储位置用于记录rdp操作记录"}]', '{"terminalRecPath":"./rec","uploadMaxFileSize":"1000MB","termOpSaveDays":"30","guacdHost":"","guacdPort":"","guacdFilePath":"./guacd/rdp-file","guacdRecPath":"./guacd/rdp-rec"}', '机器相关配置,如终端回放路径等', 'all', '2023-07-13 16:26:44', 1, 'admin', '2024-04-06 12:25:03', 1, 'admin', 0, NULL);
BEGIN;
INSERT
INTO
t_tag_tree (pid,
code,
code_path,
type,
name,
create_time,
creator_id,
creator,
update_time,
modifier_id,
modifier,
is_deleted)
select
tag_id,
resource_code,
CONCAT(tag_path , resource_code, '/'),
resource_type,
resource_code,
DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'),
1,
'admin',
DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s'),
1,
'admin',
0
from
t_tag_resource
WHERE
is_deleted = 0;
DROP TABLE t_tag_tree;
COMMIT;