-
+
-
+
-
-
- {
- form.tagCodePaths = tagCodePaths;
- tagSelectRef.validate();
- }
- "
- multiple
- :select-tags="form.tagCodePaths"
- />
+
+
+
@@ -55,9 +46,9 @@
@@ -65,7 +56,7 @@
diff --git a/frontend/src/views/ops/tag/AuthCertList.vue b/frontend/src/views/ops/tag/AuthCertList.vue
index add5121e..101683f8 100755
--- a/frontend/src/views/ops/tag/AuthCertList.vue
+++ b/frontend/src/views/ops/tag/AuthCertList.vue
@@ -8,7 +8,7 @@
:columns="state.columns"
>
- {{ $t('common.create') }}
+ {{ $t('common.create') }}
@@ -20,9 +20,9 @@
- {{ $t('common.edit') }}
+ {{ $t('common.edit') }}
- {{ $t('common.delete') }}
+ {{ $t('common.delete') }}
@@ -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 });
diff --git a/frontend/src/views/ops/tag/TagTreeList.vue b/frontend/src/views/ops/tag/TagTreeList.vue
index 30dd9787..4de4c3ec 100644
--- a/frontend/src/views/ops/tag/TagTreeList.vue
+++ b/frontend/src/views/ops/tag/TagTreeList.vue
@@ -10,7 +10,7 @@
v-auth="'tag:save'"
type="primary"
icon="plus"
- @click="showSaveTagDialog(null)"
+ @click="onShowSaveTagDialog(null)"
>
@@ -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 @@
-
+
@@ -137,7 +137,7 @@
-
+
@@ -151,8 +151,8 @@
@@ -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);
}
};
diff --git a/frontend/src/views/ops/tag/TeamList.vue b/frontend/src/views/ops/tag/TeamList.vue
index 776288e1..5b0c8a48 100755
--- a/frontend/src/views/ops/tag/TeamList.vue
+++ b/frontend/src/views/ops/tag/TeamList.vue
@@ -10,8 +10,8 @@
:columns="columns"
>
- {{ $t('common.create') }}
-
+ {{ $t('common.create') }}
+
{{ $t('common.delete') }}
@@ -23,22 +23,22 @@
{{ formatDate(data.validityStartDate) }} ~ {{ formatDate(data.validityEndDate) }}
- {{ $t('team.member') }}
+ {{ $t('team.member') }}
- {{ $t('common.edit') }}
+ {{ $t('common.edit') }}
-
+
@@ -69,8 +69,8 @@
@@ -85,22 +85,22 @@
:columns="showMemDialog.columns"
>
- {{ $t('common.add') }}
+ {{ $t('common.add') }}
-
+
-
+
@@ -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;
};
diff --git a/frontend/src/views/system/account/AccountEdit.vue b/frontend/src/views/system/account/AccountEdit.vue
index 6c711b7e..90ba56e8 100755
--- a/frontend/src/views/system/account/AccountEdit.vue
+++ b/frontend/src/views/system/account/AccountEdit.vue
@@ -1,7 +1,7 @@
-
-
+
+
@@ -49,15 +49,15 @@
- {{ $t('common.cancel') }}
- {{ $t('common.confirm') }}
+ {{ $t('common.cancel') }}
+ {{ $t('common.confirm') }}
diff --git a/frontend/src/views/system/config/ConfigList.vue b/frontend/src/views/system/config/ConfigList.vue
index e37bae8c..421cad0f 100755
--- a/frontend/src/views/system/config/ConfigList.vue
+++ b/frontend/src/views/system/config/ConfigList.vue
@@ -9,7 +9,7 @@
:data-handler-fn="handleData"
>
- {{ $t('common.create') }}
+ {{ $t('common.create') }}
@@ -19,11 +19,11 @@
{{ $t('system.sysconf.conf') }}
- {{ $t('common.edit') }}
+ {{ $t('common.edit') }}
-
+
-
+
@@ -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;
diff --git a/frontend/src/views/system/resource/ResourceEdit.vue b/frontend/src/views/system/resource/ResourceEdit.vue
index 229772d6..c0e4cc93 100644
--- a/frontend/src/views/system/resource/ResourceEdit.vue
+++ b/frontend/src/views/system/resource/ResourceEdit.vue
@@ -1,7 +1,7 @@
-
+
@@ -71,7 +71,7 @@
prop="meta.linkType"
:tooltip="$t('system.menu.externalLinkTips')"
>
-
+
@@ -87,17 +87,15 @@
-
- {{ $t('common.cancel') }}
- {{ $t('common.confirm') }}
-
+ {{ $t('common.cancel') }}
+ {{ $t('common.confirm') }}
diff --git a/server/internal/auth/api/account_login.go b/server/internal/auth/api/account_login.go
index 5a48bdb1..7de6e9e8 100644
--- a/server/internal/auth/api/account_login.go
+++ b/server/internal/auth/api/account_login.go
@@ -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)
diff --git a/server/internal/auth/api/ldap_login.go b/server/internal/auth/api/ldap_login.go
index 282a594d..d9193e65 100644
--- a/server/internal/auth/api/ldap_login.go
+++ b/server/internal/auth/api/ldap_login.go
@@ -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()
// 判断是否有开启登录验证码校验
diff --git a/server/internal/db/api/db.go b/server/internal/db/api/db.go
index f826f145..c4aa8847 100644
--- a/server/internal/db/api/db.go
+++ b/server/internal/db/api/db.go
@@ -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")
diff --git a/server/internal/db/api/db_data_sync.go b/server/internal/db/api/db_data_sync.go
index 9411426f..1af279c0 100644
--- a/server/internal/db/api/db_data_sync.go
+++ b/server/internal/db/api/db_data_sync.go
@@ -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 {
diff --git a/server/internal/db/api/db_instance.go b/server/internal/db/api/db_instance.go
index 3eb90289..f634f41d 100644
--- a/server/internal/db/api/db_instance.go
+++ b/server/internal/db/api/db_instance.go
@@ -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
diff --git a/server/internal/db/api/db_sql.go b/server/internal/db/api/db_sql.go
index 42ffdf5a..56f316f7 100644
--- a/server/internal/db/api/db_sql.go
+++ b/server/internal/db/api/db_sql.go
@@ -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)
diff --git a/server/internal/db/api/db_sql_exec.go b/server/internal/db/api/db_sql_exec.go
index d417ff5f..5b93b508 100644
--- a/server/internal/db/api/db_sql_exec.go
+++ b/server/internal/db/api/db_sql_exec.go
@@ -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)
diff --git a/server/internal/db/api/db_transfer.go b/server/internal/db/api/db_transfer.go
index d4281916..0be07f41 100644
--- a/server/internal/db/api/db_transfer.go
+++ b/server/internal/db/api/db_transfer.go
@@ -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
diff --git a/server/internal/db/application/db_sql_exec.go b/server/internal/db/application/db_sql_exec.go
index 89add493..0ba2a3ed 100644
--- a/server/internal/db/application/db_sql_exec.go
+++ b/server/internal/db/application/db_sql_exec.go
@@ -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())
}
diff --git a/server/internal/es/api/es_instance.go b/server/internal/es/api/es_instance.go
index 00f87796..9e118061 100644
--- a/server/internal/es/api/es_instance.go
+++ b/server/internal/es/api/es_instance.go
@@ -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{
diff --git a/server/internal/es/api/form/instance.go b/server/internal/es/api/form/instance.go
index 6b9e6c0e..b8f2d5d0 100644
--- a/server/internal/es/api/form/instance.go
+++ b/server/internal/es/api/form/instance.go
@@ -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"`
diff --git a/server/internal/es/api/vo/instance.go b/server/internal/es/api/vo/instance.go
index 880ed877..3852a722 100644
--- a/server/internal/es/api/vo/instance.go
+++ b/server/internal/es/api/vo/instance.go
@@ -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"`
diff --git a/server/internal/es/domain/entity/es_instance.go b/server/internal/es/domain/entity/es_instance.go
index f1c9f41d..cecdf395 100644
--- a/server/internal/es/domain/entity/es_instance.go
+++ b/server/internal/es/domain/entity/es_instance.go
@@ -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 {
diff --git a/server/internal/flow/api/procdef.go b/server/internal/flow/api/procdef.go
index f83539c6..3bb37a05 100644
--- a/server/internal/flow/api/procdef.go
+++ b/server/internal/flow/api/procdef.go
@@ -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{
diff --git a/server/internal/flow/api/procinst.go b/server/internal/flow/api/procinst.go
index 81f25100..b0b25b6e 100644
--- a/server/internal/flow/api/procinst.go
+++ b/server/internal/flow/api/procinst.go
@@ -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),
diff --git a/server/internal/flow/api/procinst_task.go b/server/internal/flow/api/procinst_task.go
index 1ec63530..e314cce1 100644
--- a/server/internal/flow/api/procinst_task.go
+++ b/server/internal/flow/api/procinst_task.go
@@ -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}))
}
diff --git a/server/internal/flow/application/execution.go b/server/internal/flow/application/execution.go
index d371a5a3..b6744fc3 100644
--- a/server/internal/flow/application/execution.go
+++ b/server/internal/flow/application/execution.go
@@ -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)
diff --git a/server/internal/flow/domain/entity/procdef.go b/server/internal/flow/domain/entity/procdef.go
index c61817e8..6d9f931b 100644
--- a/server/internal/flow/domain/entity/procdef.go
+++ b/server/internal/flow/domain/entity/procdef.go
@@ -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
diff --git a/server/internal/flow/domain/entity/procinst.go b/server/internal/flow/domain/entity/procinst.go
index 9105b519..79e289d1 100644
--- a/server/internal/flow/domain/entity/procinst.go
+++ b/server/internal/flow/domain/entity/procinst.go
@@ -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
diff --git a/server/internal/machine/api/form/form.go b/server/internal/machine/api/form/form.go
index 71d46103..688b6b32 100644
--- a/server/internal/machine/api/form/form.go
+++ b/server/internal/machine/api/form/form.go
@@ -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"`
}
diff --git a/server/internal/machine/api/machine.go b/server/internal/machine/api/machine.go
index 59acf925..06061627 100644
--- a/server/internal/machine/api/machine.go
+++ b/server/internal/machine/api/machine.go
@@ -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")
}
diff --git a/server/internal/machine/api/machine_cmd_conf.go b/server/internal/machine/api/machine_cmd_conf.go
index 541f7578..3efd6b9f 100644
--- a/server/internal/machine/api/machine_cmd_conf.go
+++ b/server/internal/machine/api/machine_cmd_conf.go
@@ -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{
diff --git a/server/internal/machine/api/machine_cronjob.go b/server/internal/machine/api/machine_cronjob.go
index 60cffb8b..4bee4ced 100644
--- a/server/internal/machine/api/machine_cronjob.go
+++ b/server/internal/machine/api/machine_cronjob.go
@@ -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
diff --git a/server/internal/machine/api/machine_file.go b/server/internal/machine/api/machine_file.go
index 7a8e5ae5..b3d3c2b6 100644
--- a/server/internal/machine/api/machine_file.go
+++ b/server/internal/machine/api/machine_file.go
@@ -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")
diff --git a/server/internal/machine/api/machine_script.go b/server/internal/machine/api/machine_script.go
index 83e6e812..aad72589 100644
--- a/server/internal/machine/api/machine_script.go
+++ b/server/internal/machine/api/machine_script.go
@@ -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))
diff --git a/server/internal/machine/api/vo/vo.go b/server/internal/machine/api/vo/vo.go
index 9bb1b9a7..e989325b 100644
--- a/server/internal/machine/api/vo/vo.go
+++ b/server/internal/machine/api/vo/vo.go
@@ -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 {
diff --git a/server/internal/machine/infrastructure/cache/machine_stats.go b/server/internal/machine/infrastructure/cache/machine_stats.go
index dd91547e..be70a623 100644
--- a/server/internal/machine/infrastructure/cache/machine_stats.go
+++ b/server/internal/machine/infrastructure/cache/machine_stats.go
@@ -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)
}
diff --git a/server/internal/mongo/api/mongo.go b/server/internal/mongo/api/mongo.go
index 48e023c5..40c251d6 100644
--- a/server/internal/mongo/api/mongo.go
+++ b/server/internal/mongo/api/mongo.go
@@ -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)
diff --git a/server/internal/msg/api/msg_channel.go b/server/internal/msg/api/msg_channel.go
index 2b85399b..60eb5861 100644
--- a/server/internal/msg/api/msg_channel.go
+++ b/server/internal/msg/api/msg_channel.go
@@ -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)
}
diff --git a/server/internal/msg/api/msg_tmpl.go b/server/internal/msg/api/msg_tmpl.go
index 83663f72..367f7ba0 100644
--- a/server/internal/msg/api/msg_tmpl.go
+++ b/server/internal/msg/api/msg_tmpl.go
@@ -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
diff --git a/server/internal/redis/api/cmd.go b/server/internal/redis/api/cmd.go
index 755e4a06..7b838dd3 100644
--- a/server/internal/redis/api/cmd.go
+++ b/server/internal/redis/api/cmd.go
@@ -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)
diff --git a/server/internal/redis/api/key.go b/server/internal/redis/api/key.go
index 93a979c7..c4a773c8 100644
--- a/server/internal/redis/api/key.go
+++ b/server/internal/redis/api/key.go
@@ -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()
diff --git a/server/internal/redis/api/redis.go b/server/internal/redis/api/redis.go
index 065ab718..9ede4622 100644
--- a/server/internal/redis/api/redis.go
+++ b/server/internal/redis/api/redis.go
@@ -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,
diff --git a/server/internal/redis/application/redis.go b/server/internal/redis/application/redis.go
index e381dfad..dc2489f4 100644
--- a/server/internal/redis/application/redis.go
+++ b/server/internal/redis/application/redis.go
@@ -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())
}
diff --git a/server/internal/sys/api/account.go b/server/internal/sys/api/account.go
index 6688e574..f9e6618a 100644
--- a/server/internal/sys/api/account.go
+++ b/server/internal/sys/api/account.go
@@ -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)))
}
diff --git a/server/internal/sys/api/config.go b/server/internal/sys/api/config.go
index adf45512..1392609b 100644
--- a/server/internal/sys/api/config.go
+++ b/server/internal/sys/api/config.go
@@ -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))
}
diff --git a/server/internal/sys/api/resource.go b/server/internal/sys/api/resource.go
index 01d70a55..bc10a327 100644
--- a/server/internal/sys/api/resource.go
+++ b/server/internal/sys/api/resource.go
@@ -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
diff --git a/server/internal/sys/api/role.go b/server/internal/sys/api/role.go
index 489182f6..89e942aa 100644
--- a/server/internal/sys/api/role.go
+++ b/server/internal/sys/api/role.go
@@ -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)
diff --git a/server/internal/sys/api/syslog.go b/server/internal/sys/api/syslog.go
index 9591fcd0..e2058204 100644
--- a/server/internal/sys/api/syslog.go
+++ b/server/internal/sys/api/syslog.go
@@ -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
diff --git a/server/internal/tag/api/resource_auth_cert.go b/server/internal/tag/api/resource_auth_cert.go
index 907fb28b..1adb834a 100644
--- a/server/internal/tag/api/resource_auth_cert.go
+++ b/server/internal/tag/api/resource_auth_cert.go
@@ -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 = "***"
diff --git a/server/internal/tag/api/tag_tree.go b/server/internal/tag/api/tag_tree.go
index 1c667c57..1b105575 100644
--- a/server/internal/tag/api/tag_tree.go
+++ b/server/internal/tag/api/tag_tree.go
@@ -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))
}
diff --git a/server/internal/tag/api/team.go b/server/internal/tag/api/team.go
index bde3329a..24756c82 100644
--- a/server/internal/tag/api/team.go
+++ b/server/internal/tag/api/team.go
@@ -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
diff --git a/server/internal/tag/api/vo/resource_auth_cert.go b/server/internal/tag/api/vo/resource_auth_cert.go
index af218555..727cb727 100644
--- a/server/internal/tag/api/vo/resource_auth_cert.go
+++ b/server/internal/tag/api/vo/resource_auth_cert.go
@@ -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"` // 备注
diff --git a/server/pkg/cache/cache.go b/server/pkg/cache/cache.go
index 1e783f44..532b5770 100644
--- a/server/pkg/cache/cache.go
+++ b/server/pkg/cache/cache.go
@@ -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
diff --git a/server/pkg/model/page.go b/server/pkg/model/page.go
index a37650c0..bc30b47b 100644
--- a/server/pkg/model/page.go
+++ b/server/pkg/model/page.go
@@ -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),
}
}
diff --git a/server/pkg/req/util.go b/server/pkg/req/util.go
index 227c34e2..317f4f12 100644
--- a/server/pkg/req/util.go
+++ b/server/pkg/req/util.go
@@ -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 {
diff --git a/server/pkg/utils/jsonx/jsonx.go b/server/pkg/utils/jsonx/jsonx.go
index 5d1fd170..c080f354 100644
--- a/server/pkg/utils/jsonx/jsonx.go
+++ b/server/pkg/utils/jsonx/jsonx.go
@@ -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
diff --git a/server/pkg/utils/structx/copier.go b/server/pkg/utils/structx/copier.go
new file mode 100644
index 00000000..638b12d5
--- /dev/null
+++ b/server/pkg/utils/structx/copier.go
@@ -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) })
+}
diff --git a/server/pkg/utils/structx/structx.go b/server/pkg/utils/structx/structx.go
index 0b008aae..081eb376 100644
--- a/server/pkg/utils/structx/structx.go
+++ b/server/pkg/utils/structx/structx.go
@@ -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() {