mirror of
				https://gitee.com/dromara/mayfly-go
				synced 2025-11-04 08:20:25 +08:00 
			
		
		
		
	refactor: 使用泛型重构参数绑定等
This commit is contained in:
		@@ -31,7 +31,7 @@
 | 
			
		||||
 | 
			
		||||
## 前言
 | 
			
		||||
 | 
			
		||||
Web版 **统一管理操作平台**,集成了对Linux系统的全面操作支持(包括终端管理[终端回放、命令过滤]、文件管理、脚本执行、进程监控及计划任务设置),同时提供了多种数据库(如 MySQL、PostgreSQL、Oracle、SQL Server、达梦、高斯、SQLite 等)的数据操作、数据同步与数据迁移功能。此外,还支持 Redis(单机、哨兵、集群模式)以及 MongoDB 的操作管理,并结合工单流程审批功能,为企业提供一站式的运维与管理解决方案。
 | 
			
		||||
Web 版 **统一管理操作平台**,集成了对 Linux 系统的全面操作支持(包括终端管理[终端回放、命令过滤]、文件管理、脚本执行、进程监控及计划任务设置),同时提供了多种数据库(如 MySQL、PostgreSQL、Oracle、SQL Server、达梦、高斯、SQLite 等)的数据操作、数据同步与数据迁移功能。此外,还支持 Redis(单机、哨兵、集群模式)、 MongoDB 、Es 的操作管理,并结合工单流程审批功能,为企业提供一站式的运维与管理解决方案。
 | 
			
		||||
 | 
			
		||||
## 开发语言与主要框架
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
 | 
			
		||||
## Preface
 | 
			
		||||
 | 
			
		||||
Web-based **Unified Management and Operation Platform**, integrating comprehensive operation support for Linux systems (including terminal management [terminal playback, command filtering], file management, script execution, process monitoring, and cronjob settings). It also provides data operation, data synchronization, and data migration for multiple databases (such as MySQL, PostgreSQL, Oracle, SQL Server, Dameng, Gauss, SQLite, etc.). Additionally, it supports Redis operations (standalone, sentinel, and cluster modes) and MongoDB management, combined with work order process approval functionality to offer enterprises an all-in-one solution for operations and management.
 | 
			
		||||
Web-based **Unified Management and Operation Platform**, integrating comprehensive operation support for Linux systems (including terminal management [terminal playback, command filtering], file management, script execution, process monitoring, and cronjob settings). It also provides data operation, data synchronization, and data migration for multiple databases (such as MySQL, PostgreSQL, Oracle, SQL Server, Dameng, Gauss, SQLite, etc.). Additionally, it supports Redis operations (standalone, sentinel, and cluster modes) and MongoDB、Es management, combined with work order process approval functionality to offer enterprises an all-in-one solution for operations and management.
 | 
			
		||||
 | 
			
		||||
## Development languages and major frameworks
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -24,7 +24,7 @@
 | 
			
		||||
        "crypto-js": "^4.2.0",
 | 
			
		||||
        "dayjs": "^1.11.13",
 | 
			
		||||
        "echarts": "^5.6.0",
 | 
			
		||||
        "element-plus": "^2.9.10",
 | 
			
		||||
        "element-plus": "^2.9.11",
 | 
			
		||||
        "js-base64": "^3.7.7",
 | 
			
		||||
        "jsencrypt": "^3.3.2",
 | 
			
		||||
        "mitt": "^3.0.1",
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,7 @@ export const ResourceTypeEnum = {
 | 
			
		||||
    Redis: EnumValue.of(3, 'redis').setExtra({ icon: 'icon redis/redis', iconColor: 'var(--el-color-danger)' }).tagTypeInfo(),
 | 
			
		||||
    Mongo: EnumValue.of(4, 'mongo').setExtra({ icon: 'icon mongo/mongo', iconColor: 'var(--el-color-success)' }).tagTypeDanger(),
 | 
			
		||||
    AuthCert: EnumValue.of(5, '授权凭证').setExtra({ icon: 'Ticket', iconColor: 'var(--el-color-success)' }),
 | 
			
		||||
    Es: EnumValue.of(6, 'ES实例').setExtra({ icon: 'Coin', iconColor: 'var(--el-color-warning)' }).tagTypeWarning(),
 | 
			
		||||
    Es: EnumValue.of(6, 'ES实例').setExtra({ icon: 'icon es/es-color', iconColor: 'var(--el-color-warning)' }).tagTypeWarning(),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 标签关联的资源类型
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <el-tree-select
 | 
			
		||||
        v-bind="$attrs"
 | 
			
		||||
        v-model="state.selectTags"
 | 
			
		||||
        @change="changeTag"
 | 
			
		||||
        v-model="modelValue"
 | 
			
		||||
        :data="tags"
 | 
			
		||||
        :placeholder="$t('tag.selectTagPlaceholder')"
 | 
			
		||||
        :default-expanded-keys="defaultExpandedKeys"
 | 
			
		||||
@@ -35,44 +34,33 @@ import { tagApi } from '../tag/api';
 | 
			
		||||
import { TagResourceTypeEnum } from '@/common/commonEnum';
 | 
			
		||||
import EnumValue from '@/common/Enum';
 | 
			
		||||
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['update:modelValue', 'changeTag', 'input']);
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    selectTags: {
 | 
			
		||||
        type: [Array<any>, Object],
 | 
			
		||||
    },
 | 
			
		||||
    tagType: {
 | 
			
		||||
        type: Number,
 | 
			
		||||
        default: TagResourceTypeEnum.Tag.value,
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const modelValue = defineModel<Array<any> | Object>('modelValue');
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    tags: [],
 | 
			
		||||
    // 单选则为codePath,多选为codePath数组
 | 
			
		||||
    selectTags: [] as any,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { tags } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
const defaultExpandedKeys = computed(() => {
 | 
			
		||||
    if (Array.isArray(state.selectTags)) {
 | 
			
		||||
        // 如果 state.selectTags 是数组,直接返回
 | 
			
		||||
        return state.selectTags;
 | 
			
		||||
    if (Array.isArray(modelValue.value)) {
 | 
			
		||||
        // 如果 modelValue 是数组,直接返回
 | 
			
		||||
        return modelValue.value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // 如果 state.selectTags 不是数组,转换为包含 state.selectTags 的数组
 | 
			
		||||
    return [state.selectTags];
 | 
			
		||||
    // 如果 modelValue 不是数组,转换为包含 state.selectTags 的数组
 | 
			
		||||
    return [modelValue.value];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
    state.selectTags = props.selectTags;
 | 
			
		||||
    state.tags = await tagApi.getTagTrees.request({ type: props.tagType });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const changeTag = () => {
 | 
			
		||||
    emit('changeTag', state.selectTags);
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss"></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
            :title="title"
 | 
			
		||||
            v-model="dialogVisible"
 | 
			
		||||
            @open="open"
 | 
			
		||||
            :before-close="cancel"
 | 
			
		||||
            :before-close="onCancel"
 | 
			
		||||
            :close-on-click-modal="false"
 | 
			
		||||
            :destroy-on-close="true"
 | 
			
		||||
            width="38%"
 | 
			
		||||
@@ -51,7 +51,7 @@
 | 
			
		||||
                        :loading="state.loadingDbNames"
 | 
			
		||||
                    >
 | 
			
		||||
                        <template #header>
 | 
			
		||||
                            <el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="handleCheckAll">
 | 
			
		||||
                            <el-checkbox v-model="checkAllDbNames" :indeterminate="indeterminateDbNames" @change="onCheckAll">
 | 
			
		||||
                                {{ $t('db.allSelect') }}
 | 
			
		||||
                            </el-checkbox>
 | 
			
		||||
                        </template>
 | 
			
		||||
@@ -65,8 +65,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
    </div>
 | 
			
		||||
@@ -198,7 +198,7 @@ const open = async () => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(dbForm);
 | 
			
		||||
    emit('confirm', state.form);
 | 
			
		||||
};
 | 
			
		||||
@@ -209,7 +209,7 @@ const resetInputDb = () => {
 | 
			
		||||
    state.instances = [];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
@@ -243,7 +243,7 @@ watch(allDatabases, (val: string[]) => {
 | 
			
		||||
    state.dbNamesFiltered = val.map((dbName: string) => dbName);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const handleCheckAll = (val: CheckboxValueType) => {
 | 
			
		||||
const onCheckAll = (val: CheckboxValueType) => {
 | 
			
		||||
    const otherSelected = state.dbNamesSelected.filter((dbName: string) => {
 | 
			
		||||
        return !state.dbNamesFiltered.includes(dbName);
 | 
			
		||||
    });
 | 
			
		||||
 
 | 
			
		||||
@@ -8,17 +8,8 @@
 | 
			
		||||
            <el-form :model="form" ref="dbFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-divider content-position="left">{{ $t('common.basic') }}</el-divider>
 | 
			
		||||
 | 
			
		||||
                <el-form-item ref="tagSelectRef" prop="tagCodePaths" :label="$t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select
 | 
			
		||||
                        multiple
 | 
			
		||||
                        @change-tag="
 | 
			
		||||
                            (paths: any) => {
 | 
			
		||||
                                form.tagCodePaths = paths;
 | 
			
		||||
                                tagSelectRef.validate();
 | 
			
		||||
                            }
 | 
			
		||||
                        "
 | 
			
		||||
                        :select-tags="form.tagCodePaths"
 | 
			
		||||
                    />
 | 
			
		||||
                <el-form-item prop="tagCodePaths" :label="$t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select multiple v-model="form.tagCodePaths" />
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="name" :label="$t('common.name')" required>
 | 
			
		||||
@@ -114,7 +105,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { computed, reactive, ref, toRefs, watchEffect } from 'vue';
 | 
			
		||||
import { computed, reactive, toRefs, useTemplateRef, watchEffect } from 'vue';
 | 
			
		||||
import { dbApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
 | 
			
		||||
@@ -153,8 +144,7 @@ const rules = {
 | 
			
		||||
    host: [Rules.requiredInput('Host:Port')],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const dbFormRef: any = ref(null);
 | 
			
		||||
const tagSelectRef: any = ref(null);
 | 
			
		||||
const dbFormRef: any = useTemplateRef('dbFormRef');
 | 
			
		||||
 | 
			
		||||
const DefaultForm = {
 | 
			
		||||
    id: null,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,15 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="onCancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="title" :back="cancel" />
 | 
			
		||||
                <DrawerHeader :header="title" :back="onCancel" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form :model="form" ref="dbForm" :rules="rules" label-width="auto">
 | 
			
		||||
            <el-form :model="form" ref="dbFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-divider content-position="left">{{ t('common.basic') }}</el-divider>
 | 
			
		||||
 | 
			
		||||
                <el-form-item ref="tagSelectRef" prop="tagCodePaths" :label="t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select
 | 
			
		||||
                        multiple
 | 
			
		||||
                        @change-tag="
 | 
			
		||||
                            (paths: any) => {
 | 
			
		||||
                                form.tagCodePaths = paths;
 | 
			
		||||
                                tagSelectRef.validate();
 | 
			
		||||
                            }
 | 
			
		||||
                        "
 | 
			
		||||
                        :select-tags="form.tagCodePaths"
 | 
			
		||||
                    />
 | 
			
		||||
                <el-form-item prop="tagCodePaths" :label="t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select multiple v-model="form.tagCodePaths" />
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="name" :label="t('common.name')" required>
 | 
			
		||||
@@ -50,7 +41,7 @@
 | 
			
		||||
                        :resource-code="form.code"
 | 
			
		||||
                        :resource-type="TagResourceTypeEnum.EsInstance.value"
 | 
			
		||||
                        :test-conn-btn-loading="testConnBtnLoading"
 | 
			
		||||
                        @test-conn="testConn"
 | 
			
		||||
                        @test-conn="onTestConn"
 | 
			
		||||
                        :disable-ciphertext-type="[AuthCertCiphertextTypeEnum.PrivateKey.value]"
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
@@ -63,16 +54,16 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <el-button @click="testConn(null)" type="success" v-if="form.authCerts?.length <= 0">{{ t('ac.testConn') }}</el-button>
 | 
			
		||||
                <el-button @click="cancel()">{{ t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ t('common.confirm') }}</el-button>
 | 
			
		||||
                <el-button @click="onTestConn(null)" type="success" v-if="form.authCerts?.length <= 0">{{ t('ac.testConn') }}</el-button>
 | 
			
		||||
                <el-button @click="onCancel()">{{ t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ t('common.confirm') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { reactive, ref, toRefs, watchEffect } from 'vue';
 | 
			
		||||
import { reactive, toRefs, useTemplateRef, watchEffect } from 'vue';
 | 
			
		||||
import { esApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import SshTunnelSelect from '../component/SshTunnelSelect.vue';
 | 
			
		||||
@@ -88,9 +79,6 @@ import { Rules } from '@/common/rule';
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    visible: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
    },
 | 
			
		||||
    data: {
 | 
			
		||||
        type: [Boolean, Object],
 | 
			
		||||
    },
 | 
			
		||||
@@ -99,6 +87,8 @@ const props = defineProps({
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const dialogVisible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['update:visible', 'cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
@@ -109,8 +99,7 @@ const rules = {
 | 
			
		||||
    host: [Rules.requiredInput('Host:Port')],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const dbForm: any = ref(null);
 | 
			
		||||
const tagSelectRef: any = ref(null);
 | 
			
		||||
const dbFormRef: any = useTemplateRef('dbFormRef');
 | 
			
		||||
 | 
			
		||||
const DefaultForm = {
 | 
			
		||||
    id: null,
 | 
			
		||||
@@ -126,19 +115,17 @@ const DefaultForm = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    dialogVisible: false,
 | 
			
		||||
    form: DefaultForm,
 | 
			
		||||
    submitForm: {} as any,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { dialogVisible, form, submitForm } = toRefs(state);
 | 
			
		||||
const { form, submitForm } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
const { isFetching: saveBtnLoading, execute: saveInstanceExec, data: saveInstanceRes } = esApi.saveInstance.useApi(submitForm);
 | 
			
		||||
const { isFetching: testConnBtnLoading, execute: testConnExec, data: testConnRes } = esApi.testConn.useApi<any>(submitForm);
 | 
			
		||||
 | 
			
		||||
watchEffect(() => {
 | 
			
		||||
    state.dialogVisible = props.visible;
 | 
			
		||||
    if (!state.dialogVisible) {
 | 
			
		||||
    if (!dialogVisible.value) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const dbInst: any = props.data;
 | 
			
		||||
@@ -161,8 +148,8 @@ const getReqForm = async () => {
 | 
			
		||||
    return reqForm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const testConn = async (authCert: any) => {
 | 
			
		||||
    await useI18nFormValidate(dbForm);
 | 
			
		||||
const onTestConn = async (authCert: any) => {
 | 
			
		||||
    await useI18nFormValidate(dbFormRef);
 | 
			
		||||
    state.submitForm = await getReqForm();
 | 
			
		||||
    if (authCert) {
 | 
			
		||||
        state.submitForm.authCerts = [authCert];
 | 
			
		||||
@@ -172,23 +159,23 @@ const testConn = async (authCert: any) => {
 | 
			
		||||
    ElMessage.success(t('es.connSuccess'));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    if (!state.form.version) {
 | 
			
		||||
        ElMessage.warning(t('es.shouldTestConn'));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await useI18nFormValidate(dbForm);
 | 
			
		||||
    await useI18nFormValidate(dbFormRef);
 | 
			
		||||
    state.submitForm = await getReqForm();
 | 
			
		||||
    await saveInstanceExec();
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    state.form.id = saveInstanceRes as any;
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
    emit('update:visible', false);
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,23 +1,14 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="onCancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="title" :back="cancel" />
 | 
			
		||||
                <DrawerHeader :header="title" :back="onCancel" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form :model="form" ref="machineForm" :rules="rules" label-width="auto">
 | 
			
		||||
            <el-form :model="form" ref="machineFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-divider content-position="left">{{ $t('common.basic') }}</el-divider>
 | 
			
		||||
                <el-form-item ref="tagSelectRef" prop="tagCodePaths" :label="$t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select
 | 
			
		||||
                        multiple
 | 
			
		||||
                        @change-tag="
 | 
			
		||||
                            (paths) => {
 | 
			
		||||
                                form.tagCodePaths = paths;
 | 
			
		||||
                                tagSelectRef.validate();
 | 
			
		||||
                            }
 | 
			
		||||
                        "
 | 
			
		||||
                        :select-tags="form.tagCodePaths"
 | 
			
		||||
                    />
 | 
			
		||||
                <el-form-item prop="tagCodePaths" :label="$t('tag.relateTag')">
 | 
			
		||||
                    <tag-tree-select multiple v-model="form.tagCodePaths" />
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
                <el-form-item prop="name" :label="$t('common.name')" required>
 | 
			
		||||
                    <el-input v-model.trim="form.name" auto-complete="off"></el-input>
 | 
			
		||||
@@ -48,7 +39,7 @@
 | 
			
		||||
                        :resource-code="form.code"
 | 
			
		||||
                        :resource-type="TagResourceTypeEnum.Machine.value"
 | 
			
		||||
                        :test-conn-btn-loading="testConnBtnLoading"
 | 
			
		||||
                        @test-conn="testConn"
 | 
			
		||||
                        @test-conn="onTestConn"
 | 
			
		||||
                    />
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
@@ -71,8 +62,8 @@
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div>
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
@@ -80,7 +71,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { reactive, ref, toRefs, watchEffect } from 'vue';
 | 
			
		||||
import { reactive, toRefs, useTemplateRef, watchEffect } from 'vue';
 | 
			
		||||
import { machineApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import TagTreeSelect from '../component/TagTreeSelect.vue';
 | 
			
		||||
@@ -119,8 +110,7 @@ const rules = {
 | 
			
		||||
    ip: [Rules.requiredInput('machine.ipAndPort')],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const machineForm: any = ref(null);
 | 
			
		||||
const tagSelectRef: any = ref(null);
 | 
			
		||||
const machineFormRef: any = useTemplateRef('machineFormRef');
 | 
			
		||||
 | 
			
		||||
const defaultForm = {
 | 
			
		||||
    id: null,
 | 
			
		||||
@@ -166,8 +156,8 @@ watchEffect(() => {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const testConn = async (authCert: any) => {
 | 
			
		||||
    await useI18nFormValidate(machineForm);
 | 
			
		||||
const onTestConn = async (authCert: any) => {
 | 
			
		||||
    await useI18nFormValidate(machineFormRef);
 | 
			
		||||
 | 
			
		||||
    state.submitForm = getReqForm();
 | 
			
		||||
    state.submitForm.authCerts = [authCert];
 | 
			
		||||
@@ -175,8 +165,8 @@ const testConn = async (authCert: any) => {
 | 
			
		||||
    ElMessage.success(t('machine.connSuccess'));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(machineForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(machineFormRef);
 | 
			
		||||
 | 
			
		||||
    if (state.form.authCerts.length == 0) {
 | 
			
		||||
        ElMessage.error(t('machine.noAcErrMsg'));
 | 
			
		||||
@@ -187,7 +177,7 @@ const btnOk = async () => {
 | 
			
		||||
    await saveMachineExec();
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    emit('val-change', submitForm);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getReqForm = () => {
 | 
			
		||||
@@ -208,7 +198,7 @@ const handleChangeProtocol = (val: any) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,12 @@
 | 
			
		||||
            <el-table-column :label="$t('common.operation')" min-width="120px">
 | 
			
		||||
                <template #header>
 | 
			
		||||
                    <el-text tag="b">{{ $t('common.operation') }}</el-text>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" class="ml-1" type="primary" circle size="small" icon="Plus" @click="openFormDialog(false)"> </el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" class="ml-1" type="primary" circle size="small" icon="Plus" @click="onOpenFormDialog(false)">
 | 
			
		||||
                    </el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
                <template #default="scope">
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" @click="openFormDialog(scope.row)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:del'" @click="deleteCmdConf(scope.row)" type="danger" link>{{ $t('common.delete') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" @click="onOpenFormDialog(scope.row)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:del'" @click="onDeleteCmdConf(scope.row)" type="danger" link>{{ $t('common.delete') }}</el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
            </el-table-column>
 | 
			
		||||
        </el-table>
 | 
			
		||||
@@ -38,7 +39,7 @@
 | 
			
		||||
            :close-on-click-modal="false"
 | 
			
		||||
        >
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="$t('machine.cmdConfig')" :back="cancelEdit" />
 | 
			
		||||
                <DrawerHeader :header="$t('machine.cmdConfig')" :back="onCancelEdit" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form ref="formRef" :model="state.form" :rules="rules" label-width="auto">
 | 
			
		||||
@@ -46,7 +47,7 @@
 | 
			
		||||
                    <el-input v-model="form.name"></el-input>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
                <el-form-item prop="cmds" :label="$t('machine.filterCmds')" required>
 | 
			
		||||
                <el-form-item prop="cmds" :label="$t('machine.filterCmds')">
 | 
			
		||||
                    <el-row>
 | 
			
		||||
                        <el-tag
 | 
			
		||||
                            class="ml-0.5 mt-0.5"
 | 
			
		||||
@@ -54,7 +55,7 @@
 | 
			
		||||
                            :key="tag"
 | 
			
		||||
                            closable
 | 
			
		||||
                            :disable-transitions="false"
 | 
			
		||||
                            @close="handleCmdClose(tag)"
 | 
			
		||||
                            @close="onCmdClose(tag)"
 | 
			
		||||
                            type="danger"
 | 
			
		||||
                        >
 | 
			
		||||
                            {{ tag }}
 | 
			
		||||
@@ -65,11 +66,11 @@
 | 
			
		||||
                            v-model="state.cmdInputValue"
 | 
			
		||||
                            class="mt-0.5"
 | 
			
		||||
                            size="small"
 | 
			
		||||
                            @keyup.enter="handleCmdInputConfirm"
 | 
			
		||||
                            @blur="handleCmdInputConfirm"
 | 
			
		||||
                            @keyup.enter="onCmdInputConfirm"
 | 
			
		||||
                            @blur="onCmdInputConfirm"
 | 
			
		||||
                            :placeholder="$t('machine.cmdPlaceholder')"
 | 
			
		||||
                        />
 | 
			
		||||
                        <el-button v-else class="ml-0.5 mt-0.5" size="small" @click="showCmdInput"> + {{ $t('machine.newCmd') }} </el-button>
 | 
			
		||||
                        <el-button v-else class="ml-0.5 mt-0.5" size="small" @click="onShowCmdInput"> + {{ $t('machine.newCmd') }} </el-button>
 | 
			
		||||
                    </el-row>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
 | 
			
		||||
@@ -87,8 +88,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button :loading="submiting" @click="cancelEdit">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" type="primary" :loading="submiting" @click="submitForm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button :loading="submiting" @click="onCancelEdit">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'cmdconf:save'" type="primary" :loading="submiting" @click="onSubmitForm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
@@ -143,18 +144,18 @@ const getCmdConfs = async () => {
 | 
			
		||||
    state.cmdConfs = await cmdConfApi.list.request();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleCmdClose = (tag: string) => {
 | 
			
		||||
const onCmdClose = (tag: string) => {
 | 
			
		||||
    state.form.cmds.splice(state.form.cmds.indexOf(tag), 1);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showCmdInput = () => {
 | 
			
		||||
const onShowCmdInput = () => {
 | 
			
		||||
    state.inputCmdVisible = true;
 | 
			
		||||
    nextTick(() => {
 | 
			
		||||
        cmdInputRef.value!.input!.focus();
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleCmdInputConfirm = () => {
 | 
			
		||||
const onCmdInputConfirm = () => {
 | 
			
		||||
    if (state.cmdInputValue) {
 | 
			
		||||
        state.form.cmds.push(state.cmdInputValue);
 | 
			
		||||
    }
 | 
			
		||||
@@ -162,24 +163,25 @@ const handleCmdInputConfirm = () => {
 | 
			
		||||
    state.cmdInputValue = '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const openFormDialog = (data: any) => {
 | 
			
		||||
const onOpenFormDialog = (data: any) => {
 | 
			
		||||
    if (!data) {
 | 
			
		||||
        state.form = { ...DefaultForm };
 | 
			
		||||
    } else {
 | 
			
		||||
        state.form = deepClone(data);
 | 
			
		||||
        state.form.codePaths = data.tags?.map((tag: any) => tag.codePath);
 | 
			
		||||
        state.form.cmds = data.cmds || [];
 | 
			
		||||
    }
 | 
			
		||||
    state.dialogVisible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteCmdConf = async (data: any) => {
 | 
			
		||||
const onDeleteCmdConf = async (data: any) => {
 | 
			
		||||
    await useI18nDeleteConfirm(data.name);
 | 
			
		||||
    await cmdConfApi.delete.request({ id: data.id });
 | 
			
		||||
    useI18nDeleteSuccessMsg();
 | 
			
		||||
    getCmdConfs();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancelEdit = () => {
 | 
			
		||||
const onCancelEdit = () => {
 | 
			
		||||
    state.dialogVisible = false;
 | 
			
		||||
    // 取消表单的校验
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
@@ -188,14 +190,14 @@ const cancelEdit = () => {
 | 
			
		||||
    }, 200);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const submitForm = async () => {
 | 
			
		||||
const onSubmitForm = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
        await useI18nFormValidate(formRef);
 | 
			
		||||
        state.submiting = true;
 | 
			
		||||
        await cmdConfApi.save.request(state.form);
 | 
			
		||||
        useI18nSaveSuccessMsg();
 | 
			
		||||
 | 
			
		||||
        cancelEdit();
 | 
			
		||||
        onCancelEdit();
 | 
			
		||||
        getCmdConfs();
 | 
			
		||||
    } finally {
 | 
			
		||||
        state.submiting = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-dialog :title="title" v-model="dialogVisible" :before-close="cancel" :close-on-click-modal="false" width="38%" :destroy-on-close="true">
 | 
			
		||||
            <el-form :model="form" ref="mongoForm" :rules="rules" label-width="auto">
 | 
			
		||||
        <el-dialog :title="title" v-model="dialogVisible" :before-close="onCancel" :close-on-click-modal="false" width="38%" :destroy-on-close="true">
 | 
			
		||||
            <el-form :model="form" ref="mongoFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-tabs v-model="tabActiveName">
 | 
			
		||||
                    <el-tab-pane :label="$t('common.basic')" name="basic">
 | 
			
		||||
                        <el-form-item ref="tagSelectRef" prop="tagCodePaths" :label="$t('tag.relateTag')" required>
 | 
			
		||||
                            <tag-tree-select
 | 
			
		||||
                                @change-tag="
 | 
			
		||||
                                    (tagCodePaths) => {
 | 
			
		||||
                                        form.tagCodePaths = tagCodePaths;
 | 
			
		||||
                                        tagSelectRef.validate();
 | 
			
		||||
                                    }
 | 
			
		||||
                                "
 | 
			
		||||
                                multiple
 | 
			
		||||
                                :select-tags="form.tagCodePaths"
 | 
			
		||||
                            />
 | 
			
		||||
                        <el-form-item prop="tagCodePaths" :label="$t('tag.relateTag')" required>
 | 
			
		||||
                            <tag-tree-select multiple v-model="form.tagCodePaths" />
 | 
			
		||||
                        </el-form-item>
 | 
			
		||||
 | 
			
		||||
                        <el-form-item prop="name" :label="$t('common.name')" required>
 | 
			
		||||
@@ -41,9 +32,9 @@
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="testConn" :loading="testConnBtnLoading" type="success">{{ $t('ac.testConn') }}</el-button>
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onTestConn" :loading="testConnBtnLoading" type="success">{{ $t('ac.testConn') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
@@ -51,7 +42,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { toRefs, reactive, ref, watchEffect } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watchEffect, useTemplateRef } from 'vue';
 | 
			
		||||
import { mongoApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import TagTreeSelect from '../component/TagTreeSelect.vue';
 | 
			
		||||
@@ -63,9 +54,6 @@ import { Rules } from '@/common/rule';
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    visible: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
    },
 | 
			
		||||
    mongo: {
 | 
			
		||||
        type: [Boolean, Object],
 | 
			
		||||
    },
 | 
			
		||||
@@ -74,8 +62,10 @@ const props = defineProps({
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const dialogVisible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['update:visible', 'cancel', 'val-change']);
 | 
			
		||||
const emit = defineEmits(['cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
const rules = {
 | 
			
		||||
    tagCodePaths: [Rules.requiredSelect('tag.relateTag')],
 | 
			
		||||
@@ -83,11 +73,9 @@ const rules = {
 | 
			
		||||
    uri: [Rules.requiredInput('mongo.connUrl')],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const mongoForm: any = ref(null);
 | 
			
		||||
const tagSelectRef: any = ref(null);
 | 
			
		||||
const mongoFormRef: any = useTemplateRef('mongoFormRef');
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    dialogVisible: false,
 | 
			
		||||
    tabActiveName: 'basic',
 | 
			
		||||
    form: {
 | 
			
		||||
        id: null,
 | 
			
		||||
@@ -100,14 +88,13 @@ const state = reactive({
 | 
			
		||||
    submitForm: {},
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { dialogVisible, tabActiveName, form, submitForm } = toRefs(state);
 | 
			
		||||
const { tabActiveName, form, submitForm } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = mongoApi.testConn.useApi(submitForm);
 | 
			
		||||
const { isFetching: saveBtnLoading, execute: saveMongoExec } = mongoApi.saveMongo.useApi(submitForm);
 | 
			
		||||
 | 
			
		||||
watchEffect(() => {
 | 
			
		||||
    state.dialogVisible = props.visible;
 | 
			
		||||
    if (!state.dialogVisible) {
 | 
			
		||||
    if (!dialogVisible.value) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    state.tabActiveName = 'basic';
 | 
			
		||||
@@ -116,7 +103,7 @@ watchEffect(() => {
 | 
			
		||||
        state.form = { ...mongo };
 | 
			
		||||
        state.form.tagCodePaths = mongo.tags.map((t: any) => t.codePath);
 | 
			
		||||
    } else {
 | 
			
		||||
        state.form = { db: 0 } as any;
 | 
			
		||||
        state.form = { db: 0, tagCodePaths: [] } as any;
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@@ -128,24 +115,24 @@ const getReqForm = () => {
 | 
			
		||||
    return reqForm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const testConn = async () => {
 | 
			
		||||
    await useI18nFormValidate(mongoForm);
 | 
			
		||||
const onTestConn = async () => {
 | 
			
		||||
    await useI18nFormValidate(mongoFormRef);
 | 
			
		||||
    state.submitForm = getReqForm();
 | 
			
		||||
    await testConnExec();
 | 
			
		||||
    ElMessage.success(t('ac.connSuccess'));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(mongoForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(mongoFormRef);
 | 
			
		||||
    state.submitForm = getReqForm();
 | 
			
		||||
    await saveMongoExec();
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
    emit('update:visible', false);
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
            lazy
 | 
			
		||||
        >
 | 
			
		||||
            <template #tableHeader>
 | 
			
		||||
                <el-button type="primary" icon="plus" @click="editMongo(true)" plain>{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button type="primary" icon="plus" @click="editMongo(false)" plain>{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button type="danger" icon="delete" :disabled="selectionData.length < 1" @click="deleteMongo" plain>{{ $t('common.delete') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,22 +1,13 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="cancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
        <el-drawer :title="title" v-model="dialogVisible" :before-close="onCancel" :destroy-on-close="true" :close-on-click-modal="false" size="40%">
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="title" :back="cancel" />
 | 
			
		||||
                <DrawerHeader :header="title" :back="onCancel" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form :model="form" ref="redisForm" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-form-item ref="tagSelectRef" prop="tagCodePaths" :label="$t('tag.relateTag')" required>
 | 
			
		||||
                    <tag-tree-select
 | 
			
		||||
                        @change-tag="
 | 
			
		||||
                            (tagCodePaths) => {
 | 
			
		||||
                                form.tagCodePaths = tagCodePaths;
 | 
			
		||||
                                tagSelectRef.validate();
 | 
			
		||||
                            }
 | 
			
		||||
                        "
 | 
			
		||||
                        multiple
 | 
			
		||||
                        :select-tags="form.tagCodePaths"
 | 
			
		||||
                    />
 | 
			
		||||
            <el-form :model="form" ref="redisFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-form-item prop="tagCodePaths" :label="$t('tag.relateTag')" required>
 | 
			
		||||
                    <tag-tree-select multiple v-model="form.tagCodePaths" />
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
                <el-form-item prop="name" :label="$t('common.name')" required>
 | 
			
		||||
                    <el-input v-model.trim="form.name" auto-complete="off"></el-input>
 | 
			
		||||
@@ -55,9 +46,9 @@
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="testConn" :loading="testConnBtnLoading" type="success">{{ $t('ac.testConn') }}</el-button>
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onTestConn" :loading="testConnBtnLoading" type="success">{{ $t('ac.testConn') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
@@ -65,7 +56,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { toRefs, reactive, ref, watch } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watch, useTemplateRef } from 'vue';
 | 
			
		||||
import { redisApi } from './api';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import TagTreeSelect from '../component/TagTreeSelect.vue';
 | 
			
		||||
@@ -78,9 +69,6 @@ import { Rules } from '@/common/rule';
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
    visible: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
    },
 | 
			
		||||
    redis: {
 | 
			
		||||
        type: [Boolean, Object],
 | 
			
		||||
    },
 | 
			
		||||
@@ -89,7 +77,9 @@ const props = defineProps({
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['update:visible', 'val-change', 'cancel']);
 | 
			
		||||
const dialogVisible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['val-change', 'cancel']);
 | 
			
		||||
 | 
			
		||||
const rules = {
 | 
			
		||||
    tagCodePaths: [Rules.requiredSelect('tag.relateTag')],
 | 
			
		||||
@@ -99,12 +89,9 @@ const rules = {
 | 
			
		||||
    mode: [Rules.requiredSelect('mode')],
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const redisForm: any = ref(null);
 | 
			
		||||
const tagSelectRef: any = ref(null);
 | 
			
		||||
const redisFormRef: any = useTemplateRef('redisFormRef');
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    dialogVisible: false,
 | 
			
		||||
    tabActiveName: 'basic',
 | 
			
		||||
    form: {
 | 
			
		||||
        id: null,
 | 
			
		||||
        code: '',
 | 
			
		||||
@@ -124,19 +111,16 @@ const state = reactive({
 | 
			
		||||
    pwd: '',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const { dialogVisible, tabActiveName, form, submitForm, dbList } = toRefs(state);
 | 
			
		||||
const { form, submitForm, dbList } = toRefs(state);
 | 
			
		||||
 | 
			
		||||
const { isFetching: testConnBtnLoading, execute: testConnExec } = redisApi.testConn.useApi(submitForm);
 | 
			
		||||
const { isFetching: saveBtnLoading, execute: saveRedisExec } = redisApi.saveRedis.useApi(submitForm);
 | 
			
		||||
 | 
			
		||||
watch(
 | 
			
		||||
    () => props.visible,
 | 
			
		||||
    () => {
 | 
			
		||||
        state.dialogVisible = props.visible;
 | 
			
		||||
        if (!state.dialogVisible) {
 | 
			
		||||
watch(dialogVisible, () => {
 | 
			
		||||
    if (!dialogVisible.value) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
        state.tabActiveName = 'basic';
 | 
			
		||||
 | 
			
		||||
    const redis: any = props.redis;
 | 
			
		||||
    if (redis) {
 | 
			
		||||
        state.form = { ...redis };
 | 
			
		||||
@@ -146,8 +130,7 @@ watch(
 | 
			
		||||
        state.form = { db: '0', tagCodePaths: [] } as any;
 | 
			
		||||
        state.dbList = [0];
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const convertDb = (db: string) => {
 | 
			
		||||
    state.dbList = db.split(',').map((x) => Number.parseInt(x));
 | 
			
		||||
@@ -172,24 +155,24 @@ const getReqForm = async () => {
 | 
			
		||||
    return reqForm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const testConn = async () => {
 | 
			
		||||
    await useI18nFormValidate(redisForm);
 | 
			
		||||
const onTestConn = async () => {
 | 
			
		||||
    await useI18nFormValidate(redisFormRef);
 | 
			
		||||
    state.submitForm = await getReqForm();
 | 
			
		||||
    await testConnExec();
 | 
			
		||||
    ElMessage.success(t('ac.connSuccess'));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(redisForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(redisFormRef);
 | 
			
		||||
    state.submitForm = await getReqForm();
 | 
			
		||||
    await saveRedisExec();
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
    emit('update:visible', false);
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    dialogVisible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
            :columns="state.columns"
 | 
			
		||||
        >
 | 
			
		||||
            <template #tableHeader>
 | 
			
		||||
                <el-button v-auth="'authcert:save'" type="primary" icon="plus" @click="edit(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'authcert:save'" type="primary" icon="plus" @click="onEdit(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #resourceCode="{ data }">
 | 
			
		||||
@@ -20,9 +20,9 @@
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #action="{ data }">
 | 
			
		||||
                <el-button v-auth="'authcert:save'" @click="edit(data)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'authcert:save'" @click="onEdit(data)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
 | 
			
		||||
                <el-button v-auth="'authcert:del'" @click="deleteAc(data)" type="danger" link>{{ $t('common.delete') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'authcert:del'" @click="onDeleteAc(data)" type="danger" link>{{ $t('common.delete') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </page-table>
 | 
			
		||||
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
            :title="editor.title"
 | 
			
		||||
            v-model:visible="editor.visible"
 | 
			
		||||
            :auth-cert="editor.authcert"
 | 
			
		||||
            @confirm="confirmSave"
 | 
			
		||||
            @confirm="onConfirmSave"
 | 
			
		||||
            @cancel="editor.authcert = {}"
 | 
			
		||||
            :disable-type="state.disableAuthCertType"
 | 
			
		||||
            :disable-ciphertext-type="state.disableAuthCertCiphertextType"
 | 
			
		||||
@@ -102,7 +102,7 @@ const search = async () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const edit = (data: any) => {
 | 
			
		||||
const onEdit = (data: any) => {
 | 
			
		||||
    state.disableAuthCertType = [];
 | 
			
		||||
    state.disableAuthCertCiphertextType = [];
 | 
			
		||||
    if (data) {
 | 
			
		||||
@@ -128,14 +128,14 @@ const edit = (data: any) => {
 | 
			
		||||
    state.editor.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const confirmSave = async (authCert: any) => {
 | 
			
		||||
const onConfirmSave = async (authCert: any) => {
 | 
			
		||||
    await resourceAuthCertApi.save.request(authCert);
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    state.editor.visible = false;
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteAc = async (data: any) => {
 | 
			
		||||
const onDeleteAc = async (data: any) => {
 | 
			
		||||
    try {
 | 
			
		||||
        await useI18nDeleteConfirm(data.name);
 | 
			
		||||
        await resourceAuthCertApi.delete.request({ id: data.id });
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
                            v-auth="'tag:save'"
 | 
			
		||||
                            type="primary"
 | 
			
		||||
                            icon="plus"
 | 
			
		||||
                            @click="showSaveTagDialog(null)"
 | 
			
		||||
                            @click="onShowSaveTagDialog(null)"
 | 
			
		||||
                        ></el-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div>
 | 
			
		||||
@@ -33,15 +33,15 @@
 | 
			
		||||
                        highlight-current
 | 
			
		||||
                        :props="props"
 | 
			
		||||
                        :data="data"
 | 
			
		||||
                        @node-expand="handleNodeExpand"
 | 
			
		||||
                        @node-collapse="handleNodeCollapse"
 | 
			
		||||
                        @node-contextmenu="nodeContextmenu"
 | 
			
		||||
                        @node-click="treeNodeClick"
 | 
			
		||||
                        @node-expand="onNodeExpand"
 | 
			
		||||
                        @node-collapse="onNodeCollapse"
 | 
			
		||||
                        @node-contextmenu="onNodeContextmenu"
 | 
			
		||||
                        @node-click="onTreeNodeClick"
 | 
			
		||||
                        :default-expanded-keys="defaultExpandedKeys"
 | 
			
		||||
                        draggable
 | 
			
		||||
                        :allow-drop="allowDrop"
 | 
			
		||||
                        :allow-drag="allowDrag"
 | 
			
		||||
                        @node-drop="handleDrop"
 | 
			
		||||
                        @node-drop="onNodeDrop"
 | 
			
		||||
                        :expand-on-click-node="false"
 | 
			
		||||
                        :filter-node-method="filterNode"
 | 
			
		||||
                    >
 | 
			
		||||
@@ -67,7 +67,7 @@
 | 
			
		||||
 | 
			
		||||
            <Pane min-size="40" size="70">
 | 
			
		||||
                <div class="ml-2 h-full">
 | 
			
		||||
                    <el-tabs class="h-full" @tab-change="tabChange" v-model="state.activeTabName" v-if="currentTag">
 | 
			
		||||
                    <el-tabs class="h-full" @tab-change="onTabChange" v-model="state.activeTabName" v-if="currentTag">
 | 
			
		||||
                        <el-tab-pane :label="$t('common.detail')" :name="TagDetail">
 | 
			
		||||
                            <el-descriptions :column="2" border>
 | 
			
		||||
                                <el-descriptions-item :label="$t('common.type')">
 | 
			
		||||
@@ -137,7 +137,7 @@
 | 
			
		||||
            </Pane>
 | 
			
		||||
        </Splitpanes>
 | 
			
		||||
 | 
			
		||||
        <el-dialog width="500px" :title="saveTabDialog.title" :before-close="cancelSaveTag" v-model="saveTabDialog.visible">
 | 
			
		||||
        <el-dialog width="500px" :title="saveTabDialog.title" :before-close="onCancelSaveTag" v-model="saveTabDialog.visible">
 | 
			
		||||
            <el-form ref="tagForm" :rules="rules" :model="saveTabDialog.form" label-width="auto">
 | 
			
		||||
                <el-form-item prop="code" :label="$t('tag.code')" required>
 | 
			
		||||
                    <el-input :disabled="saveTabDialog.form.id ? true : false" v-model="saveTabDialog.form.code" auto-complete="off"></el-input>
 | 
			
		||||
@@ -151,8 +151,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="cancelSaveTag()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button @click="saveTag" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancelSaveTag()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button @click="onSaveTag" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
@@ -223,7 +223,7 @@ const contextmenuAdd = new ContextmenuItem('addTag', 'tag.createSubTag')
 | 
			
		||||
        // 非标签类型不可添加子标签
 | 
			
		||||
        return data.type != TagResourceTypeEnum.Tag.value || (data.children && data.children?.[0].type != TagResourceTypeEnum.Tag.value);
 | 
			
		||||
    })
 | 
			
		||||
    .withOnClick((data: any) => showSaveTagDialog(data));
 | 
			
		||||
    .withOnClick((data: any) => onShowSaveTagDialog(data));
 | 
			
		||||
 | 
			
		||||
const contextmenuEdit = new ContextmenuItem('edit', 'common.edit')
 | 
			
		||||
    .withIcon('edit')
 | 
			
		||||
@@ -231,7 +231,7 @@ const contextmenuEdit = new ContextmenuItem('edit', 'common.edit')
 | 
			
		||||
    .withHideFunc((data: any) => {
 | 
			
		||||
        return data.type != TagResourceTypeEnum.Tag.value;
 | 
			
		||||
    })
 | 
			
		||||
    .withOnClick((data: any) => showEditTagDialog(data));
 | 
			
		||||
    .withOnClick((data: any) => onShowEditTagDialog(data));
 | 
			
		||||
 | 
			
		||||
const contextmenuDel = new ContextmenuItem('delete', 'common.delete')
 | 
			
		||||
    .withIcon('delete')
 | 
			
		||||
@@ -240,7 +240,7 @@ const contextmenuDel = new ContextmenuItem('delete', 'common.delete')
 | 
			
		||||
        // 存在子标签,则不允许删除
 | 
			
		||||
        return data.children || data.type != TagResourceTypeEnum.Tag.value;
 | 
			
		||||
    })
 | 
			
		||||
    .withOnClick((data: any) => deleteTag(data));
 | 
			
		||||
    .withOnClick((data: any) => onDeleteTag(data));
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    data: [],
 | 
			
		||||
@@ -364,7 +364,7 @@ const allowDrag = (node: any) => {
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleDrop = async (draggingNode: any, dropNode: any) => {
 | 
			
		||||
const onNodeDrop = async (draggingNode: any, dropNode: any) => {
 | 
			
		||||
    const draggingData = draggingNode.data;
 | 
			
		||||
    const dropData = dropNode.data;
 | 
			
		||||
 | 
			
		||||
@@ -378,7 +378,7 @@ const handleDrop = async (draggingNode: any, dropNode: any) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const tabChange = () => {
 | 
			
		||||
const onTabChange = () => {
 | 
			
		||||
    setNowTabData();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -420,20 +420,21 @@ const getDetail = async (id: number) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 树节点右击事件
 | 
			
		||||
const nodeContextmenu = (event: any, data: any) => {
 | 
			
		||||
const onNodeContextmenu = (event: any, data: any) => {
 | 
			
		||||
    const { clientX, clientY } = event;
 | 
			
		||||
    state.contextmenu.dropdown.x = clientX;
 | 
			
		||||
    state.contextmenu.dropdown.y = clientY;
 | 
			
		||||
    contextmenuRef.value.openContextmenu(data);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const treeNodeClick = async (data: any) => {
 | 
			
		||||
const onTreeNodeClick = async (data: any) => {
 | 
			
		||||
    state.currentTag = await getDetail(data.id);
 | 
			
		||||
    state.activeTabName = TagDetail;
 | 
			
		||||
    // 关闭可能存在的右击菜单
 | 
			
		||||
    contextmenuRef.value.closeContextmenu();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showSaveTagDialog = (data: any) => {
 | 
			
		||||
const onShowSaveTagDialog = (data: any) => {
 | 
			
		||||
    if (data) {
 | 
			
		||||
        state.saveTabDialog.form.pid = data.id;
 | 
			
		||||
        state.saveTabDialog.title = t('tag.createSubTagTitle', { codePath: data.codePath });
 | 
			
		||||
@@ -443,7 +444,7 @@ const showSaveTagDialog = (data: any) => {
 | 
			
		||||
    state.saveTabDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showEditTagDialog = (data: any) => {
 | 
			
		||||
const onShowEditTagDialog = (data: any) => {
 | 
			
		||||
    state.saveTabDialog.form.id = data.id;
 | 
			
		||||
    state.saveTabDialog.form.code = data.code;
 | 
			
		||||
    state.saveTabDialog.form.name = data.name;
 | 
			
		||||
@@ -452,23 +453,23 @@ const showEditTagDialog = (data: any) => {
 | 
			
		||||
    state.saveTabDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const saveTag = async () => {
 | 
			
		||||
const onSaveTag = async () => {
 | 
			
		||||
    await useI18nFormValidate(tagForm);
 | 
			
		||||
    const form = state.saveTabDialog.form;
 | 
			
		||||
    await tagApi.saveTagTree.request(form);
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    search();
 | 
			
		||||
    cancelSaveTag();
 | 
			
		||||
    onCancelSaveTag();
 | 
			
		||||
    state.currentTag = null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancelSaveTag = () => {
 | 
			
		||||
const onCancelSaveTag = () => {
 | 
			
		||||
    state.saveTabDialog.visible = false;
 | 
			
		||||
    state.saveTabDialog.form = {} as any;
 | 
			
		||||
    tagForm.value.resetFields();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteTag = async (data: any) => {
 | 
			
		||||
const onDeleteTag = async (data: any) => {
 | 
			
		||||
    await useI18nDeleteConfirm(data.codePath);
 | 
			
		||||
    await tagApi.delTagTree.request({ id: data.id });
 | 
			
		||||
    useI18nDeleteSuccessMsg();
 | 
			
		||||
@@ -476,7 +477,7 @@ const deleteTag = async (data: any) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 节点被展开时触发的事件
 | 
			
		||||
const handleNodeExpand = (data: any, node: any) => {
 | 
			
		||||
const onNodeExpand = (data: any, node: any) => {
 | 
			
		||||
    const id: any = node.data.id;
 | 
			
		||||
    if (!state.defaultExpandedKeys.includes(id)) {
 | 
			
		||||
        state.defaultExpandedKeys.push(id);
 | 
			
		||||
@@ -484,7 +485,7 @@ const handleNodeExpand = (data: any, node: any) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 关闭节点
 | 
			
		||||
const handleNodeCollapse = (data: any, node: any) => {
 | 
			
		||||
const onNodeCollapse = (data: any, node: any) => {
 | 
			
		||||
    removeDeafultExpandId(node.data.id);
 | 
			
		||||
 | 
			
		||||
    let childNodes = node.childNodes;
 | 
			
		||||
@@ -493,7 +494,7 @@ const handleNodeCollapse = (data: any, node: any) => {
 | 
			
		||||
            removeDeafultExpandId(cn.data.id);
 | 
			
		||||
        }
 | 
			
		||||
        // 递归删除展开的子节点节点id
 | 
			
		||||
        handleNodeCollapse(data, cn);
 | 
			
		||||
        onNodeCollapse(data, cn);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@
 | 
			
		||||
            :columns="columns"
 | 
			
		||||
        >
 | 
			
		||||
            <template #tableHeader>
 | 
			
		||||
                <el-button v-auth="'team:save'" type="primary" icon="plus" @click="showSaveTeamDialog(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'team:del'" :disabled="selectionData.length < 1" @click="deleteTeam()" type="danger" icon="delete">
 | 
			
		||||
                <el-button v-auth="'team:save'" type="primary" icon="plus" @click="onShowSaveTeamDialog(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'team:del'" :disabled="selectionData.length < 1" @click="onDeleteTeam()" type="danger" icon="delete">
 | 
			
		||||
                    {{ $t('common.delete') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
@@ -23,22 +23,22 @@
 | 
			
		||||
            <template #validityDate="{ data }"> {{ formatDate(data.validityStartDate) }} ~ {{ formatDate(data.validityEndDate) }} </template>
 | 
			
		||||
 | 
			
		||||
            <template #action="{ data }">
 | 
			
		||||
                <el-button @click.prevent="showMembers(data)" link type="primary">{{ $t('team.member') }}</el-button>
 | 
			
		||||
                <el-button @click.prevent="onShowMembers(data)" link type="primary">{{ $t('team.member') }}</el-button>
 | 
			
		||||
 | 
			
		||||
                <el-button v-auth="'team:save'" @click.prevent="showSaveTeamDialog(data)" link type="warning">{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                <el-button v-auth="'team:save'" @click.prevent="onShowSaveTeamDialog(data)" link type="warning">{{ $t('common.edit') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </page-table>
 | 
			
		||||
 | 
			
		||||
        <el-drawer
 | 
			
		||||
            :title="addTeamDialog.title"
 | 
			
		||||
            v-model="addTeamDialog.visible"
 | 
			
		||||
            :before-close="cancelSaveTeam"
 | 
			
		||||
            :before-close="onCancelSaveTeam"
 | 
			
		||||
            :destroy-on-close="true"
 | 
			
		||||
            :close-on-click-modal="false"
 | 
			
		||||
            size="40%"
 | 
			
		||||
        >
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="addTeamDialog.title" :back="cancelSaveTeam" />
 | 
			
		||||
                <DrawerHeader :header="addTeamDialog.title" :back="onCancelSaveTeam" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form ref="teamForm" :model="addTeamDialog.form" :rules="teamFormRules" label-width="auto">
 | 
			
		||||
@@ -69,8 +69,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="cancelSaveTeam()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button @click="saveTeam" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancelSaveTeam()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button @click="onSaveTeam" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
@@ -85,22 +85,22 @@
 | 
			
		||||
                :columns="showMemDialog.columns"
 | 
			
		||||
            >
 | 
			
		||||
                <template #tableHeader>
 | 
			
		||||
                    <el-button v-auth="'team:member:save'" @click="showAddMemberDialog()" type="primary" icon="plus">{{ $t('common.add') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'team:member:save'" @click="onShowAddMemberDialog()" type="primary" icon="plus">{{ $t('common.add') }}</el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <template #action="{ data }">
 | 
			
		||||
                    <el-button v-auth="'team:member:del'" @click="deleteMember(data)" type="danger" link icon="delete"></el-button>
 | 
			
		||||
                    <el-button v-auth="'team:member:del'" @click="onDeleteMember(data)" type="danger" link icon="delete"></el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
            </page-table>
 | 
			
		||||
 | 
			
		||||
            <el-dialog width="400px" :title="$t('team.addMember')" :before-close="cancelAddMember" v-model="showMemDialog.addVisible">
 | 
			
		||||
            <el-dialog width="400px" :title="$t('team.addMember')" :before-close="onCancelAddMember" v-model="showMemDialog.addVisible">
 | 
			
		||||
                <el-form :model="showMemDialog.memForm" label-width="auto">
 | 
			
		||||
                    <AccountSelectFormItem v-model="showMemDialog.memForm.accountIds" multiple focus />
 | 
			
		||||
                </el-form>
 | 
			
		||||
                <template #footer>
 | 
			
		||||
                    <div class="dialog-footer">
 | 
			
		||||
                        <el-button @click="cancelAddMember()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                        <el-button @click="addMember" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                        <el-button @click="onCancelAddMember()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                        <el-button @click="onAddMember" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </template>
 | 
			
		||||
            </el-dialog>
 | 
			
		||||
@@ -207,7 +207,7 @@ const search = async () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showSaveTeamDialog = async (data: any) => {
 | 
			
		||||
const onShowSaveTeamDialog = async (data: any) => {
 | 
			
		||||
    if (data) {
 | 
			
		||||
        state.addTeamDialog.title = useI18nEditTitle('team.team');
 | 
			
		||||
        state.addTeamDialog.form.id = data.id;
 | 
			
		||||
@@ -225,7 +225,7 @@ const showSaveTeamDialog = async (data: any) => {
 | 
			
		||||
    state.addTeamDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const saveTeam = async () => {
 | 
			
		||||
const onSaveTeam = async () => {
 | 
			
		||||
    await useI18nFormValidate(teamForm);
 | 
			
		||||
    const form = state.addTeamDialog.form;
 | 
			
		||||
    form.validityStartDate = formatDate(form.validityDate[0]);
 | 
			
		||||
@@ -233,10 +233,10 @@ const saveTeam = async () => {
 | 
			
		||||
    await tagApi.saveTeam.request(form);
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    search();
 | 
			
		||||
    cancelSaveTeam();
 | 
			
		||||
    onCancelSaveTeam();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancelSaveTeam = () => {
 | 
			
		||||
const onCancelSaveTeam = () => {
 | 
			
		||||
    state.addTeamDialog.visible = false;
 | 
			
		||||
    teamForm.value.resetFields();
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
@@ -244,7 +244,7 @@ const cancelSaveTeam = () => {
 | 
			
		||||
    }, 500);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteTeam = async () => {
 | 
			
		||||
const onDeleteTeam = async () => {
 | 
			
		||||
    await useI18nDeleteConfirm(state.selectionData.map((x: any) => x.name).join('、'));
 | 
			
		||||
    await tagApi.delTeam.request({ id: state.selectionData.map((x: any) => x.id).join(',') });
 | 
			
		||||
    useI18nDeleteSuccessMsg();
 | 
			
		||||
@@ -253,13 +253,13 @@ const deleteTeam = async () => {
 | 
			
		||||
 | 
			
		||||
/********** 团队成员相关 ***********/
 | 
			
		||||
 | 
			
		||||
const showMembers = async (team: any) => {
 | 
			
		||||
const onShowMembers = async (team: any) => {
 | 
			
		||||
    state.showMemDialog.query.teamId = team.id;
 | 
			
		||||
    state.showMemDialog.visible = true;
 | 
			
		||||
    state.showMemDialog.title = t('team.teamMember', { teamName: team.name });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteMember = async (data: any) => {
 | 
			
		||||
const onDeleteMember = async (data: any) => {
 | 
			
		||||
    await tagApi.delTeamMem.request(data);
 | 
			
		||||
    useI18nOperateSuccessMsg();
 | 
			
		||||
    // 重新赋值成员列表
 | 
			
		||||
@@ -273,11 +273,11 @@ const setMemebers = async () => {
 | 
			
		||||
    showMemPageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showAddMemberDialog = () => {
 | 
			
		||||
const onShowAddMemberDialog = () => {
 | 
			
		||||
    state.showMemDialog.addVisible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addMember = async () => {
 | 
			
		||||
const onAddMember = async () => {
 | 
			
		||||
    const memForm = state.showMemDialog.memForm;
 | 
			
		||||
    memForm.teamId = state.showMemDialog.query.teamId;
 | 
			
		||||
    notBlank(memForm.accountIds, t('team.selectAccountTips'));
 | 
			
		||||
@@ -285,10 +285,10 @@ const addMember = async () => {
 | 
			
		||||
    await tagApi.saveTeamMem.request(memForm);
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    setMemebers();
 | 
			
		||||
    cancelAddMember();
 | 
			
		||||
    onCancelAddMember();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancelAddMember = () => {
 | 
			
		||||
const onCancelAddMember = () => {
 | 
			
		||||
    state.showMemDialog.memForm = {} as any;
 | 
			
		||||
    state.showMemDialog.addVisible = false;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-dialog :title="title" v-model="visible" :before-close="cancel" :show-close="false" width="600px" :destroy-on-close="true">
 | 
			
		||||
            <el-form :model="form" ref="accountForm" :rules="rules" label-width="auto">
 | 
			
		||||
        <el-dialog :title="title" v-model="visible" :before-close="onCancel" :show-close="false" width="600px" :destroy-on-close="true">
 | 
			
		||||
            <el-form :model="form" ref="accountFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-form-item prop="name" :label="$t('system.account.name')">
 | 
			
		||||
                    <el-input v-model.trim="form.name" auto-complete="off" clearable></el-input>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
@@ -49,15 +49,15 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { toRefs, reactive, watch, ref } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watch, useTemplateRef } from 'vue';
 | 
			
		||||
import { accountApi } from '../api';
 | 
			
		||||
import { randomPassword } from '@/common/utils/string';
 | 
			
		||||
import { useI18nFormValidate, useI18nSaveSuccessMsg } from '@/hooks/useI18n';
 | 
			
		||||
@@ -77,7 +77,7 @@ const emit = defineEmits(['cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
const visible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
 | 
			
		||||
const accountForm: any = ref(null);
 | 
			
		||||
const accountFormRef: any = useTemplateRef('accountFormRef');
 | 
			
		||||
 | 
			
		||||
const rules = {
 | 
			
		||||
    name: [Rules.requiredInput('system.account.name')],
 | 
			
		||||
@@ -123,16 +123,16 @@ watch(props, (newValue: any) => {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(accountForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(accountFormRef);
 | 
			
		||||
    await saveAccountExec();
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    //重置表单域
 | 
			
		||||
    accountForm.value.resetFields();
 | 
			
		||||
    accountFormRef.value.resetFields();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    visible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -10,24 +10,24 @@
 | 
			
		||||
            :columns="columns"
 | 
			
		||||
        >
 | 
			
		||||
            <template #tableHeader>
 | 
			
		||||
                <el-button v-auth="perms.addAccount" type="primary" icon="plus" @click="editAccount(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="perms.delAccount" :disabled="state.selectionData.length < 1" @click="deleteAccount()" type="danger" icon="delete">
 | 
			
		||||
                <el-button v-auth="perms.addAccount" type="primary" icon="plus" @click="onEditAccount(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="perms.delAccount" :disabled="state.selectionData.length < 1" @click="onDeleteAccount()" type="danger" icon="delete">
 | 
			
		||||
                    {{ $t('common.delete') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #action="{ data }">
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.addAccount]" @click="editAccount(data)" type="primary">{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.addAccount]" @click="onEditAccount(data)" type="primary">{{ $t('common.edit') }}</el-button>
 | 
			
		||||
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.saveAccountRole]" @click="showRoleEdit(data)" type="success">
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.saveAccountRole]" @click="onShowRoleEdit(data)" type="success">
 | 
			
		||||
                    {{ $t('system.account.roleAllocation') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == 1" @click="changeStatus(data)" type="danger">
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == 1" @click="onChangeStatus(data)" type="danger">
 | 
			
		||||
                    {{ $t('common.disable') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == -1" type="success" @click="changeStatus(data)">
 | 
			
		||||
                <el-button link v-if="actionBtns[perms.changeAccountStatus] && data.status == -1" type="success" @click="onChangeStatus(data)">
 | 
			
		||||
                    {{ $t('common.enable') }}
 | 
			
		||||
                </el-button>
 | 
			
		||||
 | 
			
		||||
@@ -35,7 +35,7 @@
 | 
			
		||||
                    link
 | 
			
		||||
                    v-if="actionBtns[perms.addAccount]"
 | 
			
		||||
                    :disabled="!data.otpSecret || data.otpSecret == '-'"
 | 
			
		||||
                    @click="resetOtpSecret(data)"
 | 
			
		||||
                    @click="onResetOtpSecret(data)"
 | 
			
		||||
                    type="warning"
 | 
			
		||||
                >
 | 
			
		||||
                    {{ $t('system.account.resetOtp') }}
 | 
			
		||||
@@ -55,8 +55,8 @@
 | 
			
		||||
            </el-table>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
 | 
			
		||||
        <role-allocation v-model:visible="roleDialog.visible" :account="roleDialog.account" @cancel="cancel()" />
 | 
			
		||||
        <account-edit :title="accountDialog.title" v-model:visible="accountDialog.visible" v-model:account="accountDialog.data" @val-change="valChange()" />
 | 
			
		||||
        <role-allocation v-model:visible="roleDialog.visible" :account="roleDialog.account" @cancel="onCancel()" />
 | 
			
		||||
        <account-edit :title="accountDialog.title" v-model:visible="accountDialog.visible" v-model:account="accountDialog.data" @val-change="onValChange()" />
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -150,7 +150,7 @@ const search = async () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const changeStatus = async (row: any) => {
 | 
			
		||||
const onChangeStatus = async (row: any) => {
 | 
			
		||||
    let id = row.id;
 | 
			
		||||
    let status = row.status == AccountStatusEnum.Disable.value ? AccountStatusEnum.Enable.value : AccountStatusEnum.Disable.value;
 | 
			
		||||
    await accountApi.changeStatus.request({
 | 
			
		||||
@@ -161,7 +161,7 @@ const changeStatus = async (row: any) => {
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const resetOtpSecret = async (row: any) => {
 | 
			
		||||
const onResetOtpSecret = async (row: any) => {
 | 
			
		||||
    let id = row.id;
 | 
			
		||||
    await accountApi.resetOtpSecret.request({
 | 
			
		||||
        id,
 | 
			
		||||
@@ -170,7 +170,7 @@ const resetOtpSecret = async (row: any) => {
 | 
			
		||||
    row.otpSecret = '-';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const editAccount = (data: any) => {
 | 
			
		||||
const onEditAccount = (data: any) => {
 | 
			
		||||
    if (!data) {
 | 
			
		||||
        state.accountDialog.title = useI18nCreateTitle('personal.accountInfo');
 | 
			
		||||
        state.accountDialog.data = null;
 | 
			
		||||
@@ -181,22 +181,22 @@ const editAccount = (data: any) => {
 | 
			
		||||
    state.accountDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showRoleEdit = (data: any) => {
 | 
			
		||||
const onShowRoleEdit = (data: any) => {
 | 
			
		||||
    state.roleDialog.visible = true;
 | 
			
		||||
    state.roleDialog.account = data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    state.roleDialog.visible = false;
 | 
			
		||||
    state.roleDialog.account = null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const valChange = () => {
 | 
			
		||||
const onValChange = () => {
 | 
			
		||||
    state.accountDialog.visible = false;
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteAccount = async () => {
 | 
			
		||||
const onDeleteAccount = async () => {
 | 
			
		||||
    await useI18nDeleteConfirm(state.selectionData.map((x: any) => x.username).join('、'));
 | 
			
		||||
    await accountApi.del.request({ id: state.selectionData.map((x: any) => x.id).join(',') });
 | 
			
		||||
    useI18nDeleteSuccessMsg();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
            @open="searchAccountRoles()"
 | 
			
		||||
            :title="account == null ? '' : $t('system.account.allocateRoleTitle', { name: account.username })"
 | 
			
		||||
            v-model="dialogVisible"
 | 
			
		||||
            :before-close="cancel"
 | 
			
		||||
            :before-close="onCancel"
 | 
			
		||||
            :destroy-on-close="true"
 | 
			
		||||
            width="55%"
 | 
			
		||||
        >
 | 
			
		||||
@@ -20,11 +20,11 @@
 | 
			
		||||
                        lazy
 | 
			
		||||
                    >
 | 
			
		||||
                        <template #tableHeader>
 | 
			
		||||
                            <el-button @click="showResources" icon="view" type="primary" link>{{ $t('system.account.menuAndPermission') }}</el-button>
 | 
			
		||||
                            <el-button @click="onShowResources" icon="view" type="primary" link>{{ $t('system.account.menuAndPermission') }}</el-button>
 | 
			
		||||
                        </template>
 | 
			
		||||
 | 
			
		||||
                        <template #action="{ data }">
 | 
			
		||||
                            <el-button v-auth="'account:saveRoles'" type="danger" @click="relateRole(-1, data.roleId)" icon="delete" link plain>
 | 
			
		||||
                            <el-button v-auth="'account:saveRoles'" type="danger" @click="onRelateRole(-1, data.roleId)" icon="delete" link plain>
 | 
			
		||||
                                {{ $t('system.account.remove') }}
 | 
			
		||||
                            </el-button>
 | 
			
		||||
                        </template>
 | 
			
		||||
@@ -44,7 +44,7 @@
 | 
			
		||||
                        <template #action="{ data }">
 | 
			
		||||
                            <el-button
 | 
			
		||||
                                v-auth="'account:saveRoles'"
 | 
			
		||||
                                @click="relateRole(1, data.id)"
 | 
			
		||||
                                @click="onRelateRole(1, data.id)"
 | 
			
		||||
                                :disabled="data.code?.indexOf('COMMON') == 0 || data.status == RoleStatusEnum.Disable.value"
 | 
			
		||||
                                type="success"
 | 
			
		||||
                                icon="CirclePlus"
 | 
			
		||||
@@ -176,7 +176,7 @@ const onTabChange = () => {
 | 
			
		||||
    searchAccountRoles();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const relateRole = async (relateType: number, roleId: number) => {
 | 
			
		||||
const onRelateRole = async (relateType: number, roleId: number) => {
 | 
			
		||||
    await accountApi.saveRole.request({
 | 
			
		||||
        id: props.account!.id,
 | 
			
		||||
        roleId,
 | 
			
		||||
@@ -191,7 +191,7 @@ const relateRole = async (relateType: number, roleId: number) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showResources = async () => {
 | 
			
		||||
const onShowResources = async () => {
 | 
			
		||||
    let showResourceDialog = state.showResourceDialog;
 | 
			
		||||
    showResourceDialog.title = t('system.account.userMenuTitle', { name: props.account?.username });
 | 
			
		||||
    showResourceDialog.resources = [];
 | 
			
		||||
@@ -204,7 +204,7 @@ const showResources = async () => {
 | 
			
		||||
/**
 | 
			
		||||
 * 取消
 | 
			
		||||
 */
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    state.unRelatedQuery.pageNum = 1;
 | 
			
		||||
    state.unRelatedQuery.name = null;
 | 
			
		||||
    state.unRelatedQuery.code = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-drawer :title="title" v-model="visible" :show-close="false" :before-close="cancel" size="1000px" :destroy-on-close="true">
 | 
			
		||||
        <el-drawer :title="title" v-model="visible" :show-close="false" :before-close="onCancel" size="1000px" :destroy-on-close="true">
 | 
			
		||||
            <template #header>
 | 
			
		||||
                <DrawerHeader :header="title" :back="cancel" />
 | 
			
		||||
                <DrawerHeader :header="title" :back="onCancel" />
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <el-form ref="configForm" :model="form" :rules="rules" label-width="auto">
 | 
			
		||||
            <el-form ref="configFormRef" :model="form" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-form-item prop="name" :label="$t('system.sysconf.confItem')" required>
 | 
			
		||||
                    <el-input v-model="form.name"></el-input>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
@@ -35,8 +35,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-drawer>
 | 
			
		||||
@@ -44,7 +44,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { ref, toRefs, reactive, watch } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watch, useTemplateRef } from 'vue';
 | 
			
		||||
import { configApi, accountApi } from '../api';
 | 
			
		||||
import { DynamicFormEdit } from '@/components/dynamic-form';
 | 
			
		||||
import DrawerHeader from '@/components/drawer-header/DrawerHeader.vue';
 | 
			
		||||
@@ -70,7 +70,7 @@ const visible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
const configForm: any = ref(null);
 | 
			
		||||
const configFormRef: any = useTemplateRef('configFormRef');
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    params: [] as any,
 | 
			
		||||
@@ -116,7 +116,7 @@ watch(visible, () => {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    visible.value = false;
 | 
			
		||||
    // 若父组件有取消事件,则调用
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
@@ -131,8 +131,8 @@ const getAccount = (username: any) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(configForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(configFormRef);
 | 
			
		||||
    if (state.params) {
 | 
			
		||||
        state.form.params = JSON.stringify(state.params);
 | 
			
		||||
    }
 | 
			
		||||
@@ -144,7 +144,7 @@ const btnOk = async () => {
 | 
			
		||||
 | 
			
		||||
    await saveConfigExec();
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss"></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
            :data-handler-fn="handleData"
 | 
			
		||||
        >
 | 
			
		||||
            <template #tableHeader>
 | 
			
		||||
                <el-button v-auth="perms.saveConfig" type="primary" icon="plus" @click="editConfig(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
                <el-button v-auth="perms.saveConfig" type="primary" icon="plus" @click="onEditConfig(false)">{{ $t('common.create') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
 | 
			
		||||
            <template #status="{ data }">
 | 
			
		||||
@@ -19,11 +19,11 @@
 | 
			
		||||
 | 
			
		||||
            <template #action="{ data }">
 | 
			
		||||
                <el-button :disabled="data.status == -1" type="warning" @click="showSetConfigDialog(data)" link>{{ $t('system.sysconf.conf') }}</el-button>
 | 
			
		||||
                <el-button v-if="actionBtns[perms.saveConfig]" @click="editConfig(data)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
                <el-button v-if="actionBtns[perms.saveConfig]" @click="onEditConfig(data)" type="primary" link>{{ $t('common.edit') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </page-table>
 | 
			
		||||
 | 
			
		||||
        <el-dialog @close="closeSetConfigDialog" :title="$t('system.sysconf.confItemSetting')" v-model="paramsDialog.visible" width="700px">
 | 
			
		||||
        <el-dialog @close="onCloseSetConfigDialog" :title="$t('system.sysconf.confItemSetting')" v-model="paramsDialog.visible" width="700px">
 | 
			
		||||
            <dynamic-form
 | 
			
		||||
                ref="paramsFormRef"
 | 
			
		||||
                v-if="paramsDialog.paramsFormItem.length > 0"
 | 
			
		||||
@@ -39,13 +39,13 @@
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <span class="dialog-footer">
 | 
			
		||||
                    <el-button @click="closeSetConfigDialog()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCloseSetConfigDialog()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="'config:save'" type="primary" @click="setConfig()">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </span>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
 | 
			
		||||
        <config-edit :title="$t(configEdit.title)" v-model:visible="configEdit.visible" :data="configEdit.config" @val-change="configEditChange" />
 | 
			
		||||
        <config-edit :title="$t(configEdit.title)" v-model:visible="configEdit.visible" :data="configEdit.config" @val-change="onConfigEditChange" />
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
@@ -143,7 +143,7 @@ const showSetConfigDialog = (row: any) => {
 | 
			
		||||
    state.paramsDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const closeSetConfigDialog = () => {
 | 
			
		||||
const onCloseSetConfigDialog = () => {
 | 
			
		||||
    state.paramsDialog.visible = false;
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
        state.paramsDialog.config = {};
 | 
			
		||||
@@ -182,7 +182,7 @@ const setConfig = async () => {
 | 
			
		||||
        value: paramsValue,
 | 
			
		||||
    });
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    closeSetConfigDialog();
 | 
			
		||||
    onCloseSetConfigDialog();
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -195,12 +195,12 @@ const hasParam = (paramKey: string, paramItems: any) => {
 | 
			
		||||
    return false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const configEditChange = () => {
 | 
			
		||||
const onConfigEditChange = () => {
 | 
			
		||||
    useI18nSaveSuccessMsg();
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const editConfig = (data: any) => {
 | 
			
		||||
const onEditConfig = (data: any) => {
 | 
			
		||||
    if (data) {
 | 
			
		||||
        state.configEdit.title = 'common.edit';
 | 
			
		||||
        state.configEdit.config = data;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-dialog :title="title" :destroy-on-close="true" v-model="visible" width="800px">
 | 
			
		||||
            <el-form :model="form" :inline="true" ref="menuForm" :rules="rules" label-width="auto">
 | 
			
		||||
            <el-form :model="form" :inline="true" ref="menuFormRef" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-row :gutter="35">
 | 
			
		||||
                    <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
 | 
			
		||||
                        <el-form-item class="!w-full" prop="type" :label="$t('common.type')" required>
 | 
			
		||||
@@ -71,7 +71,7 @@
 | 
			
		||||
                            prop="meta.linkType"
 | 
			
		||||
                            :tooltip="$t('system.menu.externalLinkTips')"
 | 
			
		||||
                        >
 | 
			
		||||
                            <el-select class="!w-full" @change="changeLinkType" v-model="form.meta.linkType">
 | 
			
		||||
                            <el-select class="!w-full" @change="onChangeLinkType" v-model="form.meta.linkType">
 | 
			
		||||
                                <el-option :key="0" :label="$t('system.menu.no')" :value="0"> </el-option>
 | 
			
		||||
                                <el-option :key="1" :label="$t('system.menu.inline')" :value="1"> </el-option>
 | 
			
		||||
                                <el-option :key="2" :label="$t('system.menu.externalLink')" :value="2"> </el-option>
 | 
			
		||||
@@ -87,17 +87,15 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div>
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
    </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { ref, toRefs, reactive, watchEffect } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watchEffect, useTemplateRef } from 'vue';
 | 
			
		||||
import { ElMessage } from 'element-plus';
 | 
			
		||||
import { resourceApi } from '../api';
 | 
			
		||||
import { ResourceTypeEnum } from '../enums';
 | 
			
		||||
@@ -107,6 +105,7 @@ import { useI18n } from 'vue-i18n';
 | 
			
		||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
 | 
			
		||||
import FormItemTooltip from '@/components/form/FormItemTooltip.vue';
 | 
			
		||||
import { Rules } from '@/common/rule';
 | 
			
		||||
import { useI18nFormValidate } from '@/hooks/useI18n';
 | 
			
		||||
 | 
			
		||||
const { t } = useI18n();
 | 
			
		||||
 | 
			
		||||
@@ -127,7 +126,7 @@ const visible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
const menuForm: any = ref(null);
 | 
			
		||||
const menuFormRef: any = useTemplateRef('menuFormRef');
 | 
			
		||||
 | 
			
		||||
const menuTypeValue = ResourceTypeEnum.Menu.value;
 | 
			
		||||
 | 
			
		||||
@@ -208,17 +207,12 @@ watchEffect(() => {
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
// 改变外链类型
 | 
			
		||||
const changeLinkType = () => {
 | 
			
		||||
const onChangeLinkType = () => {
 | 
			
		||||
    state.form.meta.component = '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    try {
 | 
			
		||||
        await menuForm.value.validate();
 | 
			
		||||
    } catch (e: any) {
 | 
			
		||||
        ElMessage.error(t('common.formValidationError'));
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(menuFormRef);
 | 
			
		||||
 | 
			
		||||
    const submitForm = { ...state.form };
 | 
			
		||||
    if (submitForm.type == 1) {
 | 
			
		||||
@@ -233,7 +227,7 @@ const btnOk = async () => {
 | 
			
		||||
 | 
			
		||||
    emit('val-change', submitForm);
 | 
			
		||||
    ElMessage.success(t('common.saveSuccess'));
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const parseMenuMeta = (meta: any) => {
 | 
			
		||||
@@ -270,7 +264,7 @@ const parseMenuMeta = (meta: any) => {
 | 
			
		||||
    return metaForm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    visible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
                <div class="card !p-1 mr-1 flex justify-between">
 | 
			
		||||
                    <div class="mb-1">
 | 
			
		||||
                        <el-input v-model="filterResource" clearable :placeholder="$t('system.menu.filterPlaceholder')" class="mr-2 !w-[200px]" />
 | 
			
		||||
                        <el-button v-auth="perms.addResource" type="primary" icon="plus" @click="addResource(false)"></el-button>
 | 
			
		||||
                        <el-button v-auth="perms.addResource" type="primary" icon="plus" @click="onAddResource(false)"></el-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div>
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
                        @node-expand="handleNodeExpand"
 | 
			
		||||
                        @node-collapse="handleNodeCollapse"
 | 
			
		||||
                        @node-contextmenu="nodeContextmenu"
 | 
			
		||||
                        @node-click="treeNodeClick"
 | 
			
		||||
                        @node-click="onTreeNodeClick"
 | 
			
		||||
                        :default-expanded-keys="defaultExpandedKeys"
 | 
			
		||||
                        :expand-on-click-node="false"
 | 
			
		||||
                        draggable
 | 
			
		||||
@@ -136,7 +136,7 @@
 | 
			
		||||
            :typeDisabled="dialogForm.typeDisabled"
 | 
			
		||||
            :departTree="data"
 | 
			
		||||
            :type="dialogForm.type"
 | 
			
		||||
            @val-change="valChange"
 | 
			
		||||
            @val-change="onValChange"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        <contextmenu :dropdown="state.contextmenu.dropdown" :items="state.contextmenu.items" ref="contextmenuRef" />
 | 
			
		||||
@@ -186,29 +186,29 @@ const contextmenuAdd = new ContextmenuItem('add', 'system.menu.addSubResource')
 | 
			
		||||
    .withIcon('circle-plus')
 | 
			
		||||
    .withPermission(perms.addResource)
 | 
			
		||||
    .withHideFunc((data: any) => data.type !== menuTypeValue)
 | 
			
		||||
    .withOnClick((data: any) => addResource(data));
 | 
			
		||||
    .withOnClick((data: any) => onAddResource(data));
 | 
			
		||||
 | 
			
		||||
const contextmenuEdit = new ContextmenuItem('edit', 'common.edit')
 | 
			
		||||
    .withIcon('edit')
 | 
			
		||||
    .withPermission(perms.updateResource)
 | 
			
		||||
    .withOnClick((data: any) => editResource(data));
 | 
			
		||||
    .withOnClick((data: any) => onEditResource(data));
 | 
			
		||||
 | 
			
		||||
const contextmenuEnable = new ContextmenuItem('enable', 'system.menu.enable')
 | 
			
		||||
    .withIcon('circle-check')
 | 
			
		||||
    .withPermission(perms.updateResource)
 | 
			
		||||
    .withHideFunc((data: any) => data.status === 1)
 | 
			
		||||
    .withOnClick((data: any) => changeStatus(data, 1));
 | 
			
		||||
    .withOnClick((data: any) => onChangeStatus(data, 1));
 | 
			
		||||
 | 
			
		||||
const contextmenuDisable = new ContextmenuItem('disable', 'system.menu.disable')
 | 
			
		||||
    .withIcon('circle-close')
 | 
			
		||||
    .withPermission(perms.updateResource)
 | 
			
		||||
    .withHideFunc((data: any) => data.status === -1)
 | 
			
		||||
    .withOnClick((data: any) => changeStatus(data, -1));
 | 
			
		||||
    .withOnClick((data: any) => onChangeStatus(data, -1));
 | 
			
		||||
 | 
			
		||||
const contextmenuDel = new ContextmenuItem('delete', 'common.delete')
 | 
			
		||||
    .withIcon('delete')
 | 
			
		||||
    .withPermission(perms.delResource)
 | 
			
		||||
    .withOnClick((data: any) => deleteMenu(data));
 | 
			
		||||
    .withOnClick((data: any) => onDeleteMenu(data));
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    contextmenu: {
 | 
			
		||||
@@ -263,7 +263,7 @@ const nodeContextmenu = (event: any, data: any) => {
 | 
			
		||||
    contextmenuRef.value.openContextmenu(data);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const treeNodeClick = async (data: any) => {
 | 
			
		||||
const onTreeNodeClick = async (data: any) => {
 | 
			
		||||
    state.activeTabName = ResourceDetail;
 | 
			
		||||
    // 关闭可能存在的右击菜单
 | 
			
		||||
    contextmenuRef.value.closeContextmenu();
 | 
			
		||||
@@ -286,7 +286,7 @@ const onTabClick = async (activeTab: any) => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const deleteMenu = async (data: any) => {
 | 
			
		||||
const onDeleteMenu = async (data: any) => {
 | 
			
		||||
    await useI18nDeleteConfirm(data.name);
 | 
			
		||||
    await resourceApi.del.request({
 | 
			
		||||
        id: data.id,
 | 
			
		||||
@@ -296,7 +296,7 @@ const deleteMenu = async (data: any) => {
 | 
			
		||||
    search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const addResource = (data: any) => {
 | 
			
		||||
const onAddResource = (data: any) => {
 | 
			
		||||
    let dialog = state.dialogForm;
 | 
			
		||||
    dialog.data = { pid: 0, type: 1 };
 | 
			
		||||
    // 添加顶级菜单情况
 | 
			
		||||
@@ -333,7 +333,7 @@ const addResource = (data: any) => {
 | 
			
		||||
    dialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const editResource = async (data: any) => {
 | 
			
		||||
const onEditResource = async (data: any) => {
 | 
			
		||||
    const res = await resourceApi.detail.request({
 | 
			
		||||
        id: data.id,
 | 
			
		||||
    });
 | 
			
		||||
@@ -347,12 +347,12 @@ const editResource = async (data: any) => {
 | 
			
		||||
    state.dialogForm.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const valChange = () => {
 | 
			
		||||
const onValChange = () => {
 | 
			
		||||
    search();
 | 
			
		||||
    state.dialogForm.visible = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const changeStatus = async (data: any, status: any) => {
 | 
			
		||||
const onChangeStatus = async (data: any, status: any) => {
 | 
			
		||||
    await resourceApi.changeStatus.request({
 | 
			
		||||
        id: data.id,
 | 
			
		||||
        status: status,
 | 
			
		||||
 
 | 
			
		||||
@@ -9,11 +9,11 @@
 | 
			
		||||
        >
 | 
			
		||||
            <page-table ref="pageTableRef" :page-api="roleApi.roleAccounts" :search-items="searchItems" v-model:query-form="query" :columns="columns" lazy>
 | 
			
		||||
                <template #tableHeader>
 | 
			
		||||
                    <el-button v-auth="perms.saveAccountRole" type="primary" icon="plus" @click="showAddAccount()">{{ $t('common.add') }}</el-button>
 | 
			
		||||
                    <el-button v-auth="perms.saveAccountRole" type="primary" icon="plus" @click="onShowAddAccount()">{{ $t('common.add') }}</el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
 | 
			
		||||
                <template #action="{ data }">
 | 
			
		||||
                    <el-button link v-if="actionBtns[perms.saveAccountRole]" @click="relateAccount(-1, data.accountId)" icon="delete" type="danger">
 | 
			
		||||
                    <el-button link v-if="actionBtns[perms.saveAccountRole]" @click="onRelateAccount(-1, data.accountId)" icon="delete" type="danger">
 | 
			
		||||
                        {{ $t('common.remove') }}
 | 
			
		||||
                    </el-button>
 | 
			
		||||
                </template>
 | 
			
		||||
@@ -22,7 +22,7 @@
 | 
			
		||||
            <el-dialog
 | 
			
		||||
                width="400px"
 | 
			
		||||
                :title="$t('system.role.addAccount')"
 | 
			
		||||
                :before-close="cancelAddAccount"
 | 
			
		||||
                :before-close="onCancelAddAccount"
 | 
			
		||||
                v-model="addAccountDialog.visible"
 | 
			
		||||
                :destroy-on-close="true"
 | 
			
		||||
            >
 | 
			
		||||
@@ -31,8 +31,8 @@
 | 
			
		||||
                </el-form>
 | 
			
		||||
                <template #footer>
 | 
			
		||||
                    <div class="dialog-footer">
 | 
			
		||||
                        <el-button @click="cancelAddAccount()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                        <el-button @click="relateAccount(1, addAccountDialog.accountId)" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                        <el-button @click="onCancelAddAccount()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                        <el-button @click="onRelateAccount(1, addAccountDialog.accountId)" type="primary">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </template>
 | 
			
		||||
            </el-dialog>
 | 
			
		||||
@@ -107,7 +107,7 @@ const searchRoleAccount = () => {
 | 
			
		||||
    pageTableRef.value.search();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const relateAccount = async (relateType: number, accountId: number) => {
 | 
			
		||||
const onRelateAccount = async (relateType: number, accountId: number) => {
 | 
			
		||||
    await accountApi.saveRole.request({
 | 
			
		||||
        id: accountId,
 | 
			
		||||
        roleId: props.role?.id,
 | 
			
		||||
@@ -116,16 +116,16 @@ const relateAccount = async (relateType: number, accountId: number) => {
 | 
			
		||||
    useI18nOperateSuccessMsg();
 | 
			
		||||
    // 如果是新增账号,则关闭新增账号弹窗
 | 
			
		||||
    if (relateType == 1) {
 | 
			
		||||
        cancelAddAccount();
 | 
			
		||||
        onCancelAddAccount();
 | 
			
		||||
    }
 | 
			
		||||
    searchRoleAccount();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const showAddAccount = () => {
 | 
			
		||||
const onShowAddAccount = () => {
 | 
			
		||||
    state.addAccountDialog.visible = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancelAddAccount = () => {
 | 
			
		||||
const onCancelAddAccount = () => {
 | 
			
		||||
    state.addAccountDialog.accountId = null;
 | 
			
		||||
    state.addAccountDialog.accounts = [];
 | 
			
		||||
    state.addAccountDialog.visible = false;
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
        <el-dialog
 | 
			
		||||
            :title="$t('system.role.allocateMenuTitle', { roleName: roleInfo?.name })"
 | 
			
		||||
            v-model="visible"
 | 
			
		||||
            :before-close="cancel"
 | 
			
		||||
            :before-close="onCancel"
 | 
			
		||||
            :show-close="false"
 | 
			
		||||
            width="400px"
 | 
			
		||||
        >
 | 
			
		||||
@@ -26,8 +26,8 @@
 | 
			
		||||
            </el-tree>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button :loading="state.submiting" @click="cancel">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button :loading="state.submiting" type="primary" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button :loading="state.submiting" @click="onCancel">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button :loading="state.submiting" type="primary" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
@@ -88,7 +88,7 @@ watch(
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    let menuIds = menuTree.value.getCheckedKeys();
 | 
			
		||||
    let halfMenuIds = menuTree.value.getHalfCheckedKeys();
 | 
			
		||||
    let resources = [].concat(menuIds, halfMenuIds).join(',');
 | 
			
		||||
@@ -105,7 +105,7 @@ const btnOk = async () => {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    visible.value = false;
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <div>
 | 
			
		||||
        <el-dialog :title="title" v-model="visible" :show-close="false" :before-close="cancel" width="600px" :destroy-on-close="true">
 | 
			
		||||
            <el-form ref="roleForm" :model="form" :rules="rules" label-width="auto">
 | 
			
		||||
        <el-dialog :title="title" v-model="visible" :show-close="false" :before-close="onCancel" width="600px" :destroy-on-close="true">
 | 
			
		||||
            <el-form ref="roleFormRef" :model="form" :rules="rules" label-width="auto">
 | 
			
		||||
                <el-form-item prop="name" :label="$t('system.role.roleName')" required>
 | 
			
		||||
                    <el-input v-model="form.name" auto-complete="off"></el-input>
 | 
			
		||||
                </el-form-item>
 | 
			
		||||
@@ -22,8 +22,8 @@
 | 
			
		||||
            </el-form>
 | 
			
		||||
            <template #footer>
 | 
			
		||||
                <div class="dialog-footer">
 | 
			
		||||
                    <el-button @click="cancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="btnOk">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                    <el-button @click="onCancel()">{{ $t('common.cancel') }}</el-button>
 | 
			
		||||
                    <el-button type="primary" :loading="saveBtnLoading" @click="onConfirm">{{ $t('common.confirm') }}</el-button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </template>
 | 
			
		||||
        </el-dialog>
 | 
			
		||||
@@ -31,7 +31,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { ref, toRefs, reactive, watchEffect } from 'vue';
 | 
			
		||||
import { toRefs, reactive, watchEffect, useTemplateRef } from 'vue';
 | 
			
		||||
import { roleApi } from '../api';
 | 
			
		||||
import { RoleStatusEnum } from '../enums';
 | 
			
		||||
import EnumSelect from '@/components/enumselect/EnumSelect.vue';
 | 
			
		||||
@@ -58,7 +58,8 @@ const visible = defineModel<boolean>('visible', { default: false });
 | 
			
		||||
//定义事件
 | 
			
		||||
const emit = defineEmits(['cancel', 'val-change']);
 | 
			
		||||
 | 
			
		||||
const roleForm: any = ref(null);
 | 
			
		||||
const roleFormRef: any = useTemplateRef('roleFormRef');
 | 
			
		||||
 | 
			
		||||
const state = reactive({
 | 
			
		||||
    form: {
 | 
			
		||||
        id: null,
 | 
			
		||||
@@ -84,17 +85,17 @@ watchEffect(() => {
 | 
			
		||||
    }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const cancel = () => {
 | 
			
		||||
const onCancel = () => {
 | 
			
		||||
    visible.value = false;
 | 
			
		||||
    // 若父组件有取消事件,则调用
 | 
			
		||||
    emit('cancel');
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnOk = async () => {
 | 
			
		||||
    await useI18nFormValidate(roleForm);
 | 
			
		||||
const onConfirm = async () => {
 | 
			
		||||
    await useI18nFormValidate(roleFormRef);
 | 
			
		||||
    await saveRoleExec();
 | 
			
		||||
    emit('val-change', state.form);
 | 
			
		||||
    cancel();
 | 
			
		||||
    onCancel();
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
<style lang="scss"></style>
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func (a *AccountLogin) ReqConfs() *req.Confs {
 | 
			
		||||
 | 
			
		||||
// @router /auth/accounts/login [post]
 | 
			
		||||
func (a *AccountLogin) Login(rc *req.Ctx) {
 | 
			
		||||
	loginForm := req.BindJsonAndValid(rc, new(form.LoginForm))
 | 
			
		||||
	loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
 | 
			
		||||
	accountLoginSecurity := config.GetAccountLoginSecurity()
 | 
			
		||||
@@ -96,8 +96,7 @@ type OtpVerifyInfo struct {
 | 
			
		||||
 | 
			
		||||
// OTP双因素校验
 | 
			
		||||
func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
 | 
			
		||||
	otpVerify := new(form.OtpVerfiy)
 | 
			
		||||
	req.BindJsonAndValid(rc, otpVerify)
 | 
			
		||||
	otpVerify := req.BindJsonAndValid[*form.OtpVerfiy](rc)
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
 | 
			
		||||
	tokenKey := fmt.Sprintf("otp:token:%s", otpVerify.OtpToken)
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func (a *LdapLogin) GetLdapEnabled(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// @router /auth/ldap/login [post]
 | 
			
		||||
func (a *LdapLogin) Login(rc *req.Ctx) {
 | 
			
		||||
	loginForm := req.BindJsonAndValid(rc, new(form.LoginForm))
 | 
			
		||||
	loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
	accountLoginSecurity := config.GetAccountLoginSecurity()
 | 
			
		||||
	// 判断是否有开启登录验证码校验
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ func (d *Db) ReqConfs() *req.Confs {
 | 
			
		||||
 | 
			
		||||
// @router /api/dbs [get]
 | 
			
		||||
func (d *Db) Dbs(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DbQuery](rc, new(entity.DbQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DbQuery](rc)
 | 
			
		||||
 | 
			
		||||
	// 不存在可访问标签id,即没有可操作数据
 | 
			
		||||
	tags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
@@ -115,9 +115,7 @@ func (d *Db) Dbs(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Db) Save(rc *req.Ctx) {
 | 
			
		||||
	form := &form.DbForm{}
 | 
			
		||||
	db := req.BindJsonAndCopyTo[*entity.Db](rc, form, new(entity.Db))
 | 
			
		||||
 | 
			
		||||
	form, db := req.BindJsonAndCopyTo[*form.DbForm, *entity.Db](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
	biz.ErrIsNil(d.dbApp.SaveDb(rc.MetaCtx, db))
 | 
			
		||||
@@ -137,7 +135,7 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
 | 
			
		||||
/**  数据库操作相关、执行sql等   ***/
 | 
			
		||||
 | 
			
		||||
func (d *Db) ExecSql(rc *req.Ctx) {
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.DbSqlExecForm))
 | 
			
		||||
	form := req.BindJsonAndValid[*form.DbSqlExecForm](rc)
 | 
			
		||||
 | 
			
		||||
	ctx, cancel := context.WithTimeout(rc.MetaCtx, time.Duration(config.GetDbms().SqlExecTl)*time.Second)
 | 
			
		||||
	defer cancel()
 | 
			
		||||
@@ -351,8 +349,7 @@ func (d *Db) GetSchemas(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Db) CopyTable(rc *req.Ctx) {
 | 
			
		||||
	form := &form.DbCopyTableForm{}
 | 
			
		||||
	copy := req.BindJsonAndCopyTo[*dbi.DbCopyTable](rc, form, new(dbi.DbCopyTable))
 | 
			
		||||
	form, copy := req.BindJsonAndCopyTo[*form.DbCopyTableForm, *dbi.DbCopyTable](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := d.dbApp.GetDbConn(rc.MetaCtx, form.Id, form.Db)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "copy table error: %s")
 | 
			
		||||
 
 | 
			
		||||
@@ -50,22 +50,21 @@ func (d *DataSyncTask) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DataSyncTask) Tasks(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DataSyncTaskQuery](rc, new(entity.DataSyncTaskQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DataSyncTaskQuery](rc)
 | 
			
		||||
	res, err := d.dataSyncTaskApp.GetPageList(queryCond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	rc.ResData = model.PageResultConv[*entity.DataSyncTask, *vo.DataSyncTaskListVO](res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DataSyncTask) Logs(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.DataSyncLogQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DataSyncLogQuery](rc)
 | 
			
		||||
	res, err := d.dataSyncTaskApp.GetTaskLogList(queryCond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	rc.ResData = model.PageResultConv[*entity.DataSyncLog, *vo.DataSyncLogListVO](res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DataSyncTask) SaveTask(rc *req.Ctx) {
 | 
			
		||||
	form := &form.DataSyncTaskForm{}
 | 
			
		||||
	task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
 | 
			
		||||
	form, task := req.BindJsonAndCopyTo[*form.DataSyncTaskForm, *entity.DataSyncTask](rc)
 | 
			
		||||
 | 
			
		||||
	// 解码base64 sql
 | 
			
		||||
	sqlStr, err := utils.AesDecryptByLa(task.DataSql, rc.GetLoginAccount())
 | 
			
		||||
@@ -89,8 +88,7 @@ func (d *DataSyncTask) DeleteTask(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DataSyncTask) ChangeStatus(rc *req.Ctx) {
 | 
			
		||||
	form := &form.DataSyncTaskStatusForm{}
 | 
			
		||||
	task := req.BindJsonAndCopyTo[*entity.DataSyncTask](rc, form, new(entity.DataSyncTask))
 | 
			
		||||
	form, task := req.BindJsonAndCopyTo[*form.DataSyncTaskStatusForm, *entity.DataSyncTask](rc)
 | 
			
		||||
	_ = d.dataSyncTaskApp.UpdateById(rc.MetaCtx, task)
 | 
			
		||||
 | 
			
		||||
	if task.Status == entity.DataSyncTaskStatusEnable {
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ func (d *Instance) ReqConfs() *req.Confs {
 | 
			
		||||
// Instances 获取数据库实例信息
 | 
			
		||||
// @router /api/instances [get]
 | 
			
		||||
func (d *Instance) Instances(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.InstanceQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.InstanceQuery](rc)
 | 
			
		||||
 | 
			
		||||
	tags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
		TypePaths:     collx.AsArray(tagentity.NewTypePaths(tagentity.TagTypeDbInstance, tagentity.TagTypeAuthCert)),
 | 
			
		||||
@@ -90,17 +90,14 @@ func (d *Instance) Instances(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Instance) TestConn(rc *req.Ctx) {
 | 
			
		||||
	form := &form.InstanceForm{}
 | 
			
		||||
	instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
 | 
			
		||||
 | 
			
		||||
	form, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.DbInstance](rc)
 | 
			
		||||
	biz.ErrIsNil(d.instanceApp.TestConn(rc.MetaCtx, instance, form.AuthCerts[0]))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SaveInstance 保存数据库实例信息
 | 
			
		||||
// @router /api/instances [post]
 | 
			
		||||
func (d *Instance) SaveInstance(rc *req.Ctx) {
 | 
			
		||||
	form := &form.InstanceForm{}
 | 
			
		||||
	instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
 | 
			
		||||
	form, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.DbInstance](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	id, err := d.instanceApp.SaveDbInstance(rc.MetaCtx, &dto.SaveDbInstance{
 | 
			
		||||
@@ -135,8 +132,7 @@ func (d *Instance) DeleteInstance(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 获取数据库实例的所有数据库名
 | 
			
		||||
func (d *Instance) GetDatabaseNames(rc *req.Ctx) {
 | 
			
		||||
	form := &form.InstanceDbNamesForm{}
 | 
			
		||||
	instance := req.BindJsonAndCopyTo[*entity.DbInstance](rc, form, new(entity.DbInstance))
 | 
			
		||||
	form, instance := req.BindJsonAndCopyTo[*form.InstanceDbNamesForm, *entity.DbInstance](rc)
 | 
			
		||||
	res, err := d.instanceApp.GetDatabases(rc.MetaCtx, instance, form.AuthCert)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
 
 | 
			
		||||
@@ -30,8 +30,7 @@ func (d *DbSql) ReqConfs() *req.Confs {
 | 
			
		||||
 | 
			
		||||
// @router /api/db/:dbId/sql [post]
 | 
			
		||||
func (d *DbSql) SaveSql(rc *req.Ctx) {
 | 
			
		||||
	dbSqlForm := &form.DbSqlSaveForm{}
 | 
			
		||||
	req.BindJsonAndValid(rc, dbSqlForm)
 | 
			
		||||
	dbSqlForm := req.BindJsonAndValid[*form.DbSqlSaveForm](rc)
 | 
			
		||||
	rc.ReqParam = dbSqlForm
 | 
			
		||||
 | 
			
		||||
	dbId := getDbId(rc)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@ func (d *DbSqlExec) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbSqlExec) DbSqlExecs(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.DbSqlExecQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DbSqlExecQuery](rc)
 | 
			
		||||
	if statusStr := rc.Query("status"); statusStr != "" {
 | 
			
		||||
		queryCond.Status = collx.ArrayMap[string, int8](strings.Split(statusStr, ","), func(val string) int8 {
 | 
			
		||||
			return cast.ToInt8(val)
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ func (d *DbTransferTask) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbTransferTask) Tasks(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.DbTransferTaskQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DbTransferTaskQuery](rc)
 | 
			
		||||
 | 
			
		||||
	res, err := d.dbTransferTask.GetPageList(queryCond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -78,8 +78,7 @@ func (d *DbTransferTask) Tasks(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbTransferTask) SaveTask(rc *req.Ctx) {
 | 
			
		||||
	reqForm := &form.DbTransferTaskForm{}
 | 
			
		||||
	task := req.BindJsonAndCopyTo[*entity.DbTransferTask](rc, reqForm, new(entity.DbTransferTask))
 | 
			
		||||
	reqForm, task := req.BindJsonAndCopyTo[*form.DbTransferTaskForm, *entity.DbTransferTask](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = reqForm
 | 
			
		||||
	biz.ErrIsNil(d.dbTransferTask.Save(rc.MetaCtx, task))
 | 
			
		||||
@@ -98,8 +97,7 @@ func (d *DbTransferTask) DeleteTask(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbTransferTask) ChangeStatus(rc *req.Ctx) {
 | 
			
		||||
	form := &form.DbTransferTaskStatusForm{}
 | 
			
		||||
	task := req.BindJsonAndCopyTo[*entity.DbTransferTask](rc, form, new(entity.DbTransferTask))
 | 
			
		||||
	form, task := req.BindJsonAndCopyTo[*form.DbTransferTaskStatusForm, *entity.DbTransferTask](rc)
 | 
			
		||||
	_ = d.dbTransferTask.UpdateById(rc.MetaCtx, task)
 | 
			
		||||
 | 
			
		||||
	task, err := d.dbTransferTask.GetById(task.Id)
 | 
			
		||||
@@ -122,7 +120,7 @@ func (d *DbTransferTask) Stop(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbTransferTask) Files(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.DbTransferFileQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.DbTransferFileQuery](rc)
 | 
			
		||||
 | 
			
		||||
	res, err := d.dbTransferFile.GetPageList(queryCond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -142,7 +140,7 @@ func (d *DbTransferTask) FileDel(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *DbTransferTask) FileRun(rc *req.Ctx) {
 | 
			
		||||
	fm := req.BindJsonAndValid(rc, &form.DbTransferFileRunForm{})
 | 
			
		||||
	fm := req.BindJsonAndValid[*form.DbTransferFileRunForm](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = fm
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -277,7 +277,7 @@ func (d *dbSqlExecAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *fl
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	execSqlBizForm, err := jsonx.To(procinst.BizForm, new(FlowDbExecSqlBizForm))
 | 
			
		||||
	execSqlBizForm, err := jsonx.To[*FlowDbExecSqlBizForm](procinst.BizForm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ func (d *Instance) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Instance) Instances(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.InstanceQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.InstanceQuery](rc)
 | 
			
		||||
 | 
			
		||||
	// 只查询实例,兼容没有录入密码的实例
 | 
			
		||||
	instTags := d.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
@@ -92,8 +92,7 @@ func (d *Instance) Instances(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Instance) TestConn(rc *req.Ctx) {
 | 
			
		||||
	fm := &form.InstanceForm{}
 | 
			
		||||
	instance := req.BindJsonAndCopyTo[*entity.EsInstance](rc, fm, new(entity.EsInstance))
 | 
			
		||||
	fm, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.EsInstance](rc)
 | 
			
		||||
 | 
			
		||||
	var ac *tagentity.ResourceAuthCert
 | 
			
		||||
	if len(fm.AuthCerts) > 0 {
 | 
			
		||||
@@ -105,8 +104,7 @@ func (d *Instance) TestConn(rc *req.Ctx) {
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
}
 | 
			
		||||
func (d *Instance) SaveInstance(rc *req.Ctx) {
 | 
			
		||||
	fm := &form.InstanceForm{}
 | 
			
		||||
	instance := req.BindJsonAndCopyTo[*entity.EsInstance](rc, fm, new(entity.EsInstance))
 | 
			
		||||
	fm, instance := req.BindJsonAndCopyTo[*form.InstanceForm, *entity.EsInstance](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = fm
 | 
			
		||||
	id, err := d.inst.SaveInst(rc.MetaCtx, &dto.SaveEsInstance{
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ type InstanceForm struct {
 | 
			
		||||
	Host               string  `binding:"required" json:"host"`
 | 
			
		||||
	Port               int     `binding:"required" json:"port"`
 | 
			
		||||
	Version            string  `json:"version"`
 | 
			
		||||
	Remark             string `json:"remark"`
 | 
			
		||||
	Remark             *string `json:"remark"`
 | 
			
		||||
	SshTunnelMachineId int     `json:"sshTunnelMachineId"`
 | 
			
		||||
 | 
			
		||||
	AuthCerts    []*tagentity.ResourceAuthCert `json:"authCerts"` // 资产授权凭证信息列表
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,11 @@ type InstanceListVO struct {
 | 
			
		||||
	Host    *string `json:"host"`
 | 
			
		||||
	Port    *int    `json:"port"`
 | 
			
		||||
	Version *string `json:"version"`
 | 
			
		||||
	Remark  *string `json:"remark"`
 | 
			
		||||
 | 
			
		||||
	CreateTime *time.Time `json:"createTime"`
 | 
			
		||||
	Creator    *string    `json:"creator"`
 | 
			
		||||
	CreatorId  *int64     `json:"creatorId"`
 | 
			
		||||
 | 
			
		||||
	UpdateTime *time.Time `json:"updateTime"`
 | 
			
		||||
	Modifier   *string    `json:"modifier"`
 | 
			
		||||
	ModifierId *int64     `json:"modifierId"`
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ type EsInstance struct {
 | 
			
		||||
	Port               int     `json:"port"`
 | 
			
		||||
	Network            string  `json:"network" gorm:"size:20;"`
 | 
			
		||||
	Version            string  `json:"version" gorm:"size:50;"`
 | 
			
		||||
	AuthCertName       string `json:"authCertName" gorm:"size:255;"`
 | 
			
		||||
	Remark             *string `json:"remark" gorm:"size:255;"`
 | 
			
		||||
	SshTunnelMachineId int     `json:"sshTunnelMachineId"` // ssh隧道机器id
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -48,7 +48,7 @@ func (p *Procdef) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procdef) GetProcdefPage(rc *req.Ctx) {
 | 
			
		||||
	cond, page := req.BindQueryAndPage(rc, new(entity.Procdef))
 | 
			
		||||
	cond, page := req.BindQueryAndPage[*entity.Procdef](rc)
 | 
			
		||||
 | 
			
		||||
	res, err := p.procdefApp.GetPageList(cond, page)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -87,8 +87,7 @@ func (p *Procdef) GetProcdef(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Procdef) Save(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Procdef{}
 | 
			
		||||
	procdef := req.BindJsonAndCopyTo(rc, form, new(entity.Procdef))
 | 
			
		||||
	form, procdef := req.BindJsonAndCopyTo[*form.Procdef, *entity.Procdef](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	biz.ErrIsNil(a.procdefApp.SaveProcdef(rc.MetaCtx, &dto.SaveProcdef{
 | 
			
		||||
		Procdef:   procdef,
 | 
			
		||||
@@ -98,7 +97,7 @@ func (a *Procdef) Save(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (a *Procdef) SaveFlowDef(rc *req.Ctx) {
 | 
			
		||||
	form := req.BindJsonAndValid(rc, &form.ProcdefFlow{})
 | 
			
		||||
	form := req.BindJsonAndValid[*form.ProcdefFlow](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
	biz.ErrIsNil(a.procdefApp.SaveFlowDef(rc.MetaCtx, &dto.SaveFlowDef{
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ func (p *Procinst) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
 | 
			
		||||
	cond := req.BindQuery(rc, new(entity.ProcinstQuery))
 | 
			
		||||
	cond := req.BindQuery[*entity.ProcinstQuery](rc)
 | 
			
		||||
	// 非管理员只能获取自己申请的流程
 | 
			
		||||
	if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
 | 
			
		||||
		cond.CreatorId = laId
 | 
			
		||||
@@ -47,8 +47,7 @@ func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Procinst) ProcinstStart(rc *req.Ctx) {
 | 
			
		||||
	startForm := new(form.ProcinstStart)
 | 
			
		||||
	req.BindJsonAndValid(rc, startForm)
 | 
			
		||||
	startForm := req.BindJsonAndValid[*form.ProcinstStart](rc)
 | 
			
		||||
	_, err := p.procinstApp.StartProc(rc.MetaCtx, startForm.ProcdefId, &dto.StarProc{
 | 
			
		||||
		BizType: startForm.BizType,
 | 
			
		||||
		BizForm: jsonx.ToStr(startForm.BizForm),
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ func (p *ProcinstTask) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *ProcinstTask) GetTasks(rc *req.Ctx) {
 | 
			
		||||
	instTaskQuery := req.BindQuery(rc, new(entity.ProcinstTaskQuery))
 | 
			
		||||
	instTaskQuery := req.BindQuery[*entity.ProcinstTaskQuery](rc)
 | 
			
		||||
	if laId := rc.GetLoginAccount().Id; laId != consts.AdminId {
 | 
			
		||||
		// 赋值操作人为当前登录账号
 | 
			
		||||
		instTaskQuery.Assignee = fmt.Sprintf("%d", rc.GetLoginAccount().Id)
 | 
			
		||||
@@ -74,7 +74,7 @@ func (p *ProcinstTask) GetTasks(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *ProcinstTask) PassTask(rc *req.Ctx) {
 | 
			
		||||
	auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
 | 
			
		||||
	auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
 | 
			
		||||
	rc.ReqParam = auditForm
 | 
			
		||||
 | 
			
		||||
	la := rc.GetLoginAccount()
 | 
			
		||||
@@ -84,7 +84,7 @@ func (p *ProcinstTask) PassTask(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
 | 
			
		||||
	auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
 | 
			
		||||
	auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
 | 
			
		||||
	rc.ReqParam = auditForm
 | 
			
		||||
 | 
			
		||||
	la := rc.GetLoginAccount()
 | 
			
		||||
@@ -94,7 +94,7 @@ func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *ProcinstTask) BackTask(rc *req.Ctx) {
 | 
			
		||||
	auditForm := req.BindJsonAndValid(rc, new(form.ProcinstTaskAudit))
 | 
			
		||||
	auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
 | 
			
		||||
	rc.ReqParam = auditForm
 | 
			
		||||
	biz.ErrIsNil(p.procinstTaskApp.BackTask(rc.MetaCtx, dto.UserTaskOp{TaskId: auditForm.Id, Remark: auditForm.Remark}))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -104,7 +104,9 @@ func (e *executionAppImpl) MoveTo(ctx *ExecutionCtx, nextNode *entity.FlowNode)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 记录当前节点结束
 | 
			
		||||
	e.hisProcinstOpApp.RecordEnd(ctx, "copmpleted")
 | 
			
		||||
	if err := e.hisProcinstOpApp.RecordEnd(ctx, "copmpleted"); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 下一个节点为空,说明流程已结束
 | 
			
		||||
	if nextNode == nil {
 | 
			
		||||
@@ -163,7 +165,9 @@ func (e *executionAppImpl) executeNode(ctx *ExecutionCtx) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 节点开始操作记录
 | 
			
		||||
	e.hisProcinstOpApp.RecordStart(ctx)
 | 
			
		||||
	if err := e.hisProcinstOpApp.RecordStart(ctx); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 执行节点逻辑
 | 
			
		||||
	return node.Execute(ctx)
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ func (p *Procdef) GetFlowDef() *FlowDef {
 | 
			
		||||
	if p.FlowDef == "" {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	flow, err := jsonx.To(p.FlowDef, new(FlowDef))
 | 
			
		||||
	flow, err := jsonx.To[*FlowDef](p.FlowDef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("parse flow def failed", err)
 | 
			
		||||
		return flow
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ func (a *Procinst) SetEnd() {
 | 
			
		||||
 | 
			
		||||
// GetProcdefFlow 获取流程定义信息
 | 
			
		||||
func (p *Procinst) GetFlowDef() *FlowDef {
 | 
			
		||||
	flow, err := jsonx.To(p.FlowDef, new(FlowDef))
 | 
			
		||||
	flow, err := jsonx.To[*FlowDef](p.FlowDef)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		logx.ErrorTrace("parse procdef flow failed", err)
 | 
			
		||||
		return flow
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ type MachineCronJobForm struct {
 | 
			
		||||
type MachineCmdConfForm struct {
 | 
			
		||||
	Id       uint64              `json:"id"`
 | 
			
		||||
	Name     string              `json:"name"`
 | 
			
		||||
	Cmds     []string `json:"cmds"`     // 命令配置
 | 
			
		||||
	Cmds     model.Slice[string] `json:"cmds"`     // 命令配置
 | 
			
		||||
	Status   int8                `json:"execCmds"` // 状态
 | 
			
		||||
	Stratege string              `json:"stratege"` // 策略,空禁用
 | 
			
		||||
	Remark   string              `json:"remark"`   // 备注
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ func (m *Machine) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Machine) Machines(rc *req.Ctx) {
 | 
			
		||||
	condition := req.BindQuery(rc, new(entity.MachineQuery))
 | 
			
		||||
	condition := req.BindQuery[*entity.MachineQuery](rc)
 | 
			
		||||
 | 
			
		||||
	tags := m.tagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
		TypePaths:     collx.AsArray(tagentity.NewTypePaths(tagentity.TagTypeMachine, tagentity.TagTypeAuthCert)),
 | 
			
		||||
@@ -143,8 +143,7 @@ func (m *Machine) MachineStats(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 保存机器信息
 | 
			
		||||
func (m *Machine) SaveMachine(rc *req.Ctx) {
 | 
			
		||||
	machineForm := new(form.MachineForm)
 | 
			
		||||
	me := req.BindJsonAndCopyTo(rc, machineForm, new(entity.Machine))
 | 
			
		||||
	machineForm, me := req.BindJsonAndCopyTo[*form.MachineForm, *entity.Machine](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = machineForm
 | 
			
		||||
 | 
			
		||||
@@ -156,8 +155,7 @@ func (m *Machine) SaveMachine(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Machine) TestConn(rc *req.Ctx) {
 | 
			
		||||
	machineForm := new(form.MachineForm)
 | 
			
		||||
	me := req.BindJsonAndCopyTo(rc, machineForm, new(entity.Machine))
 | 
			
		||||
	machineForm, me := req.BindJsonAndCopyTo[*form.MachineForm, *entity.Machine](rc)
 | 
			
		||||
	// 测试连接
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.machineApp.TestConn(rc.MetaCtx, me, machineForm.AuthCerts[0]), "connection error: %s")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ func (mcc *MachineCmdConf) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCmdConf) MachineCmdConfs(rc *req.Ctx) {
 | 
			
		||||
	cond := req.BindQuery(rc, new(entity.MachineCmdConf))
 | 
			
		||||
	cond := req.BindQuery[*entity.MachineCmdConf](rc)
 | 
			
		||||
 | 
			
		||||
	var vos []*vo.MachineCmdConfVO
 | 
			
		||||
	err := m.machineCmdConfApp.ListByCondToAny(cond, &vos)
 | 
			
		||||
@@ -47,8 +47,7 @@ func (m *MachineCmdConf) MachineCmdConfs(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCmdConf) Save(rc *req.Ctx) {
 | 
			
		||||
	cmdForm := new(form.MachineCmdConfForm)
 | 
			
		||||
	mcj := req.BindJsonAndCopyTo[*entity.MachineCmdConf](rc, cmdForm, new(entity.MachineCmdConf))
 | 
			
		||||
	cmdForm, mcj := req.BindJsonAndCopyTo[*form.MachineCmdConfForm, *entity.MachineCmdConf](rc)
 | 
			
		||||
	rc.ReqParam = cmdForm
 | 
			
		||||
 | 
			
		||||
	err := m.machineCmdConfApp.SaveCmdConf(rc.MetaCtx, &dto.SaveMachineCmdConf{
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ func (mcj *MachineCronJob) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) MachineCronJobs(rc *req.Ctx) {
 | 
			
		||||
	cond, pageParam := req.BindQueryAndPage(rc, new(entity.MachineCronJob))
 | 
			
		||||
	cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJob](rc)
 | 
			
		||||
 | 
			
		||||
	pageRes, err := m.machineCronJobApp.GetPageList(cond, pageParam)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -62,8 +62,7 @@ func (m *MachineCronJob) MachineCronJobs(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) Save(rc *req.Ctx) {
 | 
			
		||||
	jobForm := new(form.MachineCronJobForm)
 | 
			
		||||
	mcj := req.BindJsonAndCopyTo[*entity.MachineCronJob](rc, jobForm, new(entity.MachineCronJob))
 | 
			
		||||
	jobForm, mcj := req.BindJsonAndCopyTo[*form.MachineCronJobForm, *entity.MachineCronJob](rc)
 | 
			
		||||
	rc.ReqParam = jobForm
 | 
			
		||||
 | 
			
		||||
	err := m.machineCronJobApp.SaveMachineCronJob(rc.MetaCtx, &dto.SaveMachineCronJob{
 | 
			
		||||
@@ -90,7 +89,7 @@ func (m *MachineCronJob) RunCronJob(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineCronJob) CronJobExecs(rc *req.Ctx) {
 | 
			
		||||
	cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJobExec](rc, new(entity.MachineCronJobExec))
 | 
			
		||||
	cond, pageParam := req.BindQueryAndPage[*entity.MachineCronJobExec](rc)
 | 
			
		||||
	res, err := m.machineCronJobApp.GetExecPageList(cond, pageParam)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
 
 | 
			
		||||
@@ -93,8 +93,7 @@ func (m *MachineFile) MachineFiles(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) SaveMachineFiles(rc *req.Ctx) {
 | 
			
		||||
	fileForm := new(form.MachineFileForm)
 | 
			
		||||
	entity := req.BindJsonAndCopyTo[*entity.MachineFile](rc, fileForm, new(entity.MachineFile))
 | 
			
		||||
	fileForm, entity := req.BindJsonAndCopyTo[*form.MachineFileForm, *entity.MachineFile](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = fileForm
 | 
			
		||||
	biz.ErrIsNil(m.machineFileApp.Save(rc.MetaCtx, entity))
 | 
			
		||||
@@ -107,7 +106,7 @@ func (m *MachineFile) DeleteFile(rc *req.Ctx) {
 | 
			
		||||
/***      sftp相关操作      */
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) CreateFile(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindJsonAndValid(rc, new(form.CreateFileForm))
 | 
			
		||||
	opForm := req.BindJsonAndValid[*form.CreateFileForm](rc)
 | 
			
		||||
	path := opForm.Path
 | 
			
		||||
 | 
			
		||||
	attrs := collx.Kvs("path", path)
 | 
			
		||||
@@ -126,7 +125,7 @@ func (m *MachineFile) CreateFile(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindQuery(rc, new(dto.MachineFileOp))
 | 
			
		||||
	opForm := req.BindQuery[*dto.MachineFileOp](rc)
 | 
			
		||||
	readPath := opForm.Path
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
 | 
			
		||||
@@ -158,7 +157,7 @@ func (m *MachineFile) ReadFileContent(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) DownloadFile(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindQuery(rc, new(dto.MachineFileOp))
 | 
			
		||||
	opForm := req.BindQuery[*dto.MachineFileOp](rc)
 | 
			
		||||
 | 
			
		||||
	readPath := opForm.Path
 | 
			
		||||
 | 
			
		||||
@@ -186,7 +185,7 @@ func (m *MachineFile) DownloadFile(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) GetDirEntry(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindQuery(rc, new(dto.MachineFileOp))
 | 
			
		||||
	opForm := req.BindQuery[*dto.MachineFileOp](rc)
 | 
			
		||||
	readPath := opForm.Path
 | 
			
		||||
	rc.ReqParam = fmt.Sprintf("path: %s", readPath)
 | 
			
		||||
 | 
			
		||||
@@ -225,7 +224,7 @@ func (m *MachineFile) GetDirEntry(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) GetDirSize(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindQuery(rc, new(dto.MachineFileOp))
 | 
			
		||||
	opForm := req.BindQuery[*dto.MachineFileOp](rc)
 | 
			
		||||
 | 
			
		||||
	size, err := m.machineFileApp.GetDirSize(rc.MetaCtx, opForm)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -233,14 +232,14 @@ func (m *MachineFile) GetDirSize(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) GetFileStat(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindQuery(rc, new(dto.MachineFileOp))
 | 
			
		||||
	opForm := req.BindQuery[*dto.MachineFileOp](rc)
 | 
			
		||||
	res, err := m.machineFileApp.FileStat(rc.MetaCtx, opForm)
 | 
			
		||||
	biz.ErrIsNil(err, res)
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) WriteFileContent(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindJsonAndValid(rc, new(form.WriteFileContentForm))
 | 
			
		||||
	opForm := req.BindJsonAndValid[*form.WriteFileContentForm](rc)
 | 
			
		||||
	path := opForm.Path
 | 
			
		||||
 | 
			
		||||
	mi, err := m.machineFileApp.WriteFileContent(rc.MetaCtx, opForm.MachineFileOp, []byte(opForm.Content))
 | 
			
		||||
@@ -401,7 +400,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) RemoveFile(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindJsonAndValid(rc, new(form.RemoveFileForm))
 | 
			
		||||
	opForm := req.BindJsonAndValid[*form.RemoveFileForm](rc)
 | 
			
		||||
 | 
			
		||||
	mi, err := m.machineFileApp.RemoveFile(rc.MetaCtx, opForm.MachineFileOp, opForm.Paths...)
 | 
			
		||||
	rc.ReqParam = collx.Kvs("machine", mi, "path", opForm)
 | 
			
		||||
@@ -409,21 +408,21 @@ func (m *MachineFile) RemoveFile(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) CopyFile(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindJsonAndValid(rc, new(form.CopyFileForm))
 | 
			
		||||
	opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
 | 
			
		||||
	mi, err := m.machineFileApp.Copy(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "file copy error: %s")
 | 
			
		||||
	rc.ReqParam = collx.Kvs("machine", mi, "cp", opForm)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) MvFile(rc *req.Ctx) {
 | 
			
		||||
	opForm := req.BindJsonAndValid(rc, new(form.CopyFileForm))
 | 
			
		||||
	opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
 | 
			
		||||
	mi, err := m.machineFileApp.Mv(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
 | 
			
		||||
	rc.ReqParam = collx.Kvs("machine", mi, "mv", opForm)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "file move error: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineFile) Rename(rc *req.Ctx) {
 | 
			
		||||
	renameForm := req.BindJsonAndValid(rc, new(form.RenameForm))
 | 
			
		||||
	renameForm := req.BindJsonAndValid[*form.RenameForm](rc)
 | 
			
		||||
	mi, err := m.machineFileApp.Rename(rc.MetaCtx, renameForm.MachineFileOp, renameForm.Newname)
 | 
			
		||||
	rc.ReqParam = collx.Kvs("machine", mi, "rename", renameForm)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "file rename error: %s")
 | 
			
		||||
 
 | 
			
		||||
@@ -46,8 +46,7 @@ func (m *MachineScript) MachineScripts(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MachineScript) SaveMachineScript(rc *req.Ctx) {
 | 
			
		||||
	form := new(form.MachineScriptForm)
 | 
			
		||||
	machineScript := req.BindJsonAndCopyTo(rc, form, new(entity.MachineScript))
 | 
			
		||||
	form, machineScript := req.BindJsonAndCopyTo[*form.MachineScriptForm, *entity.MachineScript](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	biz.ErrIsNil(m.machineScriptApp.Save(rc.MetaCtx, machineScript))
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ type MachineCmdConfVO struct {
 | 
			
		||||
	model.Model
 | 
			
		||||
 | 
			
		||||
	Name     string              `json:"name"`
 | 
			
		||||
	Cmds     model.Slice[string] `json:"cmds"`     // 命令配置
 | 
			
		||||
	Cmds     model.Slice[string] `json:"cmds" gorm:"type:varchar"` // 命令配置,要加gorm标签才会正确解析model.Slice
 | 
			
		||||
	Status   int8                `json:"execCmds"`                 // 状态
 | 
			
		||||
	Stratege string              `json:"stratege"`                 // 策略,空禁用
 | 
			
		||||
	Remark   string              `json:"remark"`                   // 备注
 | 
			
		||||
 
 | 
			
		||||
@@ -20,5 +20,5 @@ func GetMachineStats(machineId uint64) (*mcm.Stats, error) {
 | 
			
		||||
	if cacheStr == "" {
 | 
			
		||||
		return nil, errors.New("不存在该值")
 | 
			
		||||
	}
 | 
			
		||||
	return jsonx.To(cacheStr, new(mcm.Stats))
 | 
			
		||||
	return jsonx.To[*mcm.Stats](cacheStr)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ func (ma *Mongo) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) Mongos(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.MongoQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.MongoQuery](rc)
 | 
			
		||||
 | 
			
		||||
	// 不存在可访问标签id,即没有可操作数据
 | 
			
		||||
	tags := m.tagTreeApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
@@ -95,14 +95,12 @@ func (m *Mongo) Mongos(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) TestConn(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Mongo{}
 | 
			
		||||
	mongo := req.BindJsonAndCopyTo[*entity.Mongo](rc, form, new(entity.Mongo))
 | 
			
		||||
	_, mongo := req.BindJsonAndCopyTo[*form.Mongo, *entity.Mongo](rc)
 | 
			
		||||
	biz.ErrIsNilAppendErr(m.mongoApp.TestConn(mongo), "connection error: %s")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) Save(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Mongo{}
 | 
			
		||||
	mongo := req.BindJsonAndCopyTo[*entity.Mongo](rc, form, new(entity.Mongo))
 | 
			
		||||
	form, mongo := req.BindJsonAndCopyTo[*form.Mongo, *entity.Mongo](rc)
 | 
			
		||||
 | 
			
		||||
	// 密码脱敏记录日志
 | 
			
		||||
	form.Uri = func(str string) string {
 | 
			
		||||
@@ -148,8 +146,7 @@ func (m *Mongo) Collections(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) RunCommand(rc *req.Ctx) {
 | 
			
		||||
	commandForm := new(form.MongoRunCommand)
 | 
			
		||||
	req.BindJsonAndValid(rc, commandForm)
 | 
			
		||||
	commandForm := req.BindJsonAndValid[*form.MongoRunCommand](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -179,7 +176,7 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) FindCommand(rc *req.Ctx) {
 | 
			
		||||
	commandForm := req.BindJsonAndValid(rc, new(form.MongoFindCommand))
 | 
			
		||||
	commandForm := req.BindJsonAndValid[*form.MongoFindCommand](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -214,7 +211,7 @@ func (m *Mongo) FindCommand(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
 | 
			
		||||
	commandForm := req.BindJsonAndValid(rc, new(form.MongoUpdateByIdCommand))
 | 
			
		||||
	commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -238,7 +235,7 @@ func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
 | 
			
		||||
	commandForm := req.BindJsonAndValid(rc, new(form.MongoUpdateByIdCommand))
 | 
			
		||||
	commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -261,7 +258,7 @@ func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mongo) InsertOneCommand(rc *req.Ctx) {
 | 
			
		||||
	commandForm := req.BindJsonAndValid(rc, new(form.MongoInsertCommand))
 | 
			
		||||
	commandForm := req.BindJsonAndValid[*form.MongoInsertCommand](rc)
 | 
			
		||||
 | 
			
		||||
	conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -36,9 +36,8 @@ func (m *MsgChannel) GetMsgChannels(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MsgChannel) SaveMsgChannels(rc *req.Ctx) {
 | 
			
		||||
	form := &form.MsgChannel{}
 | 
			
		||||
	form, channel := req.BindJsonAndCopyTo[*form.MsgChannel, *entity.MsgChannel](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	channel := req.BindJsonAndCopyTo(rc, form, new(entity.MsgChannel))
 | 
			
		||||
	err := m.msgChannelApp.SaveChannel(rc.MetaCtx, channel)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,9 +57,8 @@ func (m *MsgTmpl) GetMsgTmplChannels(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *MsgTmpl) SaveMsgTmpl(rc *req.Ctx) {
 | 
			
		||||
	form := &form.MsgTmpl{}
 | 
			
		||||
	form, channel := req.BindJsonAndCopyTo[*form.MsgTmpl, *dto.MsgTmplSave](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	channel := req.BindJsonAndCopyTo(rc, form, new(dto.MsgTmplSave))
 | 
			
		||||
	biz.ErrIsNil(m.msgTmplApp.SaveTmpl(rc.MetaCtx, channel))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -75,7 +74,7 @@ func (m *MsgTmpl) DelMsgTmpls(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
func (m *MsgTmpl) SendMsg(rc *req.Ctx) {
 | 
			
		||||
	code := rc.PathParam("code")
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.SendMsg))
 | 
			
		||||
	form := req.BindJsonAndValid[*form.SendMsg](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,8 +11,7 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (r *Redis) RunCmd(rc *req.Ctx) {
 | 
			
		||||
	var cmdReq form.RunCmdForm
 | 
			
		||||
	runCmdParam := req.BindJsonAndCopyTo(rc, &cmdReq, new(dto.RunCmd))
 | 
			
		||||
	cmdReq, runCmdParam := req.BindJsonAndCopyTo[*form.RunCmdForm, *dto.RunCmd](rc)
 | 
			
		||||
	biz.IsTrue(len(cmdReq.Cmd) > 0, "redis cmd cannot be empty")
 | 
			
		||||
 | 
			
		||||
	redisConn := r.getRedisConn(rc)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@ import (
 | 
			
		||||
func (r *Redis) ScanKeys(rc *req.Ctx) {
 | 
			
		||||
	ri := r.getRedisConn(rc)
 | 
			
		||||
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.RedisScanForm))
 | 
			
		||||
	form := req.BindJsonAndValid[*form.RedisScanForm](rc)
 | 
			
		||||
 | 
			
		||||
	cmd := ri.GetCmdable()
 | 
			
		||||
	ctx := context.Background()
 | 
			
		||||
 
 | 
			
		||||
@@ -60,7 +60,7 @@ func (rs *Redis) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Redis) RedisList(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.RedisQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.RedisQuery](rc)
 | 
			
		||||
 | 
			
		||||
	// 不存在可访问标签id,即没有可操作数据
 | 
			
		||||
	tags := r.tagApp.GetAccountTags(rc.GetLoginAccount().Id, &tagentity.TagTreeQuery{
 | 
			
		||||
@@ -87,8 +87,7 @@ func (r *Redis) RedisList(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Redis) TestConn(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Redis{}
 | 
			
		||||
	redis := req.BindJsonAndCopyTo[*entity.Redis](rc, form, new(entity.Redis))
 | 
			
		||||
	form, redis := req.BindJsonAndCopyTo[*form.Redis, *entity.Redis](rc)
 | 
			
		||||
 | 
			
		||||
	authCert := &tagentity.ResourceAuthCert{
 | 
			
		||||
		Username:       form.Username,
 | 
			
		||||
@@ -110,8 +109,7 @@ func (r *Redis) TestConn(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Redis) Save(rc *req.Ctx) {
 | 
			
		||||
	form := &form.Redis{}
 | 
			
		||||
	redis := req.BindJsonAndCopyTo[*entity.Redis](rc, form, new(entity.Redis))
 | 
			
		||||
	form, redis := req.BindJsonAndCopyTo[*form.Redis, *entity.Redis](rc)
 | 
			
		||||
 | 
			
		||||
	redisParam := &dto.SaveRedis{
 | 
			
		||||
		Redis:        redis,
 | 
			
		||||
 
 | 
			
		||||
@@ -253,7 +253,7 @@ func (r *redisAppImpl) FlowBizHandle(ctx context.Context, bizHandleParam *flowap
 | 
			
		||||
		return nil, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	runCmdParam, err := jsonx.To(procinst.BizForm, new(FlowRedisRunCmdBizForm))
 | 
			
		||||
	runCmdParam, err := jsonx.To[*FlowRedisRunCmdBizForm](procinst.BizForm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, errorx.NewBiz("failed to parse the business form information: %s", err.Error())
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ func (a *Account) GetPermissions(rc *req.Ctx) {
 | 
			
		||||
func (a *Account) ChangePassword(rc *req.Ctx) {
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.AccountChangePasswordForm))
 | 
			
		||||
	form := req.BindJsonAndValid[*form.AccountChangePasswordForm](rc)
 | 
			
		||||
 | 
			
		||||
	originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true)
 | 
			
		||||
	biz.ErrIsNilAppendErr(err, "Wrong to decrypt old password: %s")
 | 
			
		||||
@@ -145,9 +145,10 @@ func (a *Account) AccountInfo(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 更新个人账号信息
 | 
			
		||||
func (a *Account) UpdateAccount(rc *req.Ctx) {
 | 
			
		||||
	updateAccount := req.BindJsonAndCopyTo[*entity.Account](rc, new(form.AccountUpdateForm), new(entity.Account))
 | 
			
		||||
	form, updateAccount := req.BindJsonAndCopyTo[*form.AccountUpdateForm, *entity.Account](rc)
 | 
			
		||||
	// 账号id为登录者账号
 | 
			
		||||
	updateAccount.Id = rc.GetLoginAccount().Id
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
	ctx := rc.MetaCtx
 | 
			
		||||
	if updateAccount.Password != "" {
 | 
			
		||||
@@ -210,8 +211,7 @@ func (a *Account) AccountDetail(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// @router /accounts
 | 
			
		||||
func (a *Account) SaveAccount(rc *req.Ctx) {
 | 
			
		||||
	form := &form.AccountCreateForm{}
 | 
			
		||||
	account := req.BindJsonAndCopyTo(rc, form, new(entity.Account))
 | 
			
		||||
	form, account := req.BindJsonAndCopyTo[*form.AccountCreateForm, *entity.Account](rc)
 | 
			
		||||
 | 
			
		||||
	form.Password = "*****"
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
@@ -307,7 +307,7 @@ func (a *Account) AccountResources(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 关联账号角色
 | 
			
		||||
func (a *Account) RelateRole(rc *req.Ctx) {
 | 
			
		||||
	form := req.BindJsonAndValid(rc, new(form.AccountRoleForm))
 | 
			
		||||
	form := req.BindJsonAndValid[*form.AccountRoleForm](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	biz.ErrIsNil(a.roleApp.RelateAccountRole(rc.MetaCtx, form.Id, form.RoleId, consts.AccountRoleRelateType(form.RelateType)))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -55,8 +55,7 @@ func (c *Config) GetConfigValueByKey(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) SaveConfig(rc *req.Ctx) {
 | 
			
		||||
	form := &form.ConfigForm{}
 | 
			
		||||
	config := req.BindJsonAndCopyTo(rc, form, new(entity.Config))
 | 
			
		||||
	form, config := req.BindJsonAndCopyTo[*form.ConfigForm, *entity.Config](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
	biz.ErrIsNil(c.configApp.Save(rc.MetaCtx, config))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -50,8 +50,7 @@ func (r *Resource) GetById(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Resource) SaveResource(rc *req.Ctx) {
 | 
			
		||||
	form := new(form.ResourceForm)
 | 
			
		||||
	entity := req.BindJsonAndCopyTo(rc, form, new(entity.Resource))
 | 
			
		||||
	form, entity := req.BindJsonAndCopyTo[*form.ResourceForm, *entity.Resource](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ func (r *Role) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Role) Roles(rc *req.Ctx) {
 | 
			
		||||
	cond := req.BindQuery(rc, new(entity.RoleQuery))
 | 
			
		||||
	cond := req.BindQuery[*entity.RoleQuery](rc)
 | 
			
		||||
 | 
			
		||||
	notIdsStr := rc.Query("notIds")
 | 
			
		||||
	if notIdsStr != "" {
 | 
			
		||||
@@ -61,8 +61,7 @@ func (r *Role) Roles(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 保存角色信息
 | 
			
		||||
func (r *Role) SaveRole(rc *req.Ctx) {
 | 
			
		||||
	form := &form.RoleForm{}
 | 
			
		||||
	role := req.BindJsonAndCopyTo(rc, form, new(entity.Role))
 | 
			
		||||
	form, role := req.BindJsonAndCopyTo[*form.RoleForm, *entity.Role](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
	r.roleApp.SaveRole(rc.MetaCtx, role)
 | 
			
		||||
@@ -93,8 +92,7 @@ func (r *Role) RoleResource(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 保存角色资源
 | 
			
		||||
func (r *Role) SaveResource(rc *req.Ctx) {
 | 
			
		||||
	var form form.RoleResourceForm
 | 
			
		||||
	req.BindJsonAndValid(rc, &form)
 | 
			
		||||
	form := req.BindJsonAndValid[*form.RoleResourceForm](rc)
 | 
			
		||||
	rc.ReqParam = form
 | 
			
		||||
 | 
			
		||||
	// 将,拼接的字符串进行切割并转换
 | 
			
		||||
@@ -107,7 +105,7 @@ func (r *Role) SaveResource(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 查看角色关联的用户
 | 
			
		||||
func (r *Role) RoleAccount(rc *req.Ctx) {
 | 
			
		||||
	cond := req.BindQuery(rc, new(entity.RoleAccountQuery))
 | 
			
		||||
	cond := req.BindQuery[*entity.RoleAccountQuery](rc)
 | 
			
		||||
	cond.RoleId = uint64(rc.PathParamInt("id"))
 | 
			
		||||
	res, err := r.roleApp.GetRoleAccountPage(cond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,7 @@ func (s *Syslog) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *Syslog) Syslogs(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.SysLogQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.SysLogQuery](rc)
 | 
			
		||||
	res, err := r.syslogApp.GetPageList(queryCond, "create_time DESC")
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
	rc.ResData = res
 | 
			
		||||
 
 | 
			
		||||
@@ -72,8 +72,7 @@ func (r *ResourceAuthCert) GetCompleteAuthCert(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *ResourceAuthCert) SaveAuthCert(rc *req.Ctx) {
 | 
			
		||||
	acForm := &form.AuthCertForm{}
 | 
			
		||||
	ac := req.BindJsonAndCopyTo(rc, acForm, new(entity.ResourceAuthCert))
 | 
			
		||||
	acForm, ac := req.BindJsonAndCopyTo[*form.AuthCertForm, *entity.ResourceAuthCert](rc)
 | 
			
		||||
 | 
			
		||||
	// 脱敏记录日志
 | 
			
		||||
	acForm.Ciphertext = "***"
 | 
			
		||||
 
 | 
			
		||||
@@ -119,8 +119,7 @@ func (p *TagTree) ListByQuery(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *TagTree) SaveTagTree(rc *req.Ctx) {
 | 
			
		||||
	tagForm := &form.TagTree{}
 | 
			
		||||
	tagTree := req.BindJsonAndCopyTo(rc, tagForm, new(entity.TagTree))
 | 
			
		||||
	tagForm, tagTree := req.BindJsonAndCopyTo[*form.TagTree, *entity.TagTree](rc)
 | 
			
		||||
 | 
			
		||||
	rc.ReqParam = fmt.Sprintf("tagTreeId: %d, tagName: %s, code: %s", tagTree.Id, tagTree.Name, tagTree.Code)
 | 
			
		||||
 | 
			
		||||
@@ -132,8 +131,7 @@ func (p *TagTree) DelTagTree(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *TagTree) MovingTag(rc *req.Ctx) {
 | 
			
		||||
	movingForm := &form.MovingTag{}
 | 
			
		||||
	req.BindJsonAndValid(rc, movingForm)
 | 
			
		||||
	movingForm := req.BindJsonAndValid[*form.MovingTag](rc)
 | 
			
		||||
	rc.ReqParam = movingForm
 | 
			
		||||
	biz.ErrIsNil(p.tagTreeApp.MovingTag(rc.MetaCtx, movingForm.FromPath, movingForm.ToPath))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ func (t *Team) ReqConfs() *req.Confs {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Team) GetTeams(rc *req.Ctx) {
 | 
			
		||||
	queryCond := req.BindQuery(rc, new(entity.TeamQuery))
 | 
			
		||||
	queryCond := req.BindQuery[*entity.TeamQuery](rc)
 | 
			
		||||
 | 
			
		||||
	res, err := p.teamApp.GetPageList(queryCond)
 | 
			
		||||
	biz.ErrIsNil(err)
 | 
			
		||||
@@ -60,7 +60,7 @@ func (p *Team) GetTeams(rc *req.Ctx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Team) SaveTeam(rc *req.Ctx) {
 | 
			
		||||
	team := req.BindJsonAndValid(rc, new(dto.SaveTeam))
 | 
			
		||||
	team := req.BindJsonAndValid[*dto.SaveTeam](rc)
 | 
			
		||||
	rc.ReqParam = team
 | 
			
		||||
	biz.ErrIsNil(p.teamApp.SaveTeam(rc.MetaCtx, team))
 | 
			
		||||
}
 | 
			
		||||
@@ -87,7 +87,7 @@ func (p *Team) GetTeamMembers(rc *req.Ctx) {
 | 
			
		||||
 | 
			
		||||
// 保存团队信息
 | 
			
		||||
func (p *Team) SaveTeamMember(rc *req.Ctx) {
 | 
			
		||||
	teamMems := req.BindJsonAndValid(rc, new(form.TeamMember))
 | 
			
		||||
	teamMems := req.BindJsonAndValid[*form.TeamMember](rc)
 | 
			
		||||
 | 
			
		||||
	teamId := teamMems.TeamId
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type ResourceAuthCert struct {
 | 
			
		||||
	model.ExtraData
 | 
			
		||||
 | 
			
		||||
	Id             uint64                        `json:"id"`
 | 
			
		||||
	Name           string                        `json:"name"`           // 名称
 | 
			
		||||
	ResourceCode   string                        `json:"resourceCode"`   // 资源编号
 | 
			
		||||
@@ -14,7 +16,6 @@ type ResourceAuthCert struct {
 | 
			
		||||
	Username       string                        `json:"username"`       // 用户名
 | 
			
		||||
	Ciphertext     string                        `json:"ciphertext"`     // 密文
 | 
			
		||||
	CiphertextType entity.AuthCertCiphertextType `json:"ciphertextType"` // 密文类型
 | 
			
		||||
	Extra          model.Map[string, any]        `json:"extra"`          // 账号需要的其他额外信息(如秘钥口令等)
 | 
			
		||||
	Type           entity.AuthCertType           `json:"type"`           // 凭证类型
 | 
			
		||||
	Remark         string                        `json:"remark"`         // 备注
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								server/pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								server/pkg/cache/cache.go
									
									
									
									
										vendored
									
									
								
							@@ -1,8 +1,8 @@
 | 
			
		||||
package cache
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"mayfly-go/pkg/utils/anyx"
 | 
			
		||||
	"mayfly-go/pkg/utils/jsonx"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"github.com/may-fly/cast"
 | 
			
		||||
@@ -65,7 +65,7 @@ func (dc *defaultCache) GetInt(k string) (int, bool) {
 | 
			
		||||
 | 
			
		||||
func (dc *defaultCache) GetJson(k string, valPtr any) bool {
 | 
			
		||||
	if val, ok := dc.GetStr(k); ok {
 | 
			
		||||
		jsonx.To(val, valPtr)
 | 
			
		||||
		json.Unmarshal([]byte(val), valPtr)
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package model
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/structx"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -27,13 +26,8 @@ func PageResultConv[F any, T any](pageResult *PageResult[F]) *PageResult[T] {
 | 
			
		||||
	if pageResult == nil {
 | 
			
		||||
		return NewEmptyPageResult[T]()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return &PageResult[T]{
 | 
			
		||||
		Total: pageResult.Total,
 | 
			
		||||
		List: collx.ArrayMap(pageResult.List, func(item F) T {
 | 
			
		||||
			t := structx.NewInstance[T]()
 | 
			
		||||
			structx.Copy(t, item)
 | 
			
		||||
			return t
 | 
			
		||||
		}),
 | 
			
		||||
		List:  structx.CopySliceTo[F, T](pageResult.List),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,8 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 绑定并校验请求结构体参数
 | 
			
		||||
func BindJsonAndValid[T any](rc *Ctx, data T) T {
 | 
			
		||||
func BindJsonAndValid[T any](rc *Ctx) T {
 | 
			
		||||
	data := structx.NewInstance[T]()
 | 
			
		||||
	if err := rc.BindJSON(data); err != nil {
 | 
			
		||||
		panic(ConvBindValidationError(data, err))
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -18,15 +19,15 @@ func BindJsonAndValid[T any](rc *Ctx, data T) T {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 绑定请求体中的json至form结构体,并拷贝至另一结构体
 | 
			
		||||
func BindJsonAndCopyTo[T any](rc *Ctx, form any, toStruct T) T {
 | 
			
		||||
	BindJsonAndValid(rc, form)
 | 
			
		||||
	structx.Copy(toStruct, form)
 | 
			
		||||
	return toStruct
 | 
			
		||||
// 绑定请求体中的json至form结构体,并拷贝至指定结构体
 | 
			
		||||
func BindJsonAndCopyTo[F, T any](rc *Ctx) (F, T) {
 | 
			
		||||
	f := BindJsonAndValid[F](rc)
 | 
			
		||||
	return f, structx.CopyTo[T](f)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 绑定查询字符串到指定结构体
 | 
			
		||||
func BindQuery[T any](rc *Ctx, data T) T {
 | 
			
		||||
func BindQuery[T any](rc *Ctx) T {
 | 
			
		||||
	data := structx.NewInstance[T]()
 | 
			
		||||
	if err := rc.BindQuery(data); err != nil {
 | 
			
		||||
		panic(ConvBindValidationError(data, err))
 | 
			
		||||
	} else {
 | 
			
		||||
@@ -35,7 +36,8 @@ func BindQuery[T any](rc *Ctx, data T) T {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 绑定查询字符串到指定结构体,并将分页信息也返回
 | 
			
		||||
func BindQueryAndPage[T any](rc *Ctx, data T) (T, model.PageParam) {
 | 
			
		||||
func BindQueryAndPage[T any](rc *Ctx) (T, model.PageParam) {
 | 
			
		||||
	data := structx.NewInstance[T]()
 | 
			
		||||
	if err := rc.BindQuery(data); err != nil {
 | 
			
		||||
		panic(ConvBindValidationError(data, err))
 | 
			
		||||
	} else {
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,7 @@ import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"mayfly-go/pkg/logx"
 | 
			
		||||
	"mayfly-go/pkg/utils/collx"
 | 
			
		||||
	"mayfly-go/pkg/utils/structx"
 | 
			
		||||
 | 
			
		||||
	"github.com/tidwall/gjson"
 | 
			
		||||
)
 | 
			
		||||
@@ -16,9 +17,10 @@ func ToMap(jsonStr string) (collx.M, error) {
 | 
			
		||||
	return ToMapByBytes([]byte(jsonStr))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// json字符串转结构体
 | 
			
		||||
func To[T any](jsonStr string, res T) (T, error) {
 | 
			
		||||
	return res, json.Unmarshal([]byte(jsonStr), &res)
 | 
			
		||||
// json字符串转结构体, T需为指针类型
 | 
			
		||||
func To[T any](jsonStr string) (T, error) {
 | 
			
		||||
	res := structx.NewInstance[T]()
 | 
			
		||||
	return res, json.Unmarshal([]byte(jsonStr), res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// json字节数组转map
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										874
									
								
								server/pkg/utils/structx/copier.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										874
									
								
								server/pkg/utils/structx/copier.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,874 @@
 | 
			
		||||
package structx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"database/sql/driver"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"reflect"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"unicode"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
//  github.com/jinzhu/copier
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	ErrInvalidCopyDestination        = errors.New("copy destination must be non-nil and addressable")
 | 
			
		||||
	ErrInvalidCopyFrom               = errors.New("copy from must be non-nil and addressable")
 | 
			
		||||
	ErrMapKeyNotMatch                = errors.New("map's key type doesn't match")
 | 
			
		||||
	ErrNotSupported                  = errors.New("not supported")
 | 
			
		||||
	ErrFieldNameTagStartNotUpperCase = errors.New("copier field name tag must be start upper case")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// These flags define options for tag handling
 | 
			
		||||
const (
 | 
			
		||||
	// Denotes that a destination field must be copied to. If copying fails then a panic will ensue.
 | 
			
		||||
	tagMust uint8 = 1 << iota
 | 
			
		||||
 | 
			
		||||
	// Denotes that the program should not panic when the must flag is on and
 | 
			
		||||
	// value is not copied. The program will return an error instead.
 | 
			
		||||
	tagNoPanic
 | 
			
		||||
 | 
			
		||||
	// Ignore a destination field from being copied to.
 | 
			
		||||
	tagIgnore
 | 
			
		||||
 | 
			
		||||
	// Denotes the fact that the field should be overridden, no matter if the IgnoreEmpty is set
 | 
			
		||||
	tagOverride
 | 
			
		||||
 | 
			
		||||
	// Denotes that the value as been copied
 | 
			
		||||
	hasCopied
 | 
			
		||||
 | 
			
		||||
	// Some default converter types for a nicer syntax
 | 
			
		||||
	String  string  = ""
 | 
			
		||||
	Bool    bool    = false
 | 
			
		||||
	Int     int     = 0
 | 
			
		||||
	Float32 float32 = 0
 | 
			
		||||
	Float64 float64 = 0
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Option sets copy options
 | 
			
		||||
type Option struct {
 | 
			
		||||
	// setting this value to true will ignore copying zero values of all the fields, including bools, as well as a
 | 
			
		||||
	// struct having all it's fields set to their zero values respectively (see IsZero() in reflect/value.go)
 | 
			
		||||
	IgnoreEmpty   bool
 | 
			
		||||
	CaseSensitive bool
 | 
			
		||||
	DeepCopy      bool
 | 
			
		||||
	Converters    []TypeConverter
 | 
			
		||||
	// Custom field name mappings to copy values with different names in `fromValue` and `toValue` types.
 | 
			
		||||
	// Examples can be found in `copier_field_name_mapping_test.go`.
 | 
			
		||||
	FieldNameMapping []FieldNameMapping
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opt Option) converters() map[converterPair]TypeConverter {
 | 
			
		||||
	var converters = map[converterPair]TypeConverter{}
 | 
			
		||||
 | 
			
		||||
	// save converters into map for faster lookup
 | 
			
		||||
	for i := range opt.Converters {
 | 
			
		||||
		pair := converterPair{
 | 
			
		||||
			SrcType: reflect.TypeOf(opt.Converters[i].SrcType),
 | 
			
		||||
			DstType: reflect.TypeOf(opt.Converters[i].DstType),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		converters[pair] = opt.Converters[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return converters
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TypeConverter struct {
 | 
			
		||||
	SrcType interface{}
 | 
			
		||||
	DstType interface{}
 | 
			
		||||
	Fn      func(src interface{}) (dst interface{}, err error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type converterPair struct {
 | 
			
		||||
	SrcType reflect.Type
 | 
			
		||||
	DstType reflect.Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (opt Option) fieldNameMapping() map[converterPair]FieldNameMapping {
 | 
			
		||||
	var mapping = map[converterPair]FieldNameMapping{}
 | 
			
		||||
 | 
			
		||||
	for i := range opt.FieldNameMapping {
 | 
			
		||||
		pair := converterPair{
 | 
			
		||||
			SrcType: reflect.TypeOf(opt.FieldNameMapping[i].SrcType),
 | 
			
		||||
			DstType: reflect.TypeOf(opt.FieldNameMapping[i].DstType),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mapping[pair] = opt.FieldNameMapping[i]
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return mapping
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FieldNameMapping struct {
 | 
			
		||||
	SrcType interface{}
 | 
			
		||||
	DstType interface{}
 | 
			
		||||
	Mapping map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Tag Flags
 | 
			
		||||
type flags struct {
 | 
			
		||||
	BitFlags  map[string]uint8
 | 
			
		||||
	SrcNames  tagNameMapping
 | 
			
		||||
	DestNames tagNameMapping
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Field Tag name mapping
 | 
			
		||||
type tagNameMapping struct {
 | 
			
		||||
	FieldNameToTag map[string]string
 | 
			
		||||
	TagToFieldName map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Copy copy things
 | 
			
		||||
func Copy(toValue interface{}, fromValue interface{}) (err error) {
 | 
			
		||||
	return copier(toValue, fromValue, Option{})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CopyWithOption copy with option
 | 
			
		||||
func CopyWithOption(toValue interface{}, fromValue interface{}, opt Option) (err error) {
 | 
			
		||||
	return copier(toValue, fromValue, opt)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		isSlice    bool
 | 
			
		||||
		amount     = 1
 | 
			
		||||
		from       = indirect(reflect.ValueOf(fromValue))
 | 
			
		||||
		to         = indirect(reflect.ValueOf(toValue))
 | 
			
		||||
		converters = opt.converters()
 | 
			
		||||
		mappings   = opt.fieldNameMapping()
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if !to.CanAddr() {
 | 
			
		||||
		return ErrInvalidCopyDestination
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Return is from value is invalid
 | 
			
		||||
	if !from.IsValid() {
 | 
			
		||||
		return ErrInvalidCopyFrom
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fromType, isPtrFrom := indirectType(from.Type())
 | 
			
		||||
	toType, _ := indirectType(to.Type())
 | 
			
		||||
 | 
			
		||||
	if fromType.Kind() == reflect.Interface {
 | 
			
		||||
		fromType = reflect.TypeOf(from.Interface())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if toType.Kind() == reflect.Interface {
 | 
			
		||||
		toType, _ = indirectType(reflect.TypeOf(to.Interface()))
 | 
			
		||||
		oldTo := to
 | 
			
		||||
		to = reflect.New(reflect.TypeOf(to.Interface())).Elem()
 | 
			
		||||
		defer func() {
 | 
			
		||||
			oldTo.Set(to)
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Just set it if possible to assign for normal types
 | 
			
		||||
	if from.Kind() != reflect.Slice && from.Kind() != reflect.Struct && from.Kind() != reflect.Map && (from.Type().AssignableTo(to.Type()) || from.Type().ConvertibleTo(to.Type())) {
 | 
			
		||||
		if !isPtrFrom || !opt.DeepCopy {
 | 
			
		||||
			to.Set(from.Convert(to.Type()))
 | 
			
		||||
		} else {
 | 
			
		||||
			fromCopy := reflect.New(from.Type())
 | 
			
		||||
			fromCopy.Set(from.Elem())
 | 
			
		||||
			to.Set(fromCopy.Convert(to.Type()))
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if from.Kind() != reflect.Slice && fromType.Kind() == reflect.Map && toType.Kind() == reflect.Map {
 | 
			
		||||
		if !fromType.Key().ConvertibleTo(toType.Key()) {
 | 
			
		||||
			return ErrMapKeyNotMatch
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if to.IsNil() {
 | 
			
		||||
			to.Set(reflect.MakeMapWithSize(toType, from.Len()))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, k := range from.MapKeys() {
 | 
			
		||||
			toKey := indirect(reflect.New(toType.Key()))
 | 
			
		||||
			isSet, err := set(toKey, k, opt.DeepCopy, converters)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if !isSet {
 | 
			
		||||
				return fmt.Errorf("%w map, old key: %v, new key: %v", ErrNotSupported, k.Type(), toType.Key())
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			elemType := toType.Elem()
 | 
			
		||||
			if elemType.Kind() != reflect.Slice {
 | 
			
		||||
				elemType, _ = indirectType(elemType)
 | 
			
		||||
			}
 | 
			
		||||
			toValue := indirect(reflect.New(elemType))
 | 
			
		||||
			isSet, err = set(toValue, from.MapIndex(k), opt.DeepCopy, converters)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			if !isSet {
 | 
			
		||||
				if err = copier(toValue.Addr().Interface(), from.MapIndex(k).Interface(), opt); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for {
 | 
			
		||||
				if elemType == toType.Elem() {
 | 
			
		||||
					to.SetMapIndex(toKey, toValue)
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
				elemType = reflect.PointerTo(elemType)
 | 
			
		||||
				toValue = toValue.Addr()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if from.Kind() == reflect.Slice && to.Kind() == reflect.Slice {
 | 
			
		||||
		// Return directly if both slices are nil
 | 
			
		||||
		if from.IsNil() && to.IsNil() {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if to.IsNil() {
 | 
			
		||||
			slice := reflect.MakeSlice(reflect.SliceOf(to.Type().Elem()), from.Len(), from.Cap())
 | 
			
		||||
			to.Set(slice)
 | 
			
		||||
		}
 | 
			
		||||
		if fromType.ConvertibleTo(toType) {
 | 
			
		||||
			for i := 0; i < from.Len(); i++ {
 | 
			
		||||
				if to.Len() < i+1 {
 | 
			
		||||
					to.Set(reflect.Append(to, reflect.New(to.Type().Elem()).Elem()))
 | 
			
		||||
				}
 | 
			
		||||
				isSet, err := set(to.Index(i), from.Index(i), opt.DeepCopy, converters)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
				if !isSet {
 | 
			
		||||
					// ignore error while copy slice element
 | 
			
		||||
					err = copier(to.Index(i).Addr().Interface(), from.Index(i).Interface(), opt)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if to.Len() > from.Len() {
 | 
			
		||||
				to.SetLen(from.Len())
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
 | 
			
		||||
		// skip not supported type
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(converters) > 0 {
 | 
			
		||||
		if ok, e := set(to, from, opt.DeepCopy, converters); e == nil && ok {
 | 
			
		||||
			// converter supported
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if from.Kind() == reflect.Slice || to.Kind() == reflect.Slice {
 | 
			
		||||
		isSlice = true
 | 
			
		||||
		if from.Kind() == reflect.Slice {
 | 
			
		||||
			amount = from.Len()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < amount; i++ {
 | 
			
		||||
		var dest, source reflect.Value
 | 
			
		||||
 | 
			
		||||
		if isSlice {
 | 
			
		||||
			// source
 | 
			
		||||
			if from.Kind() == reflect.Slice {
 | 
			
		||||
				source = indirect(from.Index(i))
 | 
			
		||||
			} else {
 | 
			
		||||
				source = indirect(from)
 | 
			
		||||
			}
 | 
			
		||||
			// dest
 | 
			
		||||
			dest = indirect(reflect.New(toType).Elem())
 | 
			
		||||
		} else {
 | 
			
		||||
			source = indirect(from)
 | 
			
		||||
			dest = indirect(to)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if len(converters) > 0 {
 | 
			
		||||
			if ok, e := set(dest, source, opt.DeepCopy, converters); e == nil && ok {
 | 
			
		||||
				if isSlice {
 | 
			
		||||
					// FIXME: maybe should check the other types?
 | 
			
		||||
					if to.Type().Elem().Kind() == reflect.Ptr {
 | 
			
		||||
						to.Index(i).Set(dest.Addr())
 | 
			
		||||
					} else {
 | 
			
		||||
						if to.Len() < i+1 {
 | 
			
		||||
							reflect.Append(to, dest)
 | 
			
		||||
						} else {
 | 
			
		||||
							to.Index(i).Set(dest)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					to.Set(dest)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		destKind := dest.Kind()
 | 
			
		||||
		initDest := false
 | 
			
		||||
		if destKind == reflect.Interface {
 | 
			
		||||
			initDest = true
 | 
			
		||||
			dest = indirect(reflect.New(toType))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Get tag options
 | 
			
		||||
		flgs, err := getFlags(dest, source, toType, fromType)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check source
 | 
			
		||||
		if source.IsValid() {
 | 
			
		||||
			copyUnexportedStructFields(dest, source)
 | 
			
		||||
 | 
			
		||||
			// Copy from source field to dest field or method
 | 
			
		||||
			fromTypeFields := deepFields(fromType)
 | 
			
		||||
			for _, field := range fromTypeFields {
 | 
			
		||||
				name := field.Name
 | 
			
		||||
 | 
			
		||||
				// Get bit flags for field
 | 
			
		||||
				fieldFlags := flgs.BitFlags[name]
 | 
			
		||||
 | 
			
		||||
				// Check if we should ignore copying
 | 
			
		||||
				if (fieldFlags & tagIgnore) != 0 {
 | 
			
		||||
					continue
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				fieldNamesMapping := getFieldNamesMapping(mappings, fromType, toType)
 | 
			
		||||
 | 
			
		||||
				srcFieldName, destFieldName := getFieldName(name, flgs, fieldNamesMapping)
 | 
			
		||||
 | 
			
		||||
				if fromField := fieldByNameOrZeroValue(source, srcFieldName); fromField.IsValid() && !shouldIgnore(fromField, fieldFlags, opt.IgnoreEmpty) {
 | 
			
		||||
					// process for nested anonymous field
 | 
			
		||||
					destFieldNotSet := false
 | 
			
		||||
					if f, ok := dest.Type().FieldByName(destFieldName); ok {
 | 
			
		||||
						// only initialize parent embedded struct pointer in the path
 | 
			
		||||
						for idx := range f.Index[:len(f.Index)-1] {
 | 
			
		||||
							destField := dest.FieldByIndex(f.Index[:idx+1])
 | 
			
		||||
 | 
			
		||||
							if destField.Kind() != reflect.Ptr {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							if !destField.IsNil() {
 | 
			
		||||
								continue
 | 
			
		||||
							}
 | 
			
		||||
							if !destField.CanSet() {
 | 
			
		||||
								destFieldNotSet = true
 | 
			
		||||
								break
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							// destField is a nil pointer that can be set
 | 
			
		||||
							newValue := reflect.New(destField.Type().Elem())
 | 
			
		||||
							destField.Set(newValue)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					if destFieldNotSet {
 | 
			
		||||
						break
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					toField := fieldByName(dest, destFieldName, opt.CaseSensitive)
 | 
			
		||||
					if toField.IsValid() {
 | 
			
		||||
						if toField.CanSet() {
 | 
			
		||||
							isSet, err := set(toField, fromField, opt.DeepCopy, converters)
 | 
			
		||||
							if err != nil {
 | 
			
		||||
								return err
 | 
			
		||||
							}
 | 
			
		||||
							if !isSet {
 | 
			
		||||
								if err := copier(toField.Addr().Interface(), fromField.Interface(), opt); err != nil {
 | 
			
		||||
									return err
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
							if fieldFlags != 0 {
 | 
			
		||||
								// Note that a copy was made
 | 
			
		||||
								flgs.BitFlags[name] = fieldFlags | hasCopied
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						// try to set to method
 | 
			
		||||
						var toMethod reflect.Value
 | 
			
		||||
						if dest.CanAddr() {
 | 
			
		||||
							toMethod = dest.Addr().MethodByName(destFieldName)
 | 
			
		||||
						} else {
 | 
			
		||||
							toMethod = dest.MethodByName(destFieldName)
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
 | 
			
		||||
							toMethod.Call([]reflect.Value{fromField})
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Copy from from method to dest field
 | 
			
		||||
			for _, field := range deepFields(toType) {
 | 
			
		||||
				name := field.Name
 | 
			
		||||
				srcFieldName, destFieldName := getFieldName(name, flgs, getFieldNamesMapping(mappings, fromType, toType))
 | 
			
		||||
 | 
			
		||||
				var fromMethod reflect.Value
 | 
			
		||||
				if source.CanAddr() {
 | 
			
		||||
					fromMethod = source.Addr().MethodByName(srcFieldName)
 | 
			
		||||
				} else {
 | 
			
		||||
					fromMethod = source.MethodByName(srcFieldName)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 && !shouldIgnore(fromMethod, flgs.BitFlags[name], opt.IgnoreEmpty) {
 | 
			
		||||
					if toField := fieldByName(dest, destFieldName, opt.CaseSensitive); toField.IsValid() && toField.CanSet() {
 | 
			
		||||
						values := fromMethod.Call([]reflect.Value{})
 | 
			
		||||
						if len(values) >= 1 {
 | 
			
		||||
							set(toField, values[0], opt.DeepCopy, converters)
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if isSlice && to.Kind() == reflect.Slice {
 | 
			
		||||
			if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
 | 
			
		||||
				if to.Len() < i+1 {
 | 
			
		||||
					to.Set(reflect.Append(to, dest.Addr()))
 | 
			
		||||
				} else {
 | 
			
		||||
					isSet, err := set(to.Index(i), dest.Addr(), opt.DeepCopy, converters)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					if !isSet {
 | 
			
		||||
						// ignore error while copy slice element
 | 
			
		||||
						err = copier(to.Index(i).Addr().Interface(), dest.Addr().Interface(), opt)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							continue
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if dest.Type().AssignableTo(to.Type().Elem()) {
 | 
			
		||||
				if to.Len() < i+1 {
 | 
			
		||||
					to.Set(reflect.Append(to, dest))
 | 
			
		||||
				} else {
 | 
			
		||||
					isSet, err := set(to.Index(i), dest, opt.DeepCopy, converters)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					}
 | 
			
		||||
					if !isSet {
 | 
			
		||||
						// ignore error while copy slice element
 | 
			
		||||
						err = copier(to.Index(i).Addr().Interface(), dest.Interface(), opt)
 | 
			
		||||
						if err != nil {
 | 
			
		||||
							continue
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if initDest {
 | 
			
		||||
			to.Set(dest)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err = checkBitFlags(flgs.BitFlags)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFieldNamesMapping(mappings map[converterPair]FieldNameMapping, fromType reflect.Type, toType reflect.Type) map[string]string {
 | 
			
		||||
	var fieldNamesMapping map[string]string
 | 
			
		||||
 | 
			
		||||
	if len(mappings) > 0 {
 | 
			
		||||
		pair := converterPair{
 | 
			
		||||
			SrcType: fromType,
 | 
			
		||||
			DstType: toType,
 | 
			
		||||
		}
 | 
			
		||||
		if v, ok := mappings[pair]; ok {
 | 
			
		||||
			fieldNamesMapping = v.Mapping
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return fieldNamesMapping
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fieldByNameOrZeroValue(source reflect.Value, fieldName string) (value reflect.Value) {
 | 
			
		||||
	defer func() {
 | 
			
		||||
		if err := recover(); err != nil {
 | 
			
		||||
			value = reflect.Value{}
 | 
			
		||||
		}
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
	return source.FieldByName(fieldName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func copyUnexportedStructFields(to, from reflect.Value) {
 | 
			
		||||
	if from.Kind() != reflect.Struct || to.Kind() != reflect.Struct || !from.Type().AssignableTo(to.Type()) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// create a shallow copy of 'to' to get all fields
 | 
			
		||||
	tmp := indirect(reflect.New(to.Type()))
 | 
			
		||||
	tmp.Set(from)
 | 
			
		||||
 | 
			
		||||
	// revert exported fields
 | 
			
		||||
	for i := 0; i < to.NumField(); i++ {
 | 
			
		||||
		if tmp.Field(i).CanSet() {
 | 
			
		||||
			tmp.Field(i).Set(to.Field(i))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	to.Set(tmp)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func shouldIgnore(v reflect.Value, bitFlags uint8, ignoreEmpty bool) bool {
 | 
			
		||||
	return ignoreEmpty && bitFlags&tagOverride == 0 && v.IsZero()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var deepFieldsLock sync.RWMutex
 | 
			
		||||
var deepFieldsMap = make(map[reflect.Type][]reflect.StructField)
 | 
			
		||||
 | 
			
		||||
func deepFields(reflectType reflect.Type) []reflect.StructField {
 | 
			
		||||
	deepFieldsLock.RLock()
 | 
			
		||||
	cache, ok := deepFieldsMap[reflectType]
 | 
			
		||||
	deepFieldsLock.RUnlock()
 | 
			
		||||
	if ok {
 | 
			
		||||
		return cache
 | 
			
		||||
	}
 | 
			
		||||
	var res []reflect.StructField
 | 
			
		||||
	if reflectType, _ = indirectType(reflectType); reflectType.Kind() == reflect.Struct {
 | 
			
		||||
		fields := make([]reflect.StructField, 0, reflectType.NumField())
 | 
			
		||||
 | 
			
		||||
		for i := 0; i < reflectType.NumField(); i++ {
 | 
			
		||||
			v := reflectType.Field(i)
 | 
			
		||||
			// PkgPath is the package path that qualifies a lower case (unexported)
 | 
			
		||||
			// field name. It is empty for upper case (exported) field names.
 | 
			
		||||
			// See https://golang.org/ref/spec#Uniqueness_of_identifiers
 | 
			
		||||
			if v.PkgPath == "" {
 | 
			
		||||
				fields = append(fields, v)
 | 
			
		||||
				if v.Anonymous {
 | 
			
		||||
					// also consider fields of anonymous fields as fields of the root
 | 
			
		||||
					fields = append(fields, deepFields(v.Type)...)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		res = fields
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	deepFieldsLock.Lock()
 | 
			
		||||
	deepFieldsMap[reflectType] = res
 | 
			
		||||
	deepFieldsLock.Unlock()
 | 
			
		||||
	return res
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func indirect(reflectValue reflect.Value) reflect.Value {
 | 
			
		||||
	for reflectValue.Kind() == reflect.Ptr {
 | 
			
		||||
		reflectValue = reflectValue.Elem()
 | 
			
		||||
	}
 | 
			
		||||
	return reflectValue
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func indirectType(reflectType reflect.Type) (_ reflect.Type, isPtr bool) {
 | 
			
		||||
	for reflectType.Kind() == reflect.Ptr || reflectType.Kind() == reflect.Slice {
 | 
			
		||||
		reflectType = reflectType.Elem()
 | 
			
		||||
		isPtr = true
 | 
			
		||||
	}
 | 
			
		||||
	return reflectType, isPtr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func set(to, from reflect.Value, deepCopy bool, converters map[converterPair]TypeConverter) (bool, error) {
 | 
			
		||||
	if !from.IsValid() {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
	if ok, err := lookupAndCopyWithConverter(to, from, converters); err != nil {
 | 
			
		||||
		return false, err
 | 
			
		||||
	} else if ok {
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if to.Kind() == reflect.Ptr {
 | 
			
		||||
		// set `to` to nil if from is nil
 | 
			
		||||
		if from.Kind() == reflect.Ptr && from.IsNil() {
 | 
			
		||||
			to.Set(reflect.Zero(to.Type()))
 | 
			
		||||
			return true, nil
 | 
			
		||||
		} else if to.IsNil() {
 | 
			
		||||
			// `from`         -> `to`
 | 
			
		||||
			// sql.NullString -> *string
 | 
			
		||||
			if fromValuer, ok := driverValuer(from); ok {
 | 
			
		||||
				v, err := fromValuer.Value()
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return true, nil
 | 
			
		||||
				}
 | 
			
		||||
				// if `from` is not valid do nothing with `to`
 | 
			
		||||
				if v == nil {
 | 
			
		||||
					return true, nil
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			// allocate new `to` variable with default value (eg. *string -> new(string))
 | 
			
		||||
			to.Set(reflect.New(to.Type().Elem()))
 | 
			
		||||
		} else if from.Kind() != reflect.Ptr && from.IsZero() {
 | 
			
		||||
			to.Set(reflect.Zero(to.Type()))
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		// depointer `to`
 | 
			
		||||
		to = to.Elem()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if deepCopy {
 | 
			
		||||
		toKind := to.Kind()
 | 
			
		||||
		if toKind == reflect.Interface && to.IsNil() {
 | 
			
		||||
			if reflect.TypeOf(from.Interface()) != nil {
 | 
			
		||||
				to.Set(reflect.New(reflect.TypeOf(from.Interface())).Elem())
 | 
			
		||||
				toKind = reflect.TypeOf(to.Interface()).Kind()
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if from.Kind() == reflect.Ptr && from.IsNil() {
 | 
			
		||||
			to.Set(reflect.Zero(to.Type()))
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		if _, ok := to.Addr().Interface().(sql.Scanner); !ok && (toKind == reflect.Struct || toKind == reflect.Map || toKind == reflect.Slice) {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try convert directly
 | 
			
		||||
	if from.Type().ConvertibleTo(to.Type()) {
 | 
			
		||||
		to.Set(from.Convert(to.Type()))
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try Scanner
 | 
			
		||||
	if toScanner, ok := to.Addr().Interface().(sql.Scanner); ok {
 | 
			
		||||
		// `from`  -> `to`
 | 
			
		||||
		// *string -> sql.NullString
 | 
			
		||||
		if from.Kind() == reflect.Ptr {
 | 
			
		||||
			// if `from` is nil do nothing with `to`
 | 
			
		||||
			if from.IsNil() {
 | 
			
		||||
				return true, nil
 | 
			
		||||
			}
 | 
			
		||||
			// depointer `from`
 | 
			
		||||
			from = indirect(from)
 | 
			
		||||
		}
 | 
			
		||||
		// `from` -> `to`
 | 
			
		||||
		// string -> sql.NullString
 | 
			
		||||
		// set `to` by invoking method Scan(`from`)
 | 
			
		||||
		err := toScanner.Scan(from.Interface())
 | 
			
		||||
		if err == nil {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// try Valuer
 | 
			
		||||
	if fromValuer, ok := driverValuer(from); ok {
 | 
			
		||||
		// `from`         -> `to`
 | 
			
		||||
		// sql.NullString -> string
 | 
			
		||||
		v, err := fromValuer.Value()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, nil
 | 
			
		||||
		}
 | 
			
		||||
		// if `from` is not valid do nothing with `to`
 | 
			
		||||
		if v == nil {
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		rv := reflect.ValueOf(v)
 | 
			
		||||
		if rv.Type().AssignableTo(to.Type()) {
 | 
			
		||||
			to.Set(rv)
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		if to.CanSet() && rv.Type().ConvertibleTo(to.Type()) {
 | 
			
		||||
			to.Set(rv.Convert(to.Type()))
 | 
			
		||||
			return true, nil
 | 
			
		||||
		}
 | 
			
		||||
		return false, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// from is ptr
 | 
			
		||||
	if from.Kind() == reflect.Ptr {
 | 
			
		||||
		return set(to, from.Elem(), deepCopy, converters)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// lookupAndCopyWithConverter looks up the type pair, on success the TypeConverter Fn func is called to copy src to dst field.
 | 
			
		||||
func lookupAndCopyWithConverter(to, from reflect.Value, converters map[converterPair]TypeConverter) (copied bool, err error) {
 | 
			
		||||
	pair := converterPair{
 | 
			
		||||
		SrcType: from.Type(),
 | 
			
		||||
		DstType: to.Type(),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if cnv, ok := converters[pair]; ok {
 | 
			
		||||
		result, err := cnv.Fn(from.Interface())
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return false, err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if result != nil {
 | 
			
		||||
			to.Set(reflect.ValueOf(result))
 | 
			
		||||
		} else {
 | 
			
		||||
			// in case we've got a nil value to copy
 | 
			
		||||
			to.Set(reflect.Zero(to.Type()))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return true, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// parseTags Parses struct tags and returns uint8 bit flags.
 | 
			
		||||
func parseTags(tag string) (flg uint8, name string, err error) {
 | 
			
		||||
	for _, t := range strings.Split(tag, ",") {
 | 
			
		||||
		switch t {
 | 
			
		||||
		case "-":
 | 
			
		||||
			flg = tagIgnore
 | 
			
		||||
			return
 | 
			
		||||
		case "must":
 | 
			
		||||
			flg = flg | tagMust
 | 
			
		||||
		case "nopanic":
 | 
			
		||||
			flg = flg | tagNoPanic
 | 
			
		||||
		case "override":
 | 
			
		||||
			flg = flg | tagOverride
 | 
			
		||||
		default:
 | 
			
		||||
			if unicode.IsUpper([]rune(t)[0]) {
 | 
			
		||||
				name = strings.TrimSpace(t)
 | 
			
		||||
			} else {
 | 
			
		||||
				err = ErrFieldNameTagStartNotUpperCase
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getTagFlags Parses struct tags for bit flags, field name.
 | 
			
		||||
func getFlags(dest, src reflect.Value, toType, fromType reflect.Type) (flags, error) {
 | 
			
		||||
	flgs := flags{
 | 
			
		||||
		BitFlags: map[string]uint8{},
 | 
			
		||||
		SrcNames: tagNameMapping{
 | 
			
		||||
			FieldNameToTag: map[string]string{},
 | 
			
		||||
			TagToFieldName: map[string]string{},
 | 
			
		||||
		},
 | 
			
		||||
		DestNames: tagNameMapping{
 | 
			
		||||
			FieldNameToTag: map[string]string{},
 | 
			
		||||
			TagToFieldName: map[string]string{},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var toTypeFields, fromTypeFields []reflect.StructField
 | 
			
		||||
	if dest.IsValid() {
 | 
			
		||||
		toTypeFields = deepFields(toType)
 | 
			
		||||
	}
 | 
			
		||||
	if src.IsValid() {
 | 
			
		||||
		fromTypeFields = deepFields(fromType)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get a list dest of tags
 | 
			
		||||
	for _, field := range toTypeFields {
 | 
			
		||||
		tags := field.Tag.Get("copier")
 | 
			
		||||
		if tags != "" {
 | 
			
		||||
			var name string
 | 
			
		||||
			var err error
 | 
			
		||||
			if flgs.BitFlags[field.Name], name, err = parseTags(tags); err != nil {
 | 
			
		||||
				return flags{}, err
 | 
			
		||||
			} else if name != "" {
 | 
			
		||||
				flgs.DestNames.FieldNameToTag[field.Name] = name
 | 
			
		||||
				flgs.DestNames.TagToFieldName[name] = field.Name
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get a list source of tags
 | 
			
		||||
	for _, field := range fromTypeFields {
 | 
			
		||||
		tags := field.Tag.Get("copier")
 | 
			
		||||
		if tags != "" {
 | 
			
		||||
			var name string
 | 
			
		||||
			var err error
 | 
			
		||||
 | 
			
		||||
			if _, name, err = parseTags(tags); err != nil {
 | 
			
		||||
				return flags{}, err
 | 
			
		||||
			} else if name != "" {
 | 
			
		||||
				flgs.SrcNames.FieldNameToTag[field.Name] = name
 | 
			
		||||
				flgs.SrcNames.TagToFieldName[name] = field.Name
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return flgs, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// checkBitFlags Checks flags for error or panic conditions.
 | 
			
		||||
func checkBitFlags(flagsList map[string]uint8) (err error) {
 | 
			
		||||
	// Check flag conditions were met
 | 
			
		||||
	for name, flgs := range flagsList {
 | 
			
		||||
		if flgs&hasCopied == 0 {
 | 
			
		||||
			switch {
 | 
			
		||||
			case flgs&tagMust != 0 && flgs&tagNoPanic != 0:
 | 
			
		||||
				err = fmt.Errorf("field %s has must tag but was not copied", name)
 | 
			
		||||
				return
 | 
			
		||||
			case flgs&(tagMust) != 0:
 | 
			
		||||
				panic(fmt.Sprintf("Field %s has must tag but was not copied", name))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func getFieldName(fieldName string, flgs flags, fieldNameMapping map[string]string) (srcFieldName string, destFieldName string) {
 | 
			
		||||
	// get dest field name
 | 
			
		||||
	if name, ok := fieldNameMapping[fieldName]; ok {
 | 
			
		||||
		srcFieldName = fieldName
 | 
			
		||||
		destFieldName = name
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if srcTagName, ok := flgs.SrcNames.FieldNameToTag[fieldName]; ok {
 | 
			
		||||
		destFieldName = srcTagName
 | 
			
		||||
		if destTagName, ok := flgs.DestNames.TagToFieldName[srcTagName]; ok {
 | 
			
		||||
			destFieldName = destTagName
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if destTagName, ok := flgs.DestNames.TagToFieldName[fieldName]; ok {
 | 
			
		||||
			destFieldName = destTagName
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if destFieldName == "" {
 | 
			
		||||
		destFieldName = fieldName
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get source field name
 | 
			
		||||
	if destTagName, ok := flgs.DestNames.FieldNameToTag[fieldName]; ok {
 | 
			
		||||
		srcFieldName = destTagName
 | 
			
		||||
		if srcField, ok := flgs.SrcNames.TagToFieldName[destTagName]; ok {
 | 
			
		||||
			srcFieldName = srcField
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if srcField, ok := flgs.SrcNames.TagToFieldName[fieldName]; ok {
 | 
			
		||||
			srcFieldName = srcField
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if srcFieldName == "" {
 | 
			
		||||
		srcFieldName = fieldName
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func driverValuer(v reflect.Value) (i driver.Valuer, ok bool) {
 | 
			
		||||
	if !v.CanAddr() {
 | 
			
		||||
		i, ok = v.Interface().(driver.Valuer)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i, ok = v.Addr().Interface().(driver.Valuer)
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func fieldByName(v reflect.Value, name string, caseSensitive bool) reflect.Value {
 | 
			
		||||
	if caseSensitive {
 | 
			
		||||
		return v.FieldByName(name)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return v.FieldByNameFunc(func(n string) bool { return strings.EqualFold(n, name) })
 | 
			
		||||
}
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package structx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"database/sql"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
@@ -11,126 +10,18 @@ import (
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Copy copy things,引用至copier
 | 
			
		||||
func Copy(toValue any, fromValue any) (err error) {
 | 
			
		||||
	var (
 | 
			
		||||
		isSlice bool
 | 
			
		||||
		amount  = 1
 | 
			
		||||
		from    = Indirect(reflect.ValueOf(fromValue))
 | 
			
		||||
		to      = Indirect(reflect.ValueOf(toValue))
 | 
			
		||||
	)
 | 
			
		||||
// CopyTo 将fromValue转为T类型并返回
 | 
			
		||||
func CopyTo[T any](fromValue any) T {
 | 
			
		||||
	t := NewInstance[T]()
 | 
			
		||||
	Copy(t, fromValue)
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	if !to.CanAddr() {
 | 
			
		||||
		return errors.New("copy to value is unaddressable")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Return is from value is invalid
 | 
			
		||||
	if !from.IsValid() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fromType := IndirectType(from.Type())
 | 
			
		||||
	toType := IndirectType(to.Type())
 | 
			
		||||
 | 
			
		||||
	// Just set it if possible to assign
 | 
			
		||||
	// And need to do copy anyway if the type is struct
 | 
			
		||||
	if fromType.Kind() != reflect.Struct && from.Type().AssignableTo(to.Type()) {
 | 
			
		||||
		to.Set(from)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if fromType.Kind() != reflect.Struct || toType.Kind() != reflect.Struct {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if to.Kind() == reflect.Slice {
 | 
			
		||||
		isSlice = true
 | 
			
		||||
		if from.Kind() == reflect.Slice {
 | 
			
		||||
			amount = from.Len()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i := 0; i < amount; i++ {
 | 
			
		||||
		var dest, source reflect.Value
 | 
			
		||||
 | 
			
		||||
		if isSlice {
 | 
			
		||||
			// source
 | 
			
		||||
			if from.Kind() == reflect.Slice {
 | 
			
		||||
				source = Indirect(from.Index(i))
 | 
			
		||||
			} else {
 | 
			
		||||
				source = Indirect(from)
 | 
			
		||||
			}
 | 
			
		||||
			// dest
 | 
			
		||||
			dest = Indirect(reflect.New(toType).Elem())
 | 
			
		||||
		} else {
 | 
			
		||||
			source = Indirect(from)
 | 
			
		||||
			dest = Indirect(to)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// check source
 | 
			
		||||
		if source.IsValid() {
 | 
			
		||||
			fromTypeFields := deepFields(fromType)
 | 
			
		||||
			//fmt.Printf("%#v", fromTypeFields)
 | 
			
		||||
			// Copy from field to field or method
 | 
			
		||||
			for _, field := range fromTypeFields {
 | 
			
		||||
				name := field.Name
 | 
			
		||||
 | 
			
		||||
				if fromField := source.FieldByName(name); fromField.IsValid() {
 | 
			
		||||
					// has field
 | 
			
		||||
					if toField := dest.FieldByName(name); toField.IsValid() {
 | 
			
		||||
						if toField.CanSet() {
 | 
			
		||||
							if !set(toField, fromField) {
 | 
			
		||||
								if err := Copy(toField.Addr().Interface(), fromField.Interface()); err != nil {
 | 
			
		||||
									return err
 | 
			
		||||
								}
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						// try to set to method
 | 
			
		||||
						var toMethod reflect.Value
 | 
			
		||||
						if dest.CanAddr() {
 | 
			
		||||
							toMethod = dest.Addr().MethodByName(name)
 | 
			
		||||
						} else {
 | 
			
		||||
							toMethod = dest.MethodByName(name)
 | 
			
		||||
						}
 | 
			
		||||
 | 
			
		||||
						if toMethod.IsValid() && toMethod.Type().NumIn() == 1 && fromField.Type().AssignableTo(toMethod.Type().In(0)) {
 | 
			
		||||
							toMethod.Call([]reflect.Value{fromField})
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Copy from method to field
 | 
			
		||||
			for _, field := range deepFields(toType) {
 | 
			
		||||
				name := field.Name
 | 
			
		||||
 | 
			
		||||
				var fromMethod reflect.Value
 | 
			
		||||
				if source.CanAddr() {
 | 
			
		||||
					fromMethod = source.Addr().MethodByName(name)
 | 
			
		||||
				} else {
 | 
			
		||||
					fromMethod = source.MethodByName(name)
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if fromMethod.IsValid() && fromMethod.Type().NumIn() == 0 && fromMethod.Type().NumOut() == 1 {
 | 
			
		||||
					if toField := dest.FieldByName(name); toField.IsValid() && toField.CanSet() {
 | 
			
		||||
						values := fromMethod.Call([]reflect.Value{})
 | 
			
		||||
						if len(values) >= 1 {
 | 
			
		||||
							set(toField, values[0])
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if isSlice {
 | 
			
		||||
			if dest.Addr().Type().AssignableTo(to.Type().Elem()) {
 | 
			
		||||
				to.Set(reflect.Append(to, dest.Addr()))
 | 
			
		||||
			} else if dest.Type().AssignableTo(to.Type().Elem()) {
 | 
			
		||||
				to.Set(reflect.Append(to, dest))
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
// CopySliceTo 将fromValue转为[]T类型并返回
 | 
			
		||||
func CopySliceTo[F, T any](fromValue []F) []T {
 | 
			
		||||
	var to []T
 | 
			
		||||
	Copy(&to, fromValue)
 | 
			
		||||
	return to
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 对结构体的每个字段以及字段值执行doWith回调函数, 包括匿名属性的字段
 | 
			
		||||
@@ -158,23 +49,6 @@ func DoWithFields(str any, doWith func(fType reflect.StructField, fValue reflect
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func deepFields(reflectType reflect.Type) []reflect.StructField {
 | 
			
		||||
	var fields []reflect.StructField
 | 
			
		||||
 | 
			
		||||
	if reflectType = IndirectType(reflectType); reflectType.Kind() == reflect.Struct {
 | 
			
		||||
		for i := 0; i < reflectType.NumField(); i++ {
 | 
			
		||||
			v := reflectType.Field(i)
 | 
			
		||||
			if v.Anonymous {
 | 
			
		||||
				fields = append(fields, deepFields(v.Type)...)
 | 
			
		||||
			} else {
 | 
			
		||||
				fields = append(fields, v)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fields
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Indirect(reflectValue reflect.Value) reflect.Value {
 | 
			
		||||
	for reflectValue.Kind() == reflect.Ptr {
 | 
			
		||||
		reflectValue = reflectValue.Elem()
 | 
			
		||||
@@ -189,35 +63,6 @@ func IndirectType(reflectType reflect.Type) reflect.Type {
 | 
			
		||||
	return reflectType
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func set(to, from reflect.Value) bool {
 | 
			
		||||
	if from.IsValid() {
 | 
			
		||||
		if to.Kind() == reflect.Ptr {
 | 
			
		||||
			//set `to` to nil if from is nil
 | 
			
		||||
			if from.Kind() == reflect.Ptr && from.IsNil() {
 | 
			
		||||
				to.Set(reflect.Zero(to.Type()))
 | 
			
		||||
				return true
 | 
			
		||||
			} else if to.IsNil() {
 | 
			
		||||
				to.Set(reflect.New(to.Type().Elem()))
 | 
			
		||||
			}
 | 
			
		||||
			to = to.Elem()
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if from.Type().ConvertibleTo(to.Type()) {
 | 
			
		||||
			to.Set(from.Convert(to.Type()))
 | 
			
		||||
		} else if scanner, ok := to.Addr().Interface().(sql.Scanner); ok {
 | 
			
		||||
			err := scanner.Scan(from.Interface())
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return false
 | 
			
		||||
			}
 | 
			
		||||
		} else if from.Kind() == reflect.Ptr {
 | 
			
		||||
			return set(to, from.Elem())
 | 
			
		||||
		} else {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Map2Struct(m map[string]any, s any) error {
 | 
			
		||||
	toValue := Indirect(reflect.ValueOf(s))
 | 
			
		||||
	if !toValue.CanAddr() {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user