mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00: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,30 +111,26 @@ 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) {
|
||||
return;
|
||||
}
|
||||
state.tabActiveName = 'basic';
|
||||
const redis: any = props.redis;
|
||||
if (redis) {
|
||||
state.form = { ...redis };
|
||||
state.form.tagCodePaths = redis.tags.map((t: any) => t.codePath);
|
||||
convertDb(state.form.db);
|
||||
} else {
|
||||
state.form = { db: '0', tagCodePaths: [] } as any;
|
||||
state.dbList = [0];
|
||||
}
|
||||
watch(dialogVisible, () => {
|
||||
if (!dialogVisible.value) {
|
||||
return;
|
||||
}
|
||||
);
|
||||
|
||||
const redis: any = props.redis;
|
||||
if (redis) {
|
||||
state.form = { ...redis };
|
||||
state.form.tagCodePaths = redis.tags.map((t: any) => t.codePath);
|
||||
convertDb(state.form.db);
|
||||
} else {
|
||||
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{
|
||||
|
||||
@@ -5,13 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type InstanceForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Host string `binding:"required" json:"host"`
|
||||
Port int `binding:"required" json:"port"`
|
||||
Version string `json:"version"`
|
||||
Remark string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"`
|
||||
Id uint64 `json:"id"`
|
||||
Name string `binding:"required" json:"name"`
|
||||
Host string `binding:"required" json:"host"`
|
||||
Port int `binding:"required" json:"port"`
|
||||
Version string `json:"version"`
|
||||
Remark *string `json:"remark"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"`
|
||||
|
||||
AuthCerts []*tagentity.ResourceAuthCert `json:"authCerts"` // 资产授权凭证信息列表
|
||||
TagCodePaths []string `binding:"required" json:"tagCodePaths"`
|
||||
|
||||
@@ -9,16 +9,17 @@ type InstanceListVO struct {
|
||||
tagentity.AuthCerts // 授权凭证信息
|
||||
tagentity.ResourceTags
|
||||
|
||||
Id *int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
Host *string `json:"host"`
|
||||
Port *int `json:"port"`
|
||||
Version *string `json:"version"`
|
||||
Id *int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name *string `json:"name"`
|
||||
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"`
|
||||
|
||||
@@ -8,14 +8,14 @@ import (
|
||||
type EsInstance struct {
|
||||
model.Model
|
||||
|
||||
Code string `json:"code" gorm:"size:32;not null;"`
|
||||
Name string `json:"name" gorm:"size:32;not null;"`
|
||||
Host string `json:"host" gorm:"size:255;not null;"`
|
||||
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;"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
Code string `json:"code" gorm:"size:32;not null;"`
|
||||
Name string `json:"name" gorm:"size:32;not null;"`
|
||||
Host string `json:"host" gorm:"size:255;not null;"`
|
||||
Port int `json:"port"`
|
||||
Network string `json:"network" gorm:"size:20;"`
|
||||
Version string `json:"version" gorm:"size:50;"`
|
||||
Remark *string `json:"remark" gorm:"size:255;"`
|
||||
SshTunnelMachineId int `json:"sshTunnelMachineId"` // ssh隧道机器id
|
||||
}
|
||||
|
||||
func (d *EsInstance) TableName() string {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,12 +50,12 @@ type MachineCronJobForm struct {
|
||||
}
|
||||
|
||||
type MachineCmdConfForm struct {
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cmds []string `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Cmds model.Slice[string] `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
|
||||
CodePaths []string `json:"codePaths"`
|
||||
}
|
||||
|
||||
@@ -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,10 +111,10 @@ type MachineCmdConfVO struct {
|
||||
model.Model
|
||||
|
||||
Name string `json:"name"`
|
||||
Cmds model.Slice[string] `json:"cmds"` // 命令配置
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
Cmds model.Slice[string] `json:"cmds" gorm:"type:varchar"` // 命令配置,要加gorm标签才会正确解析model.Slice
|
||||
Status int8 `json:"execCmds"` // 状态
|
||||
Stratege string `json:"stratege"` // 策略,空禁用
|
||||
Remark string `json:"remark"` // 备注
|
||||
}
|
||||
|
||||
func (mcc *MachineCmdConfVO) GetRelateId() uint64 {
|
||||
|
||||
@@ -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