From d0779d17faf6ed693b15773c3faf9ae0ab90ce32 Mon Sep 17 00:00:00 2001
From: thexqn <thexqn@gmail.com>
Date: Fri, 30 Aug 2024 01:00:39 +0800
Subject: [PATCH] feat: Add unique value column to operation history table

---
 .gitignore                                    |  1 +
 cmdb-api/api/lib/cmdb/history.py              | 17 +++++++++++++++++
 .../operation_history/modules/ciTable.vue     | 19 ++++++++++++++++++-
 .../operation_history/modules/searchForm.vue  |  2 +-
 4 files changed, 37 insertions(+), 2 deletions(-)

diff --git a/.gitignore b/.gitignore
index e43370d..2fc477f 100755
--- a/.gitignore
+++ b/.gitignore
@@ -78,3 +78,4 @@ cmdb-ui/npm-debug.log*
 cmdb-ui/yarn-debug.log*
 cmdb-ui/yarn-error.log*
 cmdb-ui/package-lock.json
+start.sh
diff --git a/cmdb-api/api/lib/cmdb/history.py b/cmdb-api/api/lib/cmdb/history.py
index 2c790d2..c5a7aab 100644
--- a/cmdb-api/api/lib/cmdb/history.py
+++ b/cmdb-api/api/lib/cmdb/history.py
@@ -22,6 +22,7 @@ from api.models.cmdb import CITypeHistory
 from api.models.cmdb import CITypeTrigger
 from api.models.cmdb import CITypeUniqueConstraint
 from api.models.cmdb import OperationRecord
+from api.lib.cmdb.utils import ValueTypeMap
 
 
 class AttributeHistoryManger(object):
@@ -59,8 +60,23 @@ class AttributeHistoryManger(object):
         total = len(records)
 
         res = {}
+        unique_set = {}
+        from api.lib.cmdb.ci import CIManager
         for record in records:
             record_id = record.OperationRecord.id
+            ci_id = record.AttributeHistory.ci_id
+            if ci_id not in unique_set:
+                ci = CIManager.get_by_id(ci_id)
+                if ci and hasattr(ci, 'ci_type') and ci.ci_type:
+                    unique_id = ci.ci_type.unique_id
+                    unique_ci_type = AttributeCache.get(unique_id).value_type
+                    value_table_name = ValueTypeMap.table_name.get(f"index_{unique_ci_type}")
+                    value_table_list = getattr(ci, f"{value_table_name}.ci_id", None)
+                    matched_items = [item for item in value_table_list if item.attr_id == unique_id] if value_table_list else []
+                    if matched_items:
+                        unique_set[ci_id] = matched_items[0].value
+                else:
+                    unique_set[ci_id] = None
             attr_hist = record.AttributeHistory.to_dict()
             attr_hist['attr'] = AttributeCache.get(attr_hist['attr_id'])
             if attr_hist['attr']:
@@ -76,6 +92,7 @@ class AttributeHistoryManger(object):
 
             if record_id not in res:
                 record_dict = record.OperationRecord.to_dict()
+                record_dict['unique_value'] = unique_set.get(ci_id)
                 record_dict["user"] = UserCache.get(record_dict.get("uid"))
                 if record_dict["user"]:
                     record_dict['user'] = record_dict['user'].nickname
diff --git a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/ciTable.vue b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/ciTable.vue
index fc73711..4d2d2c1 100644
--- a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/ciTable.vue
+++ b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/ciTable.vue
@@ -45,6 +45,7 @@
         </template>
       </vxe-column>
       <vxe-column field="type_id" width="100px" :title="$t('cmdb.ciType.ciType')"></vxe-column>
+      <vxe-column field="unique_value" width="100px" :title="$t('cmdb.ciType.uniqueKey')"></vxe-column>
       <vxe-column field="operate_type" width="89px" :title="$t('operation')">
         <template #header="{ column }">
           <span>{{ column.title }}</span>
@@ -314,7 +315,7 @@ export default {
       }
     },
     mergeRowMethod({ row, _rowIndex, column, visibleData }) {
-      const fields = ['created_at', 'user', 'type_id']
+      const fields = ['created_at', 'user', 'type_id', 'unique_value']
       const cellValue = row[column.property]
       const created_at = row['created_at']
       if (column.property === 'created_at') {
@@ -365,6 +366,22 @@ export default {
             }
           }
         }
+      } else if (column.property === 'unique_value') {
+        if (cellValue && fields.includes(column.property)) {
+          const prevRow = visibleData[_rowIndex - 1]
+          let nextRow = visibleData[_rowIndex + 1]
+          if (prevRow && prevRow[column.property] === cellValue && prevRow['created_at'] === created_at) {
+            return { rowspan: 0, colspan: 0 }
+          } else {
+            let countRowspan = 1
+            while (nextRow && nextRow[column.property] === cellValue && nextRow['created_at'] === created_at) {
+              nextRow = visibleData[++countRowspan + _rowIndex]
+            }
+            if (countRowspan > 1) {
+              return { rowspan: countRowspan, colspan: 1 }
+            }
+          }
+        }
       }
     },
     filterUser() {
diff --git a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/searchForm.vue b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/searchForm.vue
index 4afd340..5702c1b 100644
--- a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/searchForm.vue
+++ b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/searchForm.vue
@@ -85,7 +85,7 @@
                 @change="onChange"
                 format="YYYY-MM-DD HH:mm"
                 :placeholder="[$t('cmdb.history.startTime'), $t('cmdb.history.endTime')]"
-                v-else-if="attr.value_type === '3'"
+                v-else-if="valueTypeMap[item.value_type] == 'date' || valueTypeMap[item.value_type] == 'datetime'"
                 :show-time="{
                   hideDisabledOptions: true,
                   defaultValue: [moment('00:00:00', 'HH:mm:ss'), moment('23:59:59', 'HH:mm:ss')],