Repository: TencentBlueKing/bk-user

Issue:
【BUG】点击设置列表字段后，选择某个字段后，审计记录是全量记录，不能确切的显示操作了哪些字段
**用文字描述你遇到的问题**

点击设置列表字段后，选择某个字段后，审计记录是全量记录，不能确切的显示操作了哪些字段

**重现方法**
变更展示字段
![企业微信截图_c107216d-7fad-47d5-8445-cd8f269eccb8](https://github.com/TencentBlueKing/bk-user/assets/49228807/0fb64e9b-7606-4dc6-b678-892c36c266db)

查看审计
![企业微信截图_7111387b-6d0c-482d-ae62-0c3f14a1e38e](https://github.com/TencentBlueKing/bk-user/assets/49228807/ebcd36ad-8941-4240-8874-21f2669891ad)


**预期行为**

只显示变更的字段审计

**版本**
- 提供用户管理的具体版本号
2.4.2
- 是否是企业版问题？
是

**如果是 SaaS 页面问题，请提供使用的操作系统和浏览器信息**
 - OS: [e.g. iOS]
 - Browser [e.g. chrome, safari]
 - Version [e.g. 22]

**额外信息**

任何你觉得有助于问题解决的内容



Discussion:
2.5.X 因为重构的原因，该功能提供了一个批量修改的接口，暂时取消记录变更审计

Resolving patch:
diff --git a/src/api/bkuser_core/api/web/audit/constants.py b/src/api/bkuser_core/api/web/audit/constants.py
--- a/src/api/bkuser_core/api/web/audit/constants.py
+++ b/src/api/bkuser_core/api/web/audit/constants.py
@@ -38,6 +38,8 @@
     ("forget_password", _("用户通过token重置密码")),
     ("admin_reset_password", _("管理员重置密码")),
     ("modify_password", _("用户通过旧密码修改")),
+    ("set_field_visible", "设置字段展示"),
+    ("set_field_invisible", "设置字段隐藏"),
 )
 
 OPERATION_VALUE_MAP = {x[1]: x[0] for x in OPERATION_NAME_TUPLE}
diff --git a/src/api/bkuser_core/api/web/field/views.py b/src/api/bkuser_core/api/web/field/views.py
--- a/src/api/bkuser_core/api/web/field/views.py
+++ b/src/api/bkuser_core/api/web/field/views.py
@@ -20,7 +20,7 @@
     FieldOutputSLZ,
 )
 from bkuser_core.audit.constants import OperationType
-from bkuser_core.audit.utils import audit_general_log
+from bkuser_core.audit.utils import audit_general_log, create_general_log
 from bkuser_core.bkiam.permissions import ManageFieldPermission
 from bkuser_core.categories.signals import post_dynamic_field_delete
 from bkuser_core.common.error_codes import error_codes
@@ -73,8 +73,19 @@ def get(self, request):
 class FieldVisiableUpdateApi(generics.UpdateAPIView):
     permission_classes = [ManageFieldPermission]
 
-    # NOTE: 无法通过这个记录审计日志, 会导致drf报错, 这个装饰器封装只支持 /url/{id}/ 这种形式
-    # @audit_general_log(operate_type=OperationType.UPDATE.value)
+    def _add_fields_update_visible_audit_log(self, queryset, visible):
+        visible_operate_type_map = {
+            True: OperationType.SET_FIELD_VISIBLE.value,
+            False: OperationType.SET_FIELD_INVISIBLE.value,
+        }
+        for item in queryset:
+            create_general_log(
+                operator=self.request.operator,
+                operate_type=visible_operate_type_map[visible],
+                operator_obj=item,
+                request=self.request,
+            )
+
     def patch(self, request, *args, **kwargs):
         slz = DynamicFieldUpdateVisibleInputSLZ(data=request.data)
         slz.is_valid(raise_exception=True)
@@ -82,10 +93,22 @@ def patch(self, request, *args, **kwargs):
         data = slz.validated_data
         updating_ids = data["updating_ids"]
 
-        # update all to False
-        DynamicFieldInfo.objects.update(visible=False)
-        # update current to True
-        DynamicFieldInfo.objects.filter(id__in=updating_ids).update(visible=True)
+        # current visible fields
+        current_visible_field_ids = DynamicFieldInfo.objects.filter(visible=True).values_list("id", flat=True)
+
+        # to visible = False
+        invisible_field_ids = set(current_visible_field_ids) - set(updating_ids)
+        if invisible_field_ids:
+            invisible_fields = DynamicFieldInfo.objects.filter(id__in=list(invisible_field_ids))
+            invisible_fields.update(visible=False)
+            self._add_fields_update_visible_audit_log(invisible_fields, visible=False)
+
+        # to visible = True
+        visible_field_ids = set(updating_ids) - set(current_visible_field_ids)
+        if visible_field_ids:
+            visible_fields = DynamicFieldInfo.objects.filter(id__in=list(visible_field_ids))
+            visible_fields.update(visible=True)
+            self._add_fields_update_visible_audit_log(visible_fields, visible=True)
 
         return Response({})
 
diff --git a/src/api/bkuser_core/audit/constants.py b/src/api/bkuser_core/audit/constants.py
--- a/src/api/bkuser_core/audit/constants.py
+++ b/src/api/bkuser_core/audit/constants.py
@@ -60,6 +60,9 @@ class OperationType(AutoLowerEnum):
     ADMIN_RESET_PASSWORD = auto()  # 管理员重置密码
     MODIFY_PASSWORD = auto()  # 用户通过旧密码修改
 
+    SET_FIELD_VISIBLE = auto()  # 展示字段设置显示
+    SET_FIELD_INVISIBLE = auto()  # 展示字段设置屏蔽
+
     _choices_labels = (
         (CREATE, "创建"),
         (UPDATE, "更新"),
@@ -74,6 +77,8 @@ class OperationType(AutoLowerEnum):
         (FORGET_PASSWORD, "用户通过token重置密码"),
         (ADMIN_RESET_PASSWORD, "管理员重置密码"),
         (MODIFY_PASSWORD, "用户通过旧密码修改"),
+        (SET_FIELD_VISIBLE, "设置字段展示"),
+        (SET_FIELD_INVISIBLE, "设置字段隐藏"),
     )
 
 


Test patch: