mirror of
				https://github.com/veops/cmdb.git
				synced 2025-10-31 19:39:24 +08:00 
			
		
		
		
	属性库
This commit is contained in:
		cmdb-ui/src/modules/cmdb/views/ci_types
| @@ -10,7 +10,10 @@ | ||||
|         </div> | ||||
|         <div class="attribute-card_value-type">{{ valueTypeMap[property.value_type] }}</div> | ||||
|       </div> | ||||
|       <div class="attribute-card-trigger" v-if="property.value_type === '3' || property.value_type === '4'"> | ||||
|       <div | ||||
|         class="attribute-card-trigger" | ||||
|         v-if="(property.value_type === '3' || property.value_type === '4') && !isStore" | ||||
|       > | ||||
|         <a @click="openTrigger"><ops-icon type="ops-trigger"/></a> | ||||
|       </div> | ||||
|     </div> | ||||
| @@ -47,7 +50,7 @@ | ||||
|       </a-popover> | ||||
|  | ||||
|       <a-space class="attribute-card-operation"> | ||||
|         <a><a-icon type="edit" @click="handleEdit"/></a> | ||||
|         <a v-if="!isStore"><a-icon type="edit" @click="handleEdit"/></a> | ||||
|         <a style="color:red;"><a-icon type="delete" @click="handleDelete"/></a> | ||||
|       </a-space> | ||||
|     </div> | ||||
| @@ -56,7 +59,7 @@ | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import { deleteCITypeAttributesById } from '@/modules/cmdb/api/CITypeAttr' | ||||
| import { deleteCITypeAttributesById, deleteAttributesById } from '@/modules/cmdb/api/CITypeAttr' | ||||
| import ValueTypeIcon from '@/components/CMDBValueTypeMapIcon' | ||||
| import { | ||||
|   ops_default_show, | ||||
| @@ -92,6 +95,10 @@ export default { | ||||
|       type: Number, | ||||
|       default: null, | ||||
|     }, | ||||
|     isStore: { | ||||
|       type: Boolean, | ||||
|       default: false, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     const propertyList = [ | ||||
| @@ -140,10 +147,17 @@ export default { | ||||
|         title: '警告', | ||||
|         content: `确认删除 【${that.property.alias || that.property.name}】?`, | ||||
|         onOk() { | ||||
|           if (that.isStore) { | ||||
|             deleteAttributesById(that.property.id).then(() => { | ||||
|               that.$message.success('删除成功!') | ||||
|               that.$emit('ok') | ||||
|             }) | ||||
|           } else { | ||||
|             deleteCITypeAttributesById(that.CITypeId, { attr_id: [that.property.id] }).then(() => { | ||||
|               that.$message.success('删除成功!') | ||||
|               that.$emit('ok') | ||||
|             }) | ||||
|           } | ||||
|         }, | ||||
|         onCancel() {}, | ||||
|       }) | ||||
|   | ||||
							
								
								
									
										213
									
								
								cmdb-ui/src/modules/cmdb/views/ci_types/attributeStore.vue
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										213
									
								
								cmdb-ui/src/modules/cmdb/views/ci_types/attributeStore.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,213 @@ | ||||
| <template> | ||||
|     <a-modal wrapClassName="attrbute-store-wrapper" width="80%" :visible="visible" @cancel="handleCancel"> | ||||
|       <template slot="title"> | ||||
|         <div class="attrbute-store-header"> | ||||
|           <span>属性库</span> | ||||
|           <div class="attrbute-store-search"> | ||||
|             <a-input-group compact> | ||||
|               <a-select class="attrbute-store-search-select" v-model="searchKey"> | ||||
|                 <a-select-option value="alias"> | ||||
|                   别名 | ||||
|                 </a-select-option> | ||||
|                 <a-select-option value="name"> | ||||
|                   名称 | ||||
|                 </a-select-option> | ||||
|               </a-select> | ||||
|               <a-input | ||||
|                 ref="input" | ||||
|                 slot="default" | ||||
|                 class="attrbute-store-search-input" | ||||
|                 v-model="searchValue" | ||||
|                 @pressEnter="pressEnter" | ||||
|                 allowClear | ||||
|                 @change="handleInput" | ||||
|               > | ||||
|                 <a-icon slot="suffix" type="search" @click="pressEnter" :style="{ cursor: 'pointer' }" /> | ||||
|               </a-input> | ||||
|             </a-input-group> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|       <a-spin :spinning="loading" :style="{ height: '100%' }"> | ||||
|         <a-row v-if="attrList.length"> | ||||
|           <a-col | ||||
|             class="attrbute-store-col" | ||||
|             :xxl="4" | ||||
|             :xl="6" | ||||
|             :lg="8" | ||||
|             :md="12" | ||||
|             :sm="24" | ||||
|             v-for="item in attrList" | ||||
|             :key="item.id" | ||||
|           > | ||||
|             <AttributeCard | ||||
|               @ok=" | ||||
|                 () => { | ||||
|                   searchAttributes() | ||||
|                 } | ||||
|               " | ||||
|               :isStore="true" | ||||
|               :property="item" | ||||
|             /> | ||||
|           </a-col> | ||||
|         </a-row> | ||||
|         <a-empty v-else> | ||||
|           <img slot="image" :src="require('@/assets/data_empty.png')" /> | ||||
|           <span slot="description"> 暂无数据 </span> | ||||
|         </a-empty> | ||||
|       </a-spin> | ||||
|       <template slot="footer"> | ||||
|         <a-pagination | ||||
|           size="small" | ||||
|           show-size-changer | ||||
|           show-quick-jumper | ||||
|           :current="tablePage.currentPage" | ||||
|           :total="tablePage.totalResult" | ||||
|           :show-total="(total, range) => `当前展示 ${range[0]}-${range[1]} 条数据, 共 ${total} 条`" | ||||
|           :page-size="tablePage.pageSize" | ||||
|           :default-current="1" | ||||
|           @change="pageOrSizeChange" | ||||
|           @showSizeChange="pageOrSizeChange" | ||||
|           :pageSizeOptions="['20', '50', '100', '200']" | ||||
|         /> | ||||
|       </template> | ||||
|     </a-modal> | ||||
|   </template> | ||||
|    | ||||
|   <script> | ||||
|   import { searchAttributes } from '../../api/CITypeAttr' | ||||
|   import AttributeCard from './attributeCard.vue' | ||||
|   export default { | ||||
|     name: 'AttrbuteStore', | ||||
|     components: { AttributeCard }, | ||||
|     data() { | ||||
|       return { | ||||
|         visible: false, | ||||
|         attrList: [], | ||||
|         tablePage: { | ||||
|           currentPage: 1, | ||||
|           pageSize: 50, | ||||
|           totalResult: 0, | ||||
|         }, | ||||
|         loading: false, | ||||
|         searchKey: 'alias', | ||||
|         searchValue: '', | ||||
|       } | ||||
|     }, | ||||
|     methods: { | ||||
|       open() { | ||||
|         this.visible = true | ||||
|         this.searchAttributes() | ||||
|       }, | ||||
|       handleCancel() { | ||||
|         this.visible = false | ||||
|       }, | ||||
|       async searchAttributes(currentPage = 1, pageSize = this.tablePage.pageSize) { | ||||
|         this.loading = true | ||||
|         const params = { | ||||
|           page: currentPage, | ||||
|           page_size: pageSize, | ||||
|         } | ||||
|         if (this.searchKey && this.searchValue) { | ||||
|           params[this.searchKey] = this.searchValue | ||||
|         } | ||||
|         searchAttributes(params) | ||||
|           .then((res) => { | ||||
|             this.attrList = res.attributes | ||||
|             this.tablePage = { | ||||
|               ...this.tablePage, | ||||
|               currentPage: res.page, | ||||
|               pageSize: res.page_size, | ||||
|               totalResult: res.numfound, | ||||
|             } | ||||
|           }) | ||||
|           .finally(() => { | ||||
|             this.loading = false | ||||
|           }) | ||||
|       }, | ||||
|       pageOrSizeChange(currentPage, pageSize) { | ||||
|         this.searchAttributes(currentPage, pageSize) | ||||
|       }, | ||||
|       pressEnter() { | ||||
|         this.searchAttributes(1) | ||||
|       }, | ||||
|       handleInput(e) { | ||||
|         if (!e.target.value) { | ||||
|           this.pressEnter() | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|   } | ||||
|   </script> | ||||
|    | ||||
|   <style lang="less" scoped> | ||||
|   .attrbute-store-wrapper { | ||||
|     .attrbute-store-col { | ||||
|       display: flex; | ||||
|       justify-content: center; | ||||
|     } | ||||
|   } | ||||
|   </style> | ||||
|    | ||||
|   <style lang="less"> | ||||
|   .attrbute-store-wrapper { | ||||
|     .ant-modal-body { | ||||
|       height: 70vh; | ||||
|       overflow: auto; | ||||
|     } | ||||
|     .attrbute-store-header { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|     } | ||||
|   } | ||||
|   </style> | ||||
|    | ||||
|   <style lang="less"> | ||||
|   @import '~@/style/static.less'; | ||||
|    | ||||
|   .attrbute-store-search { | ||||
|     width: 300px; | ||||
|     display: inline-block; | ||||
|     margin-right: 60px; | ||||
|     .ant-input-group.ant-input-group-compact > *:first-child, | ||||
|     .ant-input-group.ant-input-group-compact > .ant-select:first-child > .ant-select-selection { | ||||
|       border-top-left-radius: 20px !important; | ||||
|       border-bottom-left-radius: 20px !important; | ||||
|       background-color: #custom_colors[color_1]; | ||||
|       color: #fff; | ||||
|       border: none; | ||||
|     } | ||||
|     .ant-select-focused .ant-select-selection, | ||||
|     .ant-select-selection:focus { | ||||
|       box-shadow: none; | ||||
|     } | ||||
|     .ant-select-selection__rendered { | ||||
|       margin-right: 12px; | ||||
|     } | ||||
|     .ant-select-arrow { | ||||
|       color: #fff; | ||||
|       font-size: 10px; | ||||
|       right: 8px; | ||||
|     } | ||||
|     .attrbute-store-search-select { | ||||
|       width: 65px; | ||||
|       .ant-select-selection-selected-value { | ||||
|         font-size: 12px; | ||||
|       } | ||||
|     } | ||||
|     .attrbute-store-search-input { | ||||
|       display: inline-block; | ||||
|       width: calc(100% - 65px); | ||||
|       .ant-input { | ||||
|         background-color: #f0f5ff; | ||||
|         border: none; | ||||
|         border-radius: 20px; | ||||
|         &:focus { | ||||
|           box-shadow: none; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   </style> | ||||
|    | ||||
| @@ -25,7 +25,19 @@ | ||||
|               class="ops-button-primary" | ||||
|             >分组</a-button | ||||
|             > | ||||
|             <a-space v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')"> | ||||
|             <a-space> | ||||
|               <a | ||||
|                 @click=" | ||||
|                   () => { | ||||
|                     $refs.attrbuteStore.open() | ||||
|                   } | ||||
|                 " | ||||
|               >属性库</a | ||||
|               > | ||||
|               <a-dropdown v-if="permissions.includes('admin') || permissions.includes('cmdb_admin')"> | ||||
|                 <a><ops-icon type="ops-menu"/></a> | ||||
|                 <a-menu slot="overlay"> | ||||
|                   <a-menu-item key="0"> | ||||
|                     <a-upload | ||||
|                       name="file" | ||||
|                       accept="json" | ||||
| @@ -33,39 +45,51 @@ | ||||
|                       style="display: inline-block" | ||||
|                       action="/api/v0.1/ci_types/template/import/file " | ||||
|                     > | ||||
|                 <a>导入</a> | ||||
|                       <a-space | ||||
|                       ><a><a-icon type="upload"/></a><a>导入</a></a-space | ||||
|                       > | ||||
|                     </a-upload> | ||||
|                   </a-menu-item> | ||||
|                   <a-menu-item key="1"> | ||||
|                     <a-space> | ||||
|                       <a><a-icon type="download"/></a> | ||||
|                       <a href="/api/v0.1/ci_types/template/export/file">导出</a> | ||||
|                     </a-space> | ||||
|                   </a-menu-item> | ||||
|                 </a-menu> | ||||
|               </a-dropdown> | ||||
|             </a-space> | ||||
|           </div> | ||||
|           <draggable class="ci-types-left-content" :list="CITypeGroups" @end="handleChangeGroups" filter=".undraggable"> | ||||
|             <div v-for="g in CITypeGroups" :key="g.id || g.name"> | ||||
|               <div | ||||
|                 :class="`${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${ | ||||
|                 :class=" | ||||
|                   `${currentGId === g.id && !currentCId ? 'selected' : ''} ci-types-left-group ${ | ||||
|                     g.id === -1 ? 'undraggable' : '' | ||||
|                 }`" | ||||
|                   }` | ||||
|                 " | ||||
|                 @click="handleClickGroup(g.id)" | ||||
|               > | ||||
|                 <div> | ||||
|                   <OpsMoveIcon | ||||
|                     style="width: 17px; height: 17px; display: none; position: absolute; left: -3px; top: 10px" | ||||
|                   /> | ||||
|                   <span style="font-weight: 700">{{ g.name || '其他' }}</span> | ||||
|                   <span style="font-weight:700">{{ g.name || '其他' }}</span> | ||||
|                   <span :style="{ color: '#c3cdd7' }">({{ g.ci_types.length }})</span> | ||||
|                 </div> | ||||
|                 <a-space> | ||||
|                   <a-tooltip> | ||||
|                     <template slot="title">在该组中新增CI模型</template> | ||||
|                     <a><a-icon type="plus" @click="handleCreate(g)" /></a> | ||||
|                     <a><a-icon type="plus" @click="handleCreate(g)"/></a> | ||||
|                   </a-tooltip> | ||||
|                   <template v-if="g.id !== -1"> | ||||
|                     <a-tooltip> | ||||
|                       <template slot="title">编辑组名称</template> | ||||
|                       <a><a-icon type="edit" @click="handleEditGroup(g)" /></a> | ||||
|                       <a><a-icon type="edit" @click="handleEditGroup(g)"/></a> | ||||
|                     </a-tooltip> | ||||
|                     <a-tooltip> | ||||
|                       <template slot="title">删除该组</template> | ||||
|                       <a style="color: red"><a-icon type="delete" @click="handleDeleteGroup(g)" /></a> | ||||
|                       <a style="color: red"><a-icon type="delete" @click="handleDeleteGroup(g)"/></a> | ||||
|                     </a-tooltip> | ||||
|                   </template> | ||||
|                 </a-space> | ||||
| @@ -102,9 +126,9 @@ | ||||
|                   </div> | ||||
|                   <span class="ci-types-left-detail-title">{{ ci.alias || ci.name }}</span> | ||||
|                   <a-space class="ci-types-left-detail-action"> | ||||
|                     <a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)" /></a> | ||||
|                     <a><a-icon type="edit" @click="(e) => handleEdit(e, ci)" /></a> | ||||
|                     <a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete" /></a> | ||||
|                     <a><a-icon type="user-add" @click="(e) => handlePerm(e, ci)"/></a> | ||||
|                     <a><a-icon type="edit" @click="(e) => handleEdit(e, ci)"/></a> | ||||
|                     <a style="color: red" @click="(e) => handleDelete(e, ci)"><a-icon type="delete"/></a> | ||||
|                   </a-space> | ||||
|                 </div> | ||||
|               </draggable> | ||||
| @@ -185,8 +209,12 @@ | ||||
|             <a-divider :style="{ margin: '5px 0' }" /> | ||||
|             <div :style="{ textAlign: 'right' }"> | ||||
|               <a-radio-group v-model="default_order_asc"> | ||||
|                 <a-radio value="1"> 正序 </a-radio> | ||||
|                 <a-radio value="2"> 倒序 </a-radio> | ||||
|                 <a-radio value="1"> | ||||
|                   正序 | ||||
|                 </a-radio> | ||||
|                 <a-radio value="2"> | ||||
|                   倒序 | ||||
|                 </a-radio> | ||||
|               </a-radio-group> | ||||
|             </div> | ||||
|           </el-select> | ||||
| @@ -230,6 +258,7 @@ | ||||
|       </a-form> | ||||
|     </CustomDrawer> | ||||
|     <CMDBGrant ref="cmdbGrant" resourceType="CIType" app_id="cmdb" /> | ||||
|     <AttrbuteStore ref="attrbuteStore" /> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| @@ -257,6 +286,7 @@ import IconArea from './iconArea.vue' | ||||
| import SplitPane from '@/components/SplitPane' | ||||
| import CMDBGrant from '../../components/cmdbGrant' | ||||
| import { ops_move_icon as OpsMoveIcon } from '@/core/icons' | ||||
| import AttrbuteStore from './attrbuteStore.vue' | ||||
|  | ||||
| export default { | ||||
|   name: 'CITypes', | ||||
| @@ -270,6 +300,7 @@ export default { | ||||
|     IconArea, | ||||
|     SplitPane, | ||||
|     OpsMoveIcon, | ||||
|     AttrbuteStore, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
| @@ -589,7 +620,6 @@ export default { | ||||
|       } | ||||
|     }, | ||||
|     async handleChangeCITypes(e, g) { | ||||
|       console.log(111, g) | ||||
|       if (g.id && g.id !== -1) { | ||||
|         putCITypeGroupByGId(g.id, { name: g.name, type_ids: g.ci_types.map((i) => i.id) }) | ||||
|           .then(() => { | ||||
| @@ -613,7 +643,6 @@ export default { | ||||
|       const { type_id } = await createCIType(data).catch(() => { | ||||
|         this.loading = false | ||||
|       }) | ||||
|       console.log(111) | ||||
|       this.$message.success(`添加成功`) | ||||
|       if (this.selectGroup && this.selectGroup.id && this.selectGroup.id !== -1) { | ||||
|         const ids = this.selectGroup.ci_types.map((i) => i.id) | ||||
|   | ||||
| @@ -91,13 +91,8 @@ export default { | ||||
|         }) | ||||
|     }, | ||||
|   }, | ||||
|   beforeMount() { | ||||
|     this.loadTotalAttrs() | ||||
|   }, | ||||
|   methods: { | ||||
|     async handleSubmit(isCloseModal = true) { | ||||
|       console.log(this.targetKeys) | ||||
|  | ||||
|       if (this.activeKey === '2') { | ||||
|         if (this.targetKeys.length) { | ||||
|           this.confirmLoading = true | ||||
| @@ -125,6 +120,7 @@ export default { | ||||
|       this.visible = true | ||||
|       this.currentGroup = group | ||||
|       this.activeKey = '1' | ||||
|       this.loadTotalAttrs() | ||||
|       this.$nextTick(() => { | ||||
|         this.$refs.createNewAttribute.checkCanDefineComputed() | ||||
|       }) | ||||
|   | ||||
| @@ -90,7 +90,12 @@ export default { | ||||
|       ) | ||||
|     }, | ||||
|   }, | ||||
|   inject: ['refresh'], | ||||
|   inject: { | ||||
|     refresh: { | ||||
|       from: 'refresh', | ||||
|       default: null, | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     createFromTriggerTable(canAddTriggerAttr) { | ||||
|       this.visible = true | ||||
| @@ -163,8 +168,10 @@ export default { | ||||
|             await addTrigger(this.CITypeId, params) | ||||
|           } | ||||
|           this.handleCancel() | ||||
|           if (this.refresh) { | ||||
|             this.refresh() | ||||
|           } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleDetele() { | ||||
| @@ -176,7 +183,9 @@ export default { | ||||
|           deleteTrigger(that.CITypeId, that.triggerId).then(() => { | ||||
|             that.$message.success('删除成功!') | ||||
|             that.handleCancel() | ||||
|             if (that.refresh) { | ||||
|               that.refresh() | ||||
|             } | ||||
|           }) | ||||
|         }, | ||||
|       }) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user