mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-02 15:30:25 +08:00
refactor: 标签资源重构
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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' }),
|
||||
};
|
||||
|
||||
@@ -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位大小写字母、数字、下划线',
|
||||
};
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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', '实例名'),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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, '有结果'),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"` // 端口号
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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"], "")
|
||||
|
||||
@@ -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地址
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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("请先移除该标签关联的资源")
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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"))
|
||||
}
|
||||
|
||||
@@ -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...)
|
||||
}
|
||||
@@ -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...)
|
||||
}
|
||||
|
||||
@@ -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[:])
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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":"允许上传的最大文件大小(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);
|
||||
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
|
||||
-- ----------------------------
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user