From 273c0561c8592030127d6ee941d8b464bc656dff Mon Sep 17 00:00:00 2001
From: pycook <pycook@126.com>
Date: Wed, 19 Jul 2023 14:03:09 +0800
Subject: [PATCH 1/3] update cmdb_api.md

---
 Makefile         |    4 +-
 README.md        |    2 +-
 docs/cmdb_api.md | 1044 +++++++++++++++++-----------------------------
 3 files changed, 396 insertions(+), 654 deletions(-)

diff --git a/Makefile b/Makefile
index 3f9411f..99b1122 100644
--- a/Makefile
+++ b/Makefile
@@ -18,14 +18,14 @@ env:
 deps:
 	pipenv install --dev && \
 	pipenv run flask db-setup && \
-	pipenv run flask init-cache && \
+	pipenv run flask cmdb-init-cache && \
     cd cmdb-ui && yarn install && cd ..
 
 api:
 	cd cmdb-api && pipenv run flask run -h 0.0.0.0
 
 worker:
-	cd cmdb-api && pipenv run celery worker -A celery_worker.celery -E -Q cmdb_async --concurrency=1
+	cd cmdb-api && pipenv run celery worker -A celery_worker.celery -E -Q one_cmdb_async --concurrency=1 -D && pipenv run celery worker -A celery_worker.celery -E -Q acl_async --concurrency=1 -D
 
 ui:
 	cd cmdb-ui && yarn run serve
diff --git a/README.md b/README.md
index 4179c56..d85e02b 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@
 
 ### 更多功能
 
-> 也欢迎移步[维易科技官网](https://www.veops.cn),发现更多免费运维系统。
+> 也欢迎移步[维易科技官网](https://veops.cn),发现更多免费运维系统。
 
 ## 接入公司
 
diff --git a/docs/cmdb_api.md b/docs/cmdb_api.md
index 18c4b28..16a45e6 100644
--- a/docs/cmdb_api.md
+++ b/docs/cmdb_api.md
@@ -1,685 +1,427 @@
-# CMDB API 文档
+**CMDB接口文档v0.1**   @ [维易科技](https://veops.cn)
 
-```
-Rule                                                               Endpoint
-------------------------------------------------------------------------------------------------------------
-/api/login                                                         account_api.loginview
-/api/logout                                                        account_api.logoutview
-/api/sso/login                                                     cas.login
-/api/sso/logout                                                    cas.logout
-/api/v0.1/attributes                                               cmdb_api_v01.attributeview
-/api/v0.1/attributes/<int:attr_id>                                 cmdb_api_v01.attributeview
-/api/v0.1/attributes/<string:attr_name>                            cmdb_api_v01.attributeview
-/api/v0.1/attributes/s                                             cmdb_api_v01.attributesearchview
-/api/v0.1/attributes/search                                        cmdb_api_v01.attributesearchview
-/api/v0.1/ci                                                       cmdb_api_v01.ciview
-/api/v0.1/ci/<int:ci_id>                                           cmdb_api_v01.ciview
-/api/v0.1/ci/<int:ci_id>/detail                                    cmdb_api_v01.cidetailview
-/api/v0.1/ci/<int:ci_id>/flush                                     cmdb_api_v01.ciflushview
-/api/v0.1/ci/<int:ci_id>/unique                                    cmdb_api_v01.ciunique
-/api/v0.1/ci/flush                                                 cmdb_api_v01.ciflushview
-/api/v0.1/ci/heartbeat                                             cmdb_api_v01.ciheartbeatview
-/api/v0.1/ci/heartbeat/<string:ci_type>/<string:unique>            cmdb_api_v01.ciheartbeatview
-/api/v0.1/ci/s                                                     cmdb_api_v01.cisearchview
-/api/v0.1/ci/search                                                cmdb_api_v01.cisearchview
-/api/v0.1/ci/type/<int:type_id>                                    cmdb_api_v01.cisbytypeview
-/api/v0.1/ci_relations/<int:cr_id>                                 cmdb_api_v01.deletecirelationview
-/api/v0.1/ci_relations/<int:first_ci_id>/<int:second_ci_id>        cmdb_api_v01.cirelationview
-/api/v0.1/ci_relations/<int:first_ci_id>/second_cis                cmdb_api_v01.getsecondcisview
-/api/v0.1/ci_relations/<int:second_ci_id>/first_cis                cmdb_api_v01.getfirstcisview
-/api/v0.1/ci_relations/s                                           cmdb_api_v01.cirelationsearchview
-/api/v0.1/ci_relations/search                                      cmdb_api_v01.cirelationsearchview
-/api/v0.1/ci_relations/statistics                                  cmdb_api_v01.cirelationstatisticsview
-/api/v0.1/ci_type_relations                                        cmdb_api_v01.cityperelationview
-/api/v0.1/ci_type_relations/<int:child_id>/parents                 cmdb_api_v01.getparentsview
-/api/v0.1/ci_type_relations/<int:ctr_id>                           cmdb_api_v01.cityperelationdelete2view
-/api/v0.1/ci_type_relations/<int:parent_id>/<int:child_id>         cmdb_api_v01.cityperelationview
-/api/v0.1/ci_type_relations/<int:parent_id>/children               cmdb_api_v01.getchildrenview
-/api/v0.1/ci_types                                                 cmdb_api_v01.citypeview
-/api/v0.1/ci_types/<int:type_id>                                   cmdb_api_v01.citypeview
-/api/v0.1/ci_types/<int:type_id>/attribute_groups                  cmdb_api_v01.citypeattributegroupview
-/api/v0.1/ci_types/<int:type_id>/attributes                        cmdb_api_v01.citypeattributeview
-/api/v0.1/ci_types/<int:type_id>/enable                            cmdb_api_v01.enablecitypeview
-/api/v0.1/ci_types/<string:type_name>                              cmdb_api_v01.citypeview
-/api/v0.1/ci_types/<string:type_name>/attributes                   cmdb_api_v01.citypeattributeview
-/api/v0.1/ci_types/attribute_groups/<int:group_id>                 cmdb_api_v01.citypeattributegroupview
-/api/v0.1/ci_types/groups                                          cmdb_api_v01.citypegroupview
-/api/v0.1/ci_types/groups/<int:gid>                                cmdb_api_v01.citypegroupview
-/api/v0.1/ci_types/query                                           cmdb_api_v01.citypequeryview
-/api/v0.1/history/ci/<int:ci_id>                                   cmdb_api_v01.cihistoryview
-/api/v0.1/history/records                                          cmdb_api_v01.recordview
-/api/v0.1/history/records/<int:record_id>                          cmdb_api_v01.recorddetailview
-/api/v0.1/preference/ci_types                                      cmdb_api_v01.preferenceshowcitypesview
-/api/v0.1/preference/ci_types/<id_or_name>/attributes              cmdb_api_v01.preferenceshowattributesview
-/api/v0.1/preference/relation/view                                 cmdb_api_v01.preferencerelationapiview
-/api/v0.1/preference/tree/view                                     cmdb_api_v01.preferencetreeapiview
-/api/v0.1/relation_types                                           cmdb_api_v01.relationtypeview
-/api/v0.1/relation_types/<int:rel_id>                              cmdb_api_v01.relationtypeview
-/api/v1/acl/resource_groups                                        acl_api_v1.resourcegroupview
-/api/v1/acl/resource_groups/<int:group_id>                         acl_api_v1.resourcegroupview
-/api/v1/acl/resource_groups/<int:group_id>/items                   acl_api_v1.resourcegroupitemsview
-/api/v1/acl/resource_groups/<int:group_id>/permissions             acl_api_v1.resourcepermissionview
-/api/v1/acl/resource_types                                         acl_api_v1.resourcetypeview
-/api/v1/acl/resource_types/<int:type_id>                           acl_api_v1.resourcetypeview
-/api/v1/acl/resource_types/<int:type_id>/perms                     acl_api_v1.resourcetypepermsview
-/api/v1/acl/resources                                              acl_api_v1.resourceview
-/api/v1/acl/resources/<int:resource_id>                            acl_api_v1.resourceview
-/api/v1/acl/resources/<int:resource_id>/permissions                acl_api_v1.resourcepermissionview
-/api/v1/acl/roles                                                  acl_api_v1.roleview
-/api/v1/acl/roles/<int:child_id>/parents                           acl_api_v1.rolerelationview
-/api/v1/acl/roles/<int:rid>                                        acl_api_v1.roleview
-/api/v1/acl/roles/<int:rid>/resource_groups/<int:group_id>/grant   acl_api_v1.rolepermissiongrantview
-/api/v1/acl/roles/<int:rid>/resource_groups/<int:group_id>/revoke  acl_api_v1.rolepermissionrevokeview
-/api/v1/acl/roles/<int:rid>/resources/<int:resource_id>/grant      acl_api_v1.rolepermissiongrantview
-/api/v1/acl/roles/<int:rid>/resources/<int:resource_id>/revoke     acl_api_v1.rolepermissionrevokeview
-/api/v1/acl/users                                                  acl_api_v1.userview
-/api/v1/acl/users/<int:uid>                                        acl_api_v1.userview
-/api/v1/acl/users/info                                             acl_api_v1.getuserinfoview
-/api/v1/acl/users/reset_key_secret                                 acl_api_v1.userresetkeysecretview
-```
+# <div style="text-align: center;">CMDB接口文档</div>
 
-## 状态返回码的定义
+### 一、CI接口
 
-- 200:成功
-- 400:失败
-- 401:未认证
-- 403:no permission
-- 404:not found
-- 500:服务器未知错误
+#### 1. CI查询接口
 
-## 用户接口
+**条件搜索CI**, 按照模型的属性进行条件过滤、统计、排序等查询
 
-### CI 搜索接口
+* GET `/api/v0.1/ci/s`
+* 参数
+  
+  | 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
+  | ----  | ----   | ------   | ------ | ----|
+  | **q** | q=private_ip:192* | string | 是 | 搜索表达式 |
+  | **fl** |  | string | 否 | 返回的属性字段, 逗号分隔 |
+  | **facet** | facet=idc | string | 否 | 属性字段,逗号分隔,返回属性对应的所有值的统计 |
+  | **count** | count=1 | int | 否 | 一页返回的CI数, 默认是25 |
+  | **page** | page=1 | int | 否 | 页数, 默认是1 |
+  | **sort** |  sort=-private_ip| string | 否 | 属性的排序,降序字段前面加负号- |
+  | **ret_key** | ret_key=name | enum | 否 | 返回字段类型, 可以是`id`、`name`、`alias`, 默认`name` |
+  
+* 参数**q**说明:
+    * `_type` 指定CI模型, 多个用分号分隔. 例如: `_type:(server;vserver)`
+    * `attribute:value` 指定属性搜索, `attribute`可以是`id`,`attr_name`和`attr_alias`
+    * 以上的组合,逗号分隔
+    * 组合查询使用方法
+        * **`与`** 关系: `默认关系`
+        * **`或`**关系: 属性字段前加`-`, 例如: `-hostname:cmdb*`、
+        * **`非`**关系: 属性字段前加`~` 例如: `~hostname:cmdb*`
+        * **`或非`**关系: 属性字段前加`-~` 例如: `-~hostname:*`
+        * **`IN`**查询: 例如: `hostname:(cmdb*;cmdb-web*)` 小括号, 分号分隔
+        * **`范围`**查询: 例如: `hostname:[cmdb* _TO_ cmdb-web*]` `_TO_`分隔
+        * **`比较`**查询: 例如: `cpu_count:>5` 支持`>, >=, <, <=`
 
-- GET `/api/v0.1/ci/s`
-- 参数
-  - `string:_type` 搜索的 ci_type,多个用分号隔开, 例如: \_type:(server;vservser)
-  - `string:q` 搜索表达式, 例如`q=hostname:cmdb*`
-  - `string:fl` 返回字段(id, attr_name, attr_alias 均可),英文半角逗号分隔
-  - `string:ret_key` 返回字段类型 `Enum("id", "name", "alias")` 默认 `name`
-  - `count` 指定一次返回 CI 数
-  - `facet` 属性字段,逗号分隔,返回属性字段对应的所有值
-- 搜索表达式:
-  - 简单的字符串
-  - `attribute:value` 指定属性搜索, `attribute`可以是`id`,`attr_name`和`attr_alias`
-  - 以上的组合,逗号分隔
-- 组合查询支持
-  - `AND`关系-`默认关系`
-  - `OR`关系 - eg.`-hostname:cmdb*`、
-  - `NOT`关系-属性字段前加`~`eg. `~hostname:cmdb*`
-  - `IN`查询. eg. `hostname:(cmdb*;cmdb-web*)` 小括号, 分号分隔
-  - `RANGE`查询. eg. `hostname:[cmdb* _TO_ cmdb-web*]` `_TO_`分隔
-  - `COMPARISON`查询. eg. `cpu_core_num:>5` 支持`>, >=, <, <=`
+* 结果字段说明
 
-### CI Relation 搜索接口
-
-- GET `/api/v0.1/ci_relations/s`
-- 参数
-  - `int:root_id` 搜索的根节点的 ci_id
-  - `int:level` 搜索的层级
-  - `string:_type` 搜索的 ci_type,多个用分号隔开, 例如: \_type:(docker;kvm)
-  - `string:q` 搜索表达式, 例如`q=hostname:cmdb*`
-  - `string:fl` 返回字段(id, attr_name, attr_alias 均可),英文半角逗号分隔
-  - `string:ret_key` 返回字段类型 `Enum("id", "name", "alias")` 默认 `name`
-  - `count` 指定一次返回 CI 数
-  - `facet` 属性字段,逗号分隔,返回属性字段对应的所有值
-- 搜索表达式:
-  - 简单的字符串
-  - `attribute:value` 指定属性搜索, `attribute`可以是`id`,`attr_name`和`attr_alias`
-  - 以上的组合,逗号分隔
-- 组合查询支持
-  - `AND`关系-`默认关系`
-  - `OR`关系 - eg.`-hostname:cmdb*`、
-  - `NOT`关系-属性字段前加`~`eg. `~hostname:cmdb*`
-  - `IN`查询. eg. `hostname:(cmdb*;cmdb-web*)` 小括号, 分号分隔
-  - `RANGE`查询. eg. `hostname:[cmdb* _TO_ cmdb-web*]` `_TO_`分隔
-  - `COMPARISON`查询. eg. `cpu_count:>5` 支持`>, >=, <, <=`
-
-## api key 认证
-
-每个用户会自动生成一个 `api key` 和 一个`secret`, 通过 API 接口使用的时候,需要提供一个参数 `_key`值为您的`api key`, 以及参数`_secret`值为除`_key`以外的参数,按照**参数名的字典序**排列,并连接到`url path` + `secret`之后的`sha1`**十六进制**值。
-
-## 管理接口
-
-### Attribute 管理接口
-
-- GET `/api/v0.1/attributes/s` 列出所有属性
-
-  - param
-    - `string:q` 属性名称或者别名,允许为空
-  - return
-
-  ```
-  {
-      "numfound": 1,
-      "attributes": [
-      {
-          "attr_name": "idc",
-          "is_choice": true,
-          "choice_value": ["南汇", "欧阳路"],
-          "attr_id": 1,
-          "is_multivalue": false,
-          "attr_alias": "IDC",
-          "value_type": "text",
-          "is_uniq": false
-      }
-  }
-  ```
-
-  - error 无
-
-- GET `/api/v0.1/attributes/<string:attr_name>`、 `/api/v0.1/attributes/<int:attr_id>` 根据属性名称、别名或 ID 获取属性
-  - param
-    - `string:attr_name` 属性名称或别名
-    - `int:attr_id` 属性 ID
-    - `attr_id`和`attr_name`选其一
-  - return
-  ```
-  {
-      "attribute": {
-          "attr_name": "idc",
-          "is_choice": true,
-          "choice_value": ["南汇", "欧阳路"],
-          "attr_id": 1,
-          "is_multivalue": false,
-          "attr_alias": "IDC",
-          "value_type": "text",
-          "is_uniq": false
-      },
-  }
-  ```
-  - error
-    - `404` 找不到属性
-- POST `/api/v0.1/attributes` 增加新的属性
-  - param
-    - `string:attr_name` 属性名称
-    - `string:attr_alias` 属性别名,可为空,为空时等于`attr_name`
-    - `boolean:choice_value` 若属性有预定义值, 则不能为空
-    - `boolean:is_multivalue` 属性是否允许多值,默认`False`
-    - `boolean:is_uniq` 属性是否唯一,默认`False`
-    - `string:value_type` 属性值类型, `Enum("text", "int", "float", "date")`, 默认`text`
-  - return
-  ```
-  {
-      "attr_id":1
-  }
-  ```
-  - error
-    - `500` 属性已存在
-    - `500` 属性增加失败
-- PUT `/api/v0.1/attributes/<int:attr_id>` 修改属性
-
-  - param
-    - `string:attr_name` 属性名称
-    - `string:attr_alias` 属性别名,可为空,为空时等于`attr_name`
-    - `boolean:choice_value` 若属性有预定义值, 则不能为空
-    - `boolean:is_multivalue` 属性是否允许多值,值为 0 或者 1,默认`False`
-    - `boolean:is_uniq` 属性是否唯一,值为 0 或者 1,默认`False`
-    - `string:value_type` 属性值类型, `Enum("text", "int", "float", "date")`, 默认`text`
-  - return
-
-  ```
-  {
-      "attr_id":1
-  }
-  ```
-
-  - error
-    - `500` 属性已存在
-    - `500` 属性增加失败
-
-- DELETE `/api/v0.1/attributes/<int:attr_id>` 根据 ID 删除属性
-  - param
-    - `int:attr_id` 属性 ID
-  - return
-  ```
-  {
-      "message":"attribute %s deleted" % attr_name
-  }
-  ```
-  - error
-    - `404` 属性不存在
-    - `500` 删除属性失败
-
-#### CIType 属性管理
-
-- GET `/api/v0.1/ci_types/<int:type_id>/attributes` 根据 type_id 查询固有属性列表
-  - return
-  ```
-  {
-     "attributes": [
-         {
-             "attr_name": "idc",
-             "is_choice": true,
-             "choice_value": ["南汇", "欧阳路"],
-             "attr_id": 1,
-             "is_multivalue": false,
-             "attr_alias": "IDC",
-             "value_type": "text",
-             "is_uniq": false
-         },
+  | 字段名 | 值的类型 | 说明 |
+  | ----  | ----  | ----|
+  | **numfound** |  int | CI总数 |
+  | **total** |  int | 当前页的CI数 |
+  | **page** |  int |分页 |
+  | **result** | list | 返回的CI列表 |
+  | **facet** | dict| 根据参数facet做的聚合统计|
+  | **counter** |  dict | 当前页按模型的分类统计 |
+  
+* 返回结果
+    * 搜索示例 `/api/v0.1/ci/s?q=_type:server,private_ip:192.*,idc:*,status:在线&sort=-private_ip&facet=idc&page=1&count=1`
+    * 返回数据(默认json)
+---
+```json
+{
+  "counter": {
+    "server": 1
+  },
+  "facet": {
+    "idc": [
+      [
+        "南汇",
+        600,
+        "idc"
       ],
-     "type_id": 1,
-  }
-  ```
-- POST `/api/v0.1/ci_types/<int:type_id>/attributes` 根据`attr_id`增加 CIType 的属性
-  - param
-    - `string:attr_id` `,`分隔的`attr_id`
-    - `int:is_required` 0 或者 1
-  - return
-  ```
-  {
-      "attributes":[1, 2, 3]
-  }
-  ```
-  - error
-    - `404` CIType 不存在
-    - `404` 属性不存在
-    - `500` 增加失败
-- DELETE `/api/v0.1/ci_types/<int:type_id>/attributes` 删除 CIType 的属性
-  - param
-
-    - `string:attr_id` `,`分隔的`attr_id`
-
-  - return
-  ```
-  {
-      "attributes":[1, 2, 3]
-  }
-  ```
-  - error
-    - `404` CIType 不存在
-    - `404` 属性不存在
-    - `500` 增加失败
-
-### CIType 管理接口
-
-- `/api/v0.1/ci_types` 列出所有 CI 类型
-  - param `string:type_name` 类型名称,允许为空
-  - return
-  ```
-  {
-   "numfound": 2,
-   "ci_types": [
-      {
-          "uniq_key": "sn",
-          "type_name": "物理机",
-          "type_id": 1,
-          "enabled": True,
-          "icon_url": ""
-      },
-      {
-          "uniq_key": "uuid",
-          "type_name": "KVM",
-          "type_id": 2,
-          "enabled": True,
-          "icon_url": ""
-      }
-   ],
-  }
-  ```
-  - error 无
-- GET `/api/v0.1/ci_types/query` 查询 CI 类型
-  - param `string:q` 可以是 type_id, type_name, type_alias
-  - return
-  ```
-  {
-    "citype": {
-      "type_name": "software",
-      "type_id": 4,
-      "icon_url": "",
-      "type_alias": "\u8f6f\u4ef6",
-      "enabled": true,
-      "uniq_key": 21
-    }
-  }
-  ```
-  - error
-    - `400` message=输入参数缺失
-    - `404` message='citype is not found'
-- POST `/api/v0.1/ci_types` 增加新 CIType
-  - param (下列参数任意一个或多个)
-    - `string:type_name` CIType 名称
-    - `string:type_alias` 类型别名,可为空
-    - `int:_id` 唯一属性 ID
-    - `string:unique` 唯一属性名称
-    - `_id`和`unique`只能二选一
-    - `icon_url`
-    - `enabled` 0/1
-  - return
-  ```
-  {
-      "type_id": 2
-  }
-  ```
-  - error
-    - `400` message=输入参数缺失
-    - `500` message=CIType 已存在
-    - `500` message=唯一属性不存在
-    - `500` message=唯一属性不是唯一的
-- PUT `/api/v0.1/ci_types/<int:type_id>` 修改 CIType
-
-  - param (下列参数任意一个或多个)
-    - `string:type_name` CIType 名称
-    - `string:type_alias` 类型别名,可为空
-    - `int:_id` 唯一属性 ID
-    - `string:unique` 唯一属性名称
-    - `_id`和`unique`只能二选一
-    - `icon_url`
-    - `enabled` 0/1
-  - return
-
-  ```
-  {
-      "type_id": 2
-  }
-  ```
-
-  - error
-    - `400` message=输入参数缺失
-    - `500` message=CIType 已存在
-    - `500` message=唯一属性不存在
-    - `500` message=唯一属性不是唯一的
-
-- GET/POST `/api/v0.1/ci_types/<int:type_id>/enable` 修改 CIType
-  - param
-    - `enabled` 0 or 1
-  - return
-  ```
-  {
-      "type_id": 2
-  }
-  ```
-  - error
-    - `500` 设置失败
-    - `404` CIType 不存在
-- DELETE `/api/v0.1/ci_types/<int:type_id>` 根据 ID 删除 CIType
-  - return
-  ```
-  {
-      "message":"ci type %s deleted" % type_name
-  }
-  ```
-  - error
-    - `500` 删除失败
-    - `404` CIType 不存在
-
-### CITypeRelation 管理接口
-
-- GET `/api/v0.1/relation_types` 列出所有 CIType 关系类型名
-  - return
-  ```
-  [
-    {
-      "created_at": null,
-      "deleted": false,
-      "deleted_at": null,
-      "id": 1,
-      "name": "contain",
-      "updated_at": null
-    }
-  ]
-  ```
-  - error 无
-- GET `/api/v0.1/ci_type_relations/<int:parent_id>/children` 返回所有 child id
-  - return
-  ```
-  {
-    "children": [
-      {
-        "ctr_id": 1,
-        "type_name": "project",
-        "type_id": 2,
-        "icon_url": "",
-        "type_alias": "应用",
-        "enabled": true,
-        "uniq_key": 3
-      }
-    ]
-  }
-  ```
-  - error 无
-- GET `/api/v0.1/ci_type_relations/<int:child_id>/parents` 返回 parent id
-
-  - return
-
-  ```
-  {
-   "parents": [{'parent':1, 'relaltion_type': 'containes', "ctr_id":1}],
-  }
-  ```
-
-  - error 无
-
-- POST `/api/v0.1/ci_type_relations/<int:parent_id>/<int:child_id>` 增加 CIType 关系
-  - param
-    - `string:relation_type` 类型名称
-  - return
-  ```
-  {
-      "ctr_id": 1
-  }
-  ```
-  - error
-    - `500` 增加失败
-    - `404` CIType 不存在
-- DELETE `/api/v0.1/ci_type_relations/<int:ctr_id>` 根据`ctr_id`删除 CIType 关系
-  - return
-  ```
-  {
-      "message": "CIType relation deleted"
-  }
-  ```
-  - error
-    - `500` 删除失败
-    - `404` 关系不存在
-
-### CI 管理接口
-
-- GET `/api/v0.1/ci/type/<int:type_id>` 查询 CIType 的所有 CI,一次返回 25 条记录
-
-  - param
-
-    - `string:fields` 返回属性名、id,逗号隔开
-    - `string:ret_key` 返回属性 key,默认'name',还可是'id', 'alias'
-    - `int:page` 页码
-
-  - return
-
-  ```
-  {
-      "numfound": 1,
-      "type_id":1,
-      "page": 1,
-      "cis": [
-          {
-            "ci_type": "KVM",
-            "_type": 1,
-            "nic": [
-                  2
-            ],
-            "hostname": "xxxxxx",
-        "_unique": "xxxxxx",
-        "_id": 1
-          }
+      [
+        "外高桥",
+        600,
+        "idc"
+      ],
+      [
+        "张江",
+        600,
+        "idc"
       ]
-  }
-  ```
+    ]
+  },
+  "numfound": 1800,
+  "page": 1,
+  "result": [
+    {
+      "_id": 7238,
+      "_type": 4,
+      "buy_date": null,
+      "ci_type": "server",
+      "cpu": "Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz",
+      "cpu_count": 20,
+      "device_spec": "PowerEdge R630",
+      "env": "test",
+      "idc": "外高桥",
+      "ilo_ip": "192.168.0.120",
+      "ilo_mac": "82:7b:eb:f8:cb:03",
+      "kernel_version": "4.1.12-61.1.33.el6uek.x86_64",
+      "logic_cpu_count": 40,
+      "maintain_enddate": null,
+      "maintain_startdate": null,
+      "manufacturer": "DELL",
+      "op_duty": "张三",
+      "os_version": "CentOS Linux release 7.6.1810 (Core)",
+      "perm": null,
+      "pos": null,
+      "private_ip": "192.168.66.99",
+      "rack": "12086",
+      "raid": "1.089TB/RAID5",
+      "ram": "128GB",
+      "ram_size": "128GB",
+      "rd_duty": "李四",
+      "server_name": "192.168.66.99",
+      "sn": "8cbe16404c11",
+      "status": "在线",
+      "unique": "sn",
+      "vnc_port": null
+    }
+  ],
+  "total": 1
+}
+```
 
-  - error
-    - `404` CIType 不存在
+#### 2. 新增CI接口
 
-- GET `/api/v0.1/ci/<int:ci_id>` 查询 CI
+**创建或者修改CI**
 
-  - return
+* POST `/api/v0.1/ci` 
+* 参数
 
-  ```
+| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
+| ----  | ----   | ------   | ------ | ----|
+| **ci_type** | ci_type=server | string | 是 | 创建CI所属的模型名 |
+| **no_attribute_policy** | no_attribute_policy=ignore | string | 否 | 当添加不存在的attribute时的策略, 可选: `reject`、`ignore`, 默认`ignore` |
+| **exist_policy** | exist_policy=reject | string | 否 | CI已经存在的处理策略, 可选: `need`、`reject`、`replace` 默认`reject` |
+| **模型的属性名** | sn=xxxx | string | 否 | 属性名(id或别名亦可) |
+
+> 注意: 请求的参数里必须包含该CI的唯一标识
+
+* 返回结果
+
+  ```json
   {
-      "ci": {
-          "ci_type": "KVM",
-          "_type": 1,
-          "nic": [2],
-          "hostname": "xxxxx",
-          "_unique": "xxxxx",
-          "_id": 1
-      },
       "ci_id": 1
   }
   ```
 
-  - error 无
+#### 3. 修改CI接口
 
-- POST `/api/v0.1/ci` 增加 CI
-  - param
-    - `string:ci_type` CIType name 或者 id
-    - `string:_no_attribute_policy` 当添加不存在的 attribute 时的策略, 默认`ignore`
-    - 其他 url 参数`k=v`: `k` 为属性名(id 或别名亦可), `v`为对应的值
-    - 此 CIType 的`unique`字段必须包含在 url 参数中
-  - return
-  ```
-  {
-      "ci_id": 1,
-  }
-  ```
-  - error
-    - `500` 添加失败
-- PUT `/api/v0.1/ci` 修改 CI
-  - param
-    - `string:ci_type` CIType name 或者 id
-    - `string:_no_attribute_policy` 当添加不存在的 attribute 时的策略, 默认`ignore`
-    - 其他 url 参数`k=v`: `k` 为属性名(id 或别名亦可), `v`为对应的值
-    - 此 CIType 的`unique`字段必须包含在 url 参数中
-  - return
-  ```
-  {
-      "ci_id":1,
-  }
-  ```
-  - error
-    - `500` 添加失败
-- DELETE `/api/v0.1/ci/<int:ci_id>` 删除 ci
-  - return
-  ```
-  {
-      "message":"ok",
-  }
-  ```
-  - error
-    - `500` 删除失败
+**修改CI**, 可以使用新增CI的接口, exist_policy=replace, 或者根据ci_id来修改
 
-## CI Relation 管理接口
+* PUT `/api/v0.1/ci` 或者 `/api/v0.1/ci/<int:ci_id>`
+* 参数
 
-- GET `/api/v0.1/ci_relations/<int:first_ci_id>/second_cis` 返回所有 second cis
-  - return
-  ```
+| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
+| ----  | ----   | ------   | ------ | ----|
+| **ci_type** | ci_type=server | string | 是 | 创建CI所属的模型名 |
+| **no_attribute_policy** | no_attribute_policy=ignore | string | 否 | 当添加不存在的attribute时的策略, 可选: `reject`、`ignore`, 默认`ignore` |
+| **模型的属性名** | sn=xxxx | string | 否 | 属性名(id或别名亦可) |
+
+> 注意: 如果使用`/api/v0.1/ci`, 请求的参数里必须包含该CI的唯一标识
+
+* 返回结果
+
+  ```json
   {
-    "numfound": 1,
-    "second_cis": [
-      {
-        "ci_type": "project",
-        "ci_type_alias": "应用",
-        "_type": 2,
-        "_id": 18,
-        "project_name": "cmdb-api"
-      }
-      ]
-  }
-  ```
-  - error 无
-- GET `/api/v0.1/ci_relations/<int:second_ci_id>/first_cis` 返回 first cis
-
-  - return
-
-  ```
-  {
-    "first_cis": [
-      {
-        "ci_type": "project",
-        "ci_type_alias": "应用",
-        "_type": 2,
-        "_id": 18,
-        "project_name": "cmdb-api"
-      }
-    ],
-    "numfound": 1
+      "ci_id": 1
   }
   ```
 
-  - error 无
+#### 4. 删除CI接口
 
-- POST `/api/v0.1/ci_relations/<int:first_ci_id>/<int:second_ci_id>` 增加 CI 关系
-  - param
-    - `int: more` more 实例
-    - `string:relation_type` 类型名称
-  - return
-  ```
-  {
-      "cr_id":1
-  }
-  ```
-  - error
-    - `500` 增加失败
-    - `404` CI 不存在
-- DELETE `/api/v0.1/ci_relations/<int:cr_id>` 根据`cr_id`删除 CI 关系
-  - return
-  ```
-  {
-      "message":"CIType relation deleted"
-  }
-  ```
-  - error
-    - `500` 删除失败
-    - `404` 关系不存在
+**根据ci_id删除CI**, 硬删除操作
 
-## 历史记录管理接口
+* DELETE `/api/v0.1/ci/<int:ci_id>`
+* 参数 无
+* 返回结果
 
-- GET `/api/v0.1/history/records` 查询历史记录
-  - param
-    - `int: page`
-    - `string: username` 变更用户
-    - `string: start` 变更开始时间
-    - `string: end` 变更结束时间
-  - return
-  ```
+  ```json
   {
-    "username": "",
-    "start": "2014-12-31 14:57:43",
-    "end": "2015-01-07 14:57:43",
-    "records": [
-      {
-        "origin": null,
-        "attr_history": [],
-        "timestamp": "2015-01-01 22:12:39",
-        "reason": null,
-        "rel_history": {
-          "add": 1
-        },
-        "user": 1,
-        "record_id": 1234,
-        "ticket_id": null
-      }
-      ]
+      "message": "ok"
   }
   ```
-  - error 无
-- GET `/api/v0.1/history/records/<int:record_id>` 历史记录详情
-  - return
-  ```
+
+<div STYLE="page-break-after: always;"></div>
+
+### 二、CI关系接口
+
+#### 1. CI关系查询接口
+
+**搜索所有的CI之间的关系**, 比如某一个事业部的所有应用或者是所有服务器
+
+* GET `/api/v0.1/ci_relations/s`
+* 参数
+  
+    | 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
+    | ----  | ----   | ------   | ------ | ----|
+    | **root_id** | root_id=1 | int | 是 | 根节点的ci_id |
+    | **level** | level=1 | string | 否 | 关系的层级,多层用逗号分隔 |
+    | **reverse** | reverse=0 | int | 否 | 是否反向搜索, 0或者1, 默认是0,  |
+    | **q** | q=hostname:cmdb* | string | 否 | 搜索表达式 |
+    | **fl** |  | string | 否 | 返回的属性字段, 逗号分隔 |
+    | **facet** |  | string | 否 | 属性字段,逗号分隔,返回属性对应的所有值的统计 |
+    | **count** | count=25 | int | 否 | 一页返回的CI数, 默认是25 |
+    | **page** | page=1 | int | 否 | 页数, 默认是1 |
+    | **sort** |  | string | 否 | 属性的排序,降序字段前面加负号- |
+    | **ret_key** | | enum | 否 | 返回字段类型, 可以是`id`、`name`、`alias`, 默认`name` |
+    
+> 搜索表达式`q` 和 `CI查询接口`的搜索表达式q 完全一样!
+
+* 结果字段说明
+
+  | 字段名 | 值的类型 | 说明 |
+  | ----  | ----  | ----|
+  | **numfound** |  int | CI总数 |
+  | **total** |  int | 当前页的CI数 |
+  | **page** |  int |分页 |
+  | **result** | list | 返回的CI列表 |
+  | **facet** | dict| 根据参数facet做的聚合统计|
+  | **counter** |  dict | 当前页按模型的分类统计 |
+  
+* 返回结果
+    * 搜索某个事业部下面的物理机 `/api/v0.1/ci_relations/s?root_id=5&level=3&count=1&q=_type:server,idc:南汇`
+    * 返回数据(默认json)    
+---
+
+```json
+{
+  "counter": {
+    "server": 1
+  },
+  "facet": {},
+  "numfound": 400,
+  "page": 1,
+  "result": [
+    {
+      "_id": 159,
+      "_type": 4,
+      "bu": null,
+      "buy_date": null,
+      "ci_type": "server",
+      "cmc_ip": null,
+      "cnc_ip": null,
+      "cpu": "Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz",
+      "cpu_count": 20,
+      "ctc_ip": null,
+      "device_spec": "PowerEdge R630",
+      "env": "prod",
+      "idc": "南汇",
+      "ilo_ip": "192.168.0.120",
+      "ilo_mac": "82:7b:eb:f8:cb:03",
+      "kernel_version": "4.1.12-61.1.33.el6uek.x86_64",
+      "logic_cpu_count": 40,
+      "maintain_enddate": null,
+      "maintain_startdate": null,
+      "manufacturer": "DELL",
+      "oneagent_id": null,
+      "op_duty": "张三",
+      "os_version": "Microsoft Windows Server 2019 Standard",
+      "perm": null,
+      "pos": null,
+      "private_ip": "192.168.1.2",
+      "rack": "12086",
+      "raid": "1.089TB/RAID5",
+      "ram": "128GB",
+      "ram_size": "128GB",
+      "rd_duty": "李四",
+      "server_name": "192.168.1.2",
+      "server_room": null,
+      "sn": "1fd3b1d5c253",
+      "ssh_port": null,
+      "status": "在线",
+      "unique": "sn",
+      "vnc_port": null
+    }
+  ],
+  "total": 1
+}
+```
+
+#### 2. 增加CI关系接口
+
+**新增CI关系**, 参数`src_ci_id`是源CI的id, `dst_ci_id`是目标CI的id
+
+* POST `/api/v0.1/ci_relations/<int:src_ci_id>/<int:dst_ci_id>`
+* 参数 无
+* 返回结果
+
+  ```json
   {
-    "username": "demo",
-    "timestamp": "2015-01-02 20:21:16",
-    "rel_history": {
-      "add": [
-        [
-          123,
-          "deploy",
-          234
-        ]
-      ],
-      "delete": []
-    },
-    "attr_history": {}
+      "cr_id": 1
   }
   ```
-  - error
-    - `404` 该记录不存在
+
+#### 3. 删除CI关系接口
+
+**根据`cr_id`删除CI关系**, 参数`cr_id`是CI关系的id
+
+* DELETE `/api/v0.1/ci_relations/<int:cr_id>` 
+* 参数 无
+* 返回结果
+
+  ```json
+  {
+      "message": "CIType relation deleted"
+  }
+  ```
+
+<div STYLE="page-break-after: always;"></div>
+
+### 三、响应状态码说明
+
+|状态码|说明|
+|----|---|
+|200|成功|
+|400|请求参数错误或者失败|
+|401|未认证|
+|403|权限不够|
+|404|访问的资源不存在|
+|500|服务端未知错误|
+|502|服务未启动或者异常退出|
+
+> 所有错误或者失败,统一返回json格式为:
+  ```json
+  {
+      "message": "错误描述"
+  }
+  ```
+
+
+<div STYLE="page-break-after: always;"></div>
+
+### 四、API鉴权方法
+- 每个用户会自动生成一个 `api key` 和 一个`secret`, 在ACL系统里可查看到
+- 调用API的时候,需要提供2个参数 `_key`和`_secret`
+  - `_key`的值为您的`api key`
+  - `_secret`的计算方法:
+    - 除`_key`以外的参数,把**参数名**排序后参数值拼接在一起,并连接到`url path` + `secret`之后 
+    - 求`sha1`**十六进制**值, 即sha1(`url path` + `secret` + `参数名排序后拼接的参数值`)的16进制值
+
+
+### 五、Python调用样例
+#### 鉴权
+```python
+import hashlib
+
+key = "Your API key"
+secret = "Your API secret"
+
+def build_api_key(path, params):
+    values = "".join([str(params[k]) for k in sorted(params.keys())
+                      if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
+    _secret = "".join([path, secret, values]).encode("utf-8")
+    params["_secret"] = hashlib.sha1(_secret).hexdigest()
+    params["_key"] = key
+    
+    return params
+```
+
+#### 查询
+* 以查询CI为例
+```python
+import hashlib
+
+import requests
+from future.moves.urllib.parse import urlparse
+
+URL = "https://demo.veops.cn/api/v0.1/ci/s"
+KEY = "Your API key"
+SECRET = "Your API secret"
+
+
+def build_api_key(path, params):
+    values = "".join([str(params[k]) for k in sorted(params.keys())
+                      if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
+    _secret = "".join([path, SECRET, values]).encode("utf-8")
+    params["_secret"] = hashlib.sha1(_secret).hexdigest()
+    params["_key"] = KEY
+
+    return params
+
+
+def get_ci(payload):
+    payload = build_api_key(urlparse(URL).path, payload)
+
+    return requests.get(URL, params=payload).json()
+
+```
+
+#### 增、删、改
+* 以CI的增、删、改为例
+```python
+import hashlib
+
+import requests
+from future.moves.urllib.parse import urlparse
+
+URL = "https://demo.veops.cn/api/v0.1/ci"
+KEY = "Your API key"
+SECRET = "Your API secret"
+
+
+def build_api_key(path, params):
+    values = "".join([str(params[k]) for k in sorted(params.keys())
+                      if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
+    _secret = "".join([path, SECRET, values]).encode("utf-8")
+    params["_secret"] = hashlib.sha1(_secret).hexdigest()
+    params["_key"] = KEY
+
+    return params
+
+
+def add_ci(payload):
+    payload = build_api_key(urlparse(URL).path, payload)
+
+    return requests.post(URL, json=payload).json()
+
+
+def update_ci(payload, ci_id=None):
+    url = "{url}/{ci_id}".format(url=URL, ci_id=ci_id) if ci_id is not None else URL
+
+    payload = build_api_key(urlparse(url).path, payload)
+
+    return requests.put(url, json=payload).json()
+
+
+def delete_ci(ci_id):
+    url = "{url}/{ci_id}".format(url=URL, ci_id=ci_id)
+
+    payload = build_api_key(urlparse(url).path, {})
+
+    return requests.delete(url, json=payload).json()
+
+```

From f306594b01c5b59e3ae3db527f4590436a0489bd Mon Sep 17 00:00:00 2001
From: songbing01249 <songbing@smyfinancial.com>
Date: Wed, 19 Jul 2023 14:42:27 +0800
Subject: [PATCH 2/3] fix(ci_type_group_manager): fix resources issues

---
 cmdb-api/api/lib/cmdb/ci_type.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmdb-api/api/lib/cmdb/ci_type.py b/cmdb-api/api/lib/cmdb/ci_type.py
index 0c2d3bb..a88a16b 100644
--- a/cmdb-api/api/lib/cmdb/ci_type.py
+++ b/cmdb-api/api/lib/cmdb/ci_type.py
@@ -235,7 +235,7 @@ class CITypeGroupManager(object):
             for t in sorted(CITypeGroupItem.get_by(group_id=group['id']), key=lambda x: x['order'] or 0):
                 ci_type = CITypeCache.get(t['type_id']).to_dict()
                 if resources is None or (ci_type and ci_type['name'] in resources):
-                    ci_type['permissions'] = resources[ci_type['name']]
+                    ci_type['permissions'] = resources[ci_type['name']] if resources is not None else None
                     group.setdefault("ci_types", []).append(ci_type)
                     group_types.add(t["type_id"])
 
@@ -244,7 +244,7 @@ class CITypeGroupManager(object):
             other_types = dict(ci_types=[])
             for ci_type in ci_types:
                 if ci_type["id"] not in group_types and (resources is None or ci_type['name'] in resources):
-                    ci_type['permissions'] = resources.get(ci_type['name'])
+                    ci_type['permissions'] = resources.get(ci_type['name']) if resources is not None else None
                     other_types['ci_types'].append(ci_type)
 
             groups.append(other_types)

From 2c51cdfed28c57e5899d7d66042d798323ffc903 Mon Sep 17 00:00:00 2001
From: "yong.huang" <yong.huang@dfc.sh>
Date: Wed, 19 Jul 2023 17:40:14 +0800
Subject: [PATCH 3/3] ui lint

---
 cmdb-api/Pipfile                              |   2 +-
 cmdb-api/requirements.txt                     |   4 +-
 .../cmdb/views/ci_types/attributeEditForm.vue |  52 ++++----
 .../operation_history/modules/typeTable.vue   |   2 +-
 .../companyStructure/EmployeeModal.vue        |   6 +-
 .../setting/components/employeeTable.vue      | 122 +++++++++---------
 6 files changed, 97 insertions(+), 91 deletions(-)

diff --git a/cmdb-api/Pipfile b/cmdb-api/Pipfile
index 3402e75..b6c98dd 100644
--- a/cmdb-api/Pipfile
+++ b/cmdb-api/Pipfile
@@ -39,7 +39,7 @@ kombu = "==4.4.0"
 # common setting
 Flask-APScheduler = "==1.12.4"
 timeout-decorator = "==0.5.0"
-numpy = "==1.18.5"
+numpy = "==1.21.5"
 pandas = "==1.3.2"
 WTForms = "==3.0.0"
 email-validator = "==1.3.1"
diff --git a/cmdb-api/requirements.txt b/cmdb-api/requirements.txt
index 39b32cb..31b6886 100644
--- a/cmdb-api/requirements.txt
+++ b/cmdb-api/requirements.txt
@@ -47,7 +47,7 @@ meld3==2.0.1
 mistune==3.0.1
 more-itertools==5.0.0
 msgpack-python==0.5.6
-numpy==1.18.5
+numpy==1.21.5
 pandas==1.3.2
 Pillow==8.3.2
 pkgutil_resolve_name==1.3.10
@@ -77,4 +77,4 @@ urllib3==1.26.16
 vine==1.3.0
 Werkzeug==0.15.5
 WTForms==3.0.0
-zipp==3.16.0
\ No newline at end of file
+zipp==3.16.0
diff --git a/cmdb-ui/src/modules/cmdb/views/ci_types/attributeEditForm.vue b/cmdb-ui/src/modules/cmdb/views/ci_types/attributeEditForm.vue
index b6d940c..1b3a5c0 100644
--- a/cmdb-ui/src/modules/cmdb/views/ci_types/attributeEditForm.vue
+++ b/cmdb-ui/src/modules/cmdb/views/ci_types/attributeEditForm.vue
@@ -33,22 +33,24 @@
           />
         </a-form-item>
       </a-col>
-      <a-col :span="12"
-        ><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="别名">
-          <a-input name="alias" v-decorator="['alias', { rules: [] }]" /> </a-form-item
+      <a-col
+        :span="12"
+      ><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="别名">
+        <a-input name="alias" v-decorator="['alias', { rules: [] }]" /> </a-form-item
       ></a-col>
-      <a-col :span="12"
-        ><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="数据类型">
-          <a-select
-            :disabled="true"
-            name="value_type"
-            style="width: 100%"
-            v-decorator="['value_type', { rules: [{ required: true }] }]"
-            @change="handleChangeValueType"
-          >
-            <a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">{{ value }}</a-select-option>
-          </a-select>
-        </a-form-item></a-col
+      <a-col
+        :span="12"
+      ><a-form-item :label-col="formItemLayout.labelCol" :wrapper-col="formItemLayout.wrapperCol" label="数据类型">
+        <a-select
+          :disabled="true"
+          name="value_type"
+          style="width: 100%"
+          v-decorator="['value_type', { rules: [{ required: true }] }]"
+          @change="handleChangeValueType"
+        >
+          <a-select-option :value="key" :key="key" v-for="(value, key) in valueTypeMap">{{ value }}</a-select-option>
+        </a-select>
+      </a-form-item></a-col
       >
       <a-col :span="currentValueType === '6' ? 24 : 12">
         <a-form-item
@@ -161,8 +163,9 @@
           :wrapper-col="horizontalFormItemLayout.wrapperCol"
         >
           <template slot="label">
-            <span style="position: relative; white-space: pre"
-              >{{ `索引` }}
+            <span
+              style="position: relative; white-space: pre"
+            >{{ `索引` }}
               <a-tooltip title="字段可被用于检索,加速查询">
                 <a-icon
                   style="position: absolute; top: 3px; left: -17px; color: #2f54eb"
@@ -192,8 +195,9 @@
           :wrapper-col="horizontalFormItemLayout.wrapperCol"
         >
           <template slot="label">
-            <span style="position: relative; white-space: pre"
-              >{{ `显示` }}
+            <span
+              style="position: relative; white-space: pre"
+            >{{ `显示` }}
               <a-tooltip title="CI实例表格默认展示该字段">
                 <a-icon
                   style="position: absolute; top: 3px; left: -17px; color: #2f54eb"
@@ -237,8 +241,9 @@
           :wrapper-col="horizontalFormItemLayout.wrapperCol"
         >
           <template slot="label">
-            <span style="position: relative; white-space: pre"
-              >{{ `多值` }}
+            <span
+              style="position: relative; white-space: pre"
+            >{{ `多值` }}
               <a-tooltip title="字段的值是1个或者多个,接口返回的值的类型是list">
                 <a-icon
                   style="position: absolute; top: 3px; left: -17px; color: #2f54eb"
@@ -302,8 +307,9 @@
         <a-col :span="24" v-if="currentValueType !== '6'">
           <a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
             <template slot="label">
-              <span style="position: relative; white-space: pre"
-                >{{ `计算属性` }}
+              <span
+                style="position: relative; white-space: pre"
+              >{{ `计算属性` }}
                 <a-tooltip
                   :title="`该属性的值是通过模型的其它属性构建的表达式或者执行一段代码的方式计算而来,属性的引用方法为: {{ 属性名 }}`"
                 >
diff --git a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/typeTable.vue b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/typeTable.vue
index be1b32b..6bc8e13 100644
--- a/cmdb-ui/src/modules/cmdb/views/operation_history/modules/typeTable.vue
+++ b/cmdb-ui/src/modules/cmdb/views/operation_history/modules/typeTable.vue
@@ -60,7 +60,7 @@
       </vxe-column>
       <vxe-column field="type_id" title="模型" width="150px">
         <template #default="{ row }">
-          {{ row.operate_type === '删除模型' ? row.change.alias : row.type_id}}
+          {{ row.operate_type === '删除模型' ? row.change.alias : row.type_id }}
         </template>
       </vxe-column>
       <vxe-column field="changeDescription" title="描述">
diff --git a/cmdb-ui/src/views/setting/companyStructure/EmployeeModal.vue b/cmdb-ui/src/views/setting/companyStructure/EmployeeModal.vue
index 1c65ac3..b25fc0b 100644
--- a/cmdb-ui/src/views/setting/companyStructure/EmployeeModal.vue
+++ b/cmdb-ui/src/views/setting/companyStructure/EmployeeModal.vue
@@ -382,9 +382,9 @@
         :style="{ display: 'inline-block', width: '98%', margin: '0 7px 24px' }"
         v-if="
           attributes.findIndex((v) => v == 'bank_card_number') !== -1 ||
-          attributes.findIndex((v) => v == 'bank_card_name') !== -1 ||
-          attributes.findIndex((v) => v == 'opening_bank') !== -1 ||
-          attributes.findIndex((v) => v == 'account_opening_location') !== -1
+            attributes.findIndex((v) => v == 'bank_card_name') !== -1 ||
+            attributes.findIndex((v) => v == 'opening_bank') !== -1 ||
+            attributes.findIndex((v) => v == 'account_opening_location') !== -1
         "
       >
         <a-row :gutter="[8, { xs: 8 }]">
diff --git a/cmdb-ui/src/views/setting/components/employeeTable.vue b/cmdb-ui/src/views/setting/components/employeeTable.vue
index 979b25d..cc1a82c 100644
--- a/cmdb-ui/src/views/setting/components/employeeTable.vue
+++ b/cmdb-ui/src/views/setting/components/employeeTable.vue
@@ -179,7 +179,7 @@
       sortable
       v-if="
         checkedCols.findIndex((v) => v == 'department_name') !== -1 &&
-        attributes.findIndex((v) => v == 'department_name') !== -1
+          attributes.findIndex((v) => v == 'department_name') !== -1
       "
       key="department_name"
     >
@@ -217,7 +217,7 @@
       sortable
       v-if="
         checkedCols.findIndex((v) => v == 'position_name') !== -1 &&
-        attributes.findIndex((v) => v == 'position_name') !== -1
+          attributes.findIndex((v) => v == 'position_name') !== -1
       "
       key="position_name"
     >
@@ -251,7 +251,7 @@
       sortable
       v-if="
         checkedCols.findIndex((v) => v == 'direct_supervisor_id') !== -1 &&
-        attributes.findIndex((v) => v == 'direct_supervisor_id') !== -1
+          attributes.findIndex((v) => v == 'direct_supervisor_id') !== -1
       "
       key="direct_supervisor_id"
     >
@@ -290,8 +290,8 @@
       min-width="80"
       v-if="
         checkedCols.findIndex((v) => v == 'annual_leave') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'annual_leave') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'annual_leave') !== -1
       "
       key="annual_leave"
     >
@@ -325,8 +325,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'virtual_annual_leave') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'virtual_annual_leave') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'virtual_annual_leave') !== -1
       "
       key="virtual_annual_leave"
     >
@@ -360,8 +360,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'parenting_leave') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'parenting_leave') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'parenting_leave') !== -1
       "
       key="parenting_leave"
     >
@@ -395,8 +395,8 @@
       min-width="150"
       v-if="
         checkedCols.findIndex((v) => v == 'entry_date') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'entry_date') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'entry_date') !== -1
       "
       key="entry_date"
     >
@@ -431,8 +431,8 @@
       v-bind="tableType === 'structure' ? { filters: internOptions, 'filter-multiple': false } : {}"
       v-if="
         checkedCols.findIndex((v) => v == 'is_internship') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'is_internship') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'is_internship') !== -1
       "
       key="is_internship"
     >
@@ -469,8 +469,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'leave_date') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'leave_date') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'leave_date') !== -1
       "
       key="leave_date"
     >
@@ -504,8 +504,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'id_card') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'id_card') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'id_card') !== -1
       "
       key="id_card"
     >
@@ -539,8 +539,8 @@
       min-width="80"
       v-if="
         checkedCols.findIndex((v) => v == 'nation') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'nation') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'nation') !== -1
       "
       key="nation"
     >
@@ -574,8 +574,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'id_place') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'id_place') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'id_place') !== -1
       "
       key="id_place"
     >
@@ -609,8 +609,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'party') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'party') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'party') !== -1
       "
       key="party"
     >
@@ -644,8 +644,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'household_registration_type') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'household_registration_type') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'household_registration_type') !== -1
       "
       key="household_registration_type"
     >
@@ -679,8 +679,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'hometown') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'hometown') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'hometown') !== -1
       "
       key="hometown"
     >
@@ -714,8 +714,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'marry') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'marry') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'marry') !== -1
       "
       key="marry"
     >
@@ -749,8 +749,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'max_degree') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'max_degree') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'max_degree') !== -1
       "
       key="max_degree"
     >
@@ -784,8 +784,8 @@
       min-width="110"
       v-if="
         checkedCols.findIndex((v) => v == 'emergency_person') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'emergency_person') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'emergency_person') !== -1
       "
       key="emergency_person"
     >
@@ -819,8 +819,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'emergency_phone') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'emergency_phone') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'emergency_phone') !== -1
       "
       key="emergency_phone"
     >
@@ -854,8 +854,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'bank_card_number') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'bank_card_number') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'bank_card_number') !== -1
       "
       key="bank_card_number"
     >
@@ -889,8 +889,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'bank_card_name') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'bank_card_name') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'bank_card_name') !== -1
       "
       key="bank_card_name"
     >
@@ -924,8 +924,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'opening_bank') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'opening_bank') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'opening_bank') !== -1
       "
       key="opening_bank"
     >
@@ -959,8 +959,8 @@
       min-width="120"
       v-if="
         checkedCols.findIndex((v) => v == 'account_opening_location') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'account_opening_location') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'account_opening_location') !== -1
       "
       key="account_opening_location"
     >
@@ -993,8 +993,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'school') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'school') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'school') !== -1
       "
       key="school"
     >
@@ -1027,8 +1027,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'major') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'major') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'major') !== -1
       "
       key="major"
     >
@@ -1061,8 +1061,8 @@
       min-width="80"
       v-if="
         checkedCols.findIndex((v) => v == 'education') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'education') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'education') !== -1
       "
       key="education"
     >
@@ -1095,8 +1095,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'graduation_year') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'graduation_year') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'graduation_year') !== -1
       "
       key="graduation_year"
     >
@@ -1129,8 +1129,8 @@
       min-width="80"
       v-if="
         checkedCols.findIndex((v) => v == 'name') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'name') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'name') !== -1
       "
       key="name"
     >
@@ -1163,8 +1163,8 @@
       min-width="80"
       v-if="
         checkedCols.findIndex((v) => v == 'gender') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'gender') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'gender') !== -1
       "
       key="gender"
     >
@@ -1197,8 +1197,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'birthday') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'birthday') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'birthday') !== -1
       "
       key="birthday"
     >
@@ -1231,8 +1231,8 @@
       min-width="100"
       v-if="
         checkedCols.findIndex((v) => v == 'parental_leave_left') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'parental_leave_left') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'parental_leave_left') !== -1
       "
       key="parental_leave_left"
     >
@@ -1267,8 +1267,8 @@
       :formatter="formatDate"
       v-if="
         checkedCols.findIndex((v) => v == 'last_login') !== -1 &&
-        tableType == 'structure' &&
-        attributes.findIndex((v) => v == 'last_login') !== -1
+          tableType == 'structure' &&
+          attributes.findIndex((v) => v == 'last_login') !== -1
       "
       key="last_login"
     >