feat(ui): update ui

This commit is contained in:
songlh 2024-08-28 16:55:07 +08:00
parent 0e60aae076
commit 89da671e46
19 changed files with 959 additions and 258 deletions

View File

@ -54,6 +54,108 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe9a9;</span>
<div class="name">caise-middleware</div>
<div class="code-name">&amp;#xe9a9;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a7;</span>
<div class="name">caise-database</div>
<div class="code-name">&amp;#xe9a7;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a8;</span>
<div class="name">caise-business</div>
<div class="code-name">&amp;#xe9a8;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a6;</span>
<div class="name">caise- virtualization</div>
<div class="code-name">&amp;#xe9a6;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a4;</span>
<div class="name">caise-storage_pool</div>
<div class="code-name">&amp;#xe9a4;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a5;</span>
<div class="name">caise-storage_volume</div>
<div class="code-name">&amp;#xe9a5;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a3;</span>
<div class="name">ciase-aix</div>
<div class="code-name">&amp;#xe9a3;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99b;</span>
<div class="name">caise_pool</div>
<div class="code-name">&amp;#xe99b;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99c;</span>
<div class="name">caise-ip_address</div>
<div class="code-name">&amp;#xe99c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99d;</span>
<div class="name">caise-computer_room</div>
<div class="code-name">&amp;#xe99d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99e;</span>
<div class="name">caise-rack</div>
<div class="code-name">&amp;#xe99e;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99f;</span>
<div class="name">caise-pc</div>
<div class="code-name">&amp;#xe99f;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a0;</span>
<div class="name">caise-bandwidth_line</div>
<div class="code-name">&amp;#xe9a0;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a1;</span>
<div class="name">caise-fiber</div>
<div class="code-name">&amp;#xe9a1;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe9a2;</span>
<div class="name">caise-disk_array</div>
<div class="code-name">&amp;#xe9a2;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe99a;</span>
<div class="name">veops-group</div>
<div class="code-name">&amp;#xe99a;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe999;</span>
<div class="name">veops-inheritance</div>
<div class="code-name">&amp;#xe999;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe998;</span>
<div class="name">veops-department</div>
@ -5520,9 +5622,9 @@
<pre><code class="language-css"
>@font-face {
font-family: 'iconfont';
src: url('iconfont.woff2?t=1724653006782') format('woff2'),
url('iconfont.woff?t=1724653006782') format('woff'),
url('iconfont.ttf?t=1724653006782') format('truetype');
src: url('iconfont.woff2?t=1724834571283') format('woff2'),
url('iconfont.woff?t=1724834571283') format('woff'),
url('iconfont.ttf?t=1724834571283') format('truetype');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -5548,6 +5650,159 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont caise-middleware"></span>
<div class="name">
caise-middleware
</div>
<div class="code-name">.caise-middleware
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-database"></span>
<div class="name">
caise-database
</div>
<div class="code-name">.caise-database
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-business"></span>
<div class="name">
caise-business
</div>
<div class="code-name">.caise-business
</div>
</li>
<li class="dib">
<span class="icon iconfont a-caise-virtualization"></span>
<div class="name">
caise- virtualization
</div>
<div class="code-name">.a-caise-virtualization
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-storage_pool"></span>
<div class="name">
caise-storage_pool
</div>
<div class="code-name">.caise-storage_pool
</div>
</li>
<li class="dib">
<span class="icon iconfont a-caise-storage_volume1"></span>
<div class="name">
caise-storage_volume
</div>
<div class="code-name">.a-caise-storage_volume1
</div>
</li>
<li class="dib">
<span class="icon iconfont ciase-aix"></span>
<div class="name">
ciase-aix
</div>
<div class="code-name">.ciase-aix
</div>
</li>
<li class="dib">
<span class="icon iconfont caise_pool"></span>
<div class="name">
caise_pool
</div>
<div class="code-name">.caise_pool
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-ip_address"></span>
<div class="name">
caise-ip_address
</div>
<div class="code-name">.caise-ip_address
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-computer_room"></span>
<div class="name">
caise-computer_room
</div>
<div class="code-name">.caise-computer_room
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-rack"></span>
<div class="name">
caise-rack
</div>
<div class="code-name">.caise-rack
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-pc"></span>
<div class="name">
caise-pc
</div>
<div class="code-name">.caise-pc
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-bandwidth_line"></span>
<div class="name">
caise-bandwidth_line
</div>
<div class="code-name">.caise-bandwidth_line
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-fiber"></span>
<div class="name">
caise-fiber
</div>
<div class="code-name">.caise-fiber
</div>
</li>
<li class="dib">
<span class="icon iconfont caise-disk_array"></span>
<div class="name">
caise-disk_array
</div>
<div class="code-name">.caise-disk_array
</div>
</li>
<li class="dib">
<span class="icon iconfont veops-group"></span>
<div class="name">
veops-group
</div>
<div class="code-name">.veops-group
</div>
</li>
<li class="dib">
<span class="icon iconfont veops-inheritance"></span>
<div class="name">
veops-inheritance
</div>
<div class="code-name">.veops-inheritance
</div>
</li>
<li class="dib">
<span class="icon iconfont veops-department"></span>
<div class="name">
@ -13747,6 +14002,142 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-middleware"></use>
</svg>
<div class="name">caise-middleware</div>
<div class="code-name">#caise-middleware</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-database"></use>
</svg>
<div class="name">caise-database</div>
<div class="code-name">#caise-database</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-business"></use>
</svg>
<div class="name">caise-business</div>
<div class="code-name">#caise-business</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#a-caise-virtualization"></use>
</svg>
<div class="name">caise- virtualization</div>
<div class="code-name">#a-caise-virtualization</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-storage_pool"></use>
</svg>
<div class="name">caise-storage_pool</div>
<div class="code-name">#caise-storage_pool</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#a-caise-storage_volume1"></use>
</svg>
<div class="name">caise-storage_volume</div>
<div class="code-name">#a-caise-storage_volume1</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#ciase-aix"></use>
</svg>
<div class="name">ciase-aix</div>
<div class="code-name">#ciase-aix</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise_pool"></use>
</svg>
<div class="name">caise_pool</div>
<div class="code-name">#caise_pool</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-ip_address"></use>
</svg>
<div class="name">caise-ip_address</div>
<div class="code-name">#caise-ip_address</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-computer_room"></use>
</svg>
<div class="name">caise-computer_room</div>
<div class="code-name">#caise-computer_room</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-rack"></use>
</svg>
<div class="name">caise-rack</div>
<div class="code-name">#caise-rack</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-pc"></use>
</svg>
<div class="name">caise-pc</div>
<div class="code-name">#caise-pc</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-bandwidth_line"></use>
</svg>
<div class="name">caise-bandwidth_line</div>
<div class="code-name">#caise-bandwidth_line</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-fiber"></use>
</svg>
<div class="name">caise-fiber</div>
<div class="code-name">#caise-fiber</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#caise-disk_array"></use>
</svg>
<div class="name">caise-disk_array</div>
<div class="code-name">#caise-disk_array</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#veops-group"></use>
</svg>
<div class="name">veops-group</div>
<div class="code-name">#veops-group</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#veops-inheritance"></use>
</svg>
<div class="name">veops-inheritance</div>
<div class="code-name">#veops-inheritance</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#veops-department"></use>

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 3857903 */
src: url('iconfont.woff2?t=1724653006782') format('woff2'),
url('iconfont.woff?t=1724653006782') format('woff'),
url('iconfont.ttf?t=1724653006782') format('truetype');
src: url('iconfont.woff2?t=1724834571283') format('woff2'),
url('iconfont.woff?t=1724834571283') format('woff'),
url('iconfont.ttf?t=1724834571283') format('truetype');
}
.iconfont {
@ -13,6 +13,74 @@
-moz-osx-font-smoothing: grayscale;
}
.caise-middleware:before {
content: "\e9a9";
}
.caise-database:before {
content: "\e9a7";
}
.caise-business:before {
content: "\e9a8";
}
.a-caise-virtualization:before {
content: "\e9a6";
}
.caise-storage_pool:before {
content: "\e9a4";
}
.a-caise-storage_volume1:before {
content: "\e9a5";
}
.ciase-aix:before {
content: "\e9a3";
}
.caise_pool:before {
content: "\e99b";
}
.caise-ip_address:before {
content: "\e99c";
}
.caise-computer_room:before {
content: "\e99d";
}
.caise-rack:before {
content: "\e99e";
}
.caise-pc:before {
content: "\e99f";
}
.caise-bandwidth_line:before {
content: "\e9a0";
}
.caise-fiber:before {
content: "\e9a1";
}
.caise-disk_array:before {
content: "\e9a2";
}
.veops-group:before {
content: "\e99a";
}
.veops-inheritance:before {
content: "\e999";
}
.veops-department:before {
content: "\e998";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,125 @@
"css_prefix_text": "",
"description": "",
"glyphs": [
{
"icon_id": "41655608",
"name": "caise-middleware",
"font_class": "caise-middleware",
"unicode": "e9a9",
"unicode_decimal": 59817
},
{
"icon_id": "41655599",
"name": "caise-database",
"font_class": "caise-database",
"unicode": "e9a7",
"unicode_decimal": 59815
},
{
"icon_id": "41655591",
"name": "caise-business",
"font_class": "caise-business",
"unicode": "e9a8",
"unicode_decimal": 59816
},
{
"icon_id": "41655550",
"name": "caise- virtualization",
"font_class": "a-caise-virtualization",
"unicode": "e9a6",
"unicode_decimal": 59814
},
{
"icon_id": "41654680",
"name": "caise-storage_pool",
"font_class": "caise-storage_pool",
"unicode": "e9a4",
"unicode_decimal": 59812
},
{
"icon_id": "41654676",
"name": "caise-storage_volume",
"font_class": "a-caise-storage_volume1",
"unicode": "e9a5",
"unicode_decimal": 59813
},
{
"icon_id": "41654608",
"name": "ciase-aix",
"font_class": "ciase-aix",
"unicode": "e9a3",
"unicode_decimal": 59811
},
{
"icon_id": "41654233",
"name": "caise_pool",
"font_class": "caise_pool",
"unicode": "e99b",
"unicode_decimal": 59803
},
{
"icon_id": "41654237",
"name": "caise-ip_address",
"font_class": "caise-ip_address",
"unicode": "e99c",
"unicode_decimal": 59804
},
{
"icon_id": "41654249",
"name": "caise-computer_room",
"font_class": "caise-computer_room",
"unicode": "e99d",
"unicode_decimal": 59805
},
{
"icon_id": "41654271",
"name": "caise-rack",
"font_class": "caise-rack",
"unicode": "e99e",
"unicode_decimal": 59806
},
{
"icon_id": "41654276",
"name": "caise-pc",
"font_class": "caise-pc",
"unicode": "e99f",
"unicode_decimal": 59807
},
{
"icon_id": "41654305",
"name": "caise-bandwidth_line",
"font_class": "caise-bandwidth_line",
"unicode": "e9a0",
"unicode_decimal": 59808
},
{
"icon_id": "41654323",
"name": "caise-fiber",
"font_class": "caise-fiber",
"unicode": "e9a1",
"unicode_decimal": 59809
},
{
"icon_id": "41654369",
"name": "caise-disk_array",
"font_class": "caise-disk_array",
"unicode": "e9a2",
"unicode_decimal": 59810
},
{
"icon_id": "41643869",
"name": "veops-group",
"font_class": "veops-group",
"unicode": "e99a",
"unicode_decimal": 59802
},
{
"icon_id": "41637123",
"name": "veops-inheritance",
"font_class": "veops-inheritance",
"unicode": "e999",
"unicode_decimal": 59801
},
{
"icon_id": "41570722",
"name": "veops-department",

Binary file not shown.

View File

@ -31,7 +31,7 @@ export default {
text-align: center;
border-radius: 4px;
&:hover {
background: linear-gradient(0deg, rgba(0, 80, 201, 0.2) 0%, rgba(174, 207, 255, 0.06) 86.76%);
// background: linear-gradient(0deg, rgba(0, 80, 201, 0.2) 0%, rgba(174, 207, 255, 0.06) 86.76%);
color: @layout-header-font-selected-color;
}
}

View File

@ -5,7 +5,6 @@
v-for="route in defaultShowRoutes"
:key="route.name"
@click="() => handleClick(route)"
:title="$t(route.meta.title)"
>
{{ route.meta.title }}
</span>
@ -119,7 +118,9 @@ export default {
line-height: @layout-header-line-height;
display: inline-block;
}
> span:hover,
> span:hover {
background-color: #f0f2f5;
}
.top-menu-selected {
font-weight: bold;
color: @layout-header-font-selected-color;

View File

@ -10,10 +10,25 @@
<ops-icon class="common-settings-btn-icon" type="veops-setting" />
<span class="common-settings-btn-text">{{ $t('settings') }}</span>
</span>
<span class="locale" @click="changeLang">{{ locale === 'zh' ? '简中' : 'EN' }}</span>
<a-popover
trigger="click"
:overlayStyle="{ width: '150px' }"
overlayClassName="lang-popover-wrap"
placement="bottomRight"
:getPopupContainer="(trigger) => trigger.parentNode"
>
<span class="locale">{{ languageList.find((lang) => lang.key === locale).title }}</span>
<div class="lang-menu" slot="content">
<a
v-for="(lang) in languageList"
:key="lang.key"
:class="['lang-menu-item', lang.key === locale ? 'lang-menu-item_active' : '']"
@click="changeLang(lang.key)"
>
{{ lang.title }}
</a>
</div>
</a-popover>
<a-popover
:overlayStyle="{ width: '130px' }"
placement="bottomRight"
overlayClassName="custom-user"
>
@ -29,7 +44,7 @@
<span>{{ $t('topMenu.logout') }}</span>
</div>
</template>
<span class="action ant-dropdown-link user-dropdown-menu">
<span class="action ant-dropdown-link user-dropdown-menu user-info-wrap">
<a-avatar
v-if="avatar()"
class="avatar"
@ -54,6 +69,20 @@ export default {
components: {
DocumentLink,
},
data() {
return {
languageList: [
{
title: '简中',
key: 'zh'
},
{
title: 'EN',
key: 'en'
},
]
}
},
computed: {
...mapState(['user', 'locale']),
hasBackendPermission() {
@ -81,14 +110,9 @@ export default {
handleClick() {
this.$router.push('/setting')
},
changeLang() {
if (this.locale === 'zh') {
this.SET_LOCALE('en')
this.$i18n.locale = 'en'
} else {
this.SET_LOCALE('zh')
this.$i18n.locale = 'zh'
}
changeLang(lang) {
this.SET_LOCALE(lang)
this.$i18n.locale = lang
this.$nextTick(() => {
setDocumentTitle(`${this.$t(this.$route.meta.title)} - ${domTitle}`)
})
@ -124,6 +148,15 @@ export default {
color: @primary-color;
}
}
.lang-popover-wrap {
width: 70px;
padding: 0px;
.ant-popover-inner-content {
padding: 0px;
}
}
</style>
<style lang="less" scoped>
@ -150,6 +183,47 @@ export default {
font-weight: 400;
color: #4E5969;
}
&:hover {
.commen-settings-btn-text {
color: #2F54EB;
}
}
}
.lang-menu {
width: 100%;
display: flex;
flex-direction: column;
&-item {
width: 100%;
padding: 5px 10px;
cursor: pointer;
color: #4E5969;
&_active {
color: #2F54EB;
background-color: #f0f5ff;
}
&:hover {
color: #2F54EB;
}
}
}
.user-info-wrap {
.avatar {
transition: all 0.2s;
border: solid 1px transparent;
}
&:hover {
.avatar {
border-color: #2F54EB;
}
}
}
}
</style>

View File

@ -1,212 +1,219 @@
<template>
<a-modal :width="680" :title="title" :visible="visible" @ok="handleOk" @cancel="handleCancel">
<CustomRadio
:radioList="[
{ value: 1, label: $t('cmdb.components.all') },
{ value: 2, label: $t('cmdb.components.customize'), layout: 'vertical' },
{ value: 3, label: $t('cmdb.components.none') },
]"
:value="radioValue"
@change="changeRadioValue"
>
<template slot="extra_2" v-if="radioValue === 2">
<treeselect
v-if="colType === 'read_attr'"
v-model="selectedAttr"
:multiple="true"
:clearable="true"
searchable
:options="attrGroup"
:placeholder="$t('cmdb.ciType.selectAttributes')"
value-consists-of="LEAF_PRIORITY"
:limit="10"
:limitText="(count) => `+ ${count}`"
:normalizer="
(node) => {
return {
id: node.name || -1,
label: node.alias || node.name || $t('other'),
title: node.alias || node.name || $t('other'),
children: node.attributes,
}
}
"
appendToBody
zIndex="1050"
>
</treeselect>
<a-form-model
:model="form"
:rules="rules"
v-if="colType === 'read_ci'"
:labelCol="{ span: 2 }"
:wrapperCol="{ span: 10 }"
ref="form"
>
<a-form-model-item :label="$t('name')" prop="name">
<a-input v-model="form.name" />
</a-form-model-item>
<FilterComp
ref="filterComp"
:isDropdown="false"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
@setExpFromFilter="setExpFromFilter"
:expression="expression"
/>
</a-form-model>
</template>
</CustomRadio>
</a-modal>
</template>
<script>
import { grantCiType, revokeCiType } from '../../api/CIType'
import { getCITypeAttributesByTypeIds } from '../../api/CITypeAttr'
import FilterComp from '@/components/CMDBFilterComp'
export default {
name: 'ReadGrantModal',
components: { FilterComp },
props: {
CITypeId: {
type: Number,
default: null,
},
},
inject: {
provide_attrGroup: {
from: 'attrGroup',
},
provide_filerPerimissions: {
from: 'filerPerimissions',
},
},
data() {
return {
visible: false,
colType: '',
row: {},
radioValue: 1,
radioStyle: {
display: 'block',
height: '30px',
lineHeight: '30px',
},
selectedAttr: [],
ruleList: [],
canSearchPreferenceAttrList: [],
expression: '',
form: {
name: '',
},
rules: {
name: [{ required: true, message: this.$t('cmdb.components.customizeFilterName') }],
},
}
},
computed: {
title() {
if (this.colType === 'read_attr') {
return this.$t('cmdb.components.attributeGrant')
}
return this.$t('cmdb.components.ciGrant')
},
attrGroup() {
return this.provide_attrGroup()
},
filerPerimissions() {
return this.provide_filerPerimissions()
},
filterKey() {
if (this.colType === 'read_attr') {
return 'attr_filter'
}
return 'ci_filter'
},
},
methods: {
async open(colType, row) {
this.visible = true
this.colType = colType
this.row = row
this.form = {
name: '',
}
if (this.colType === 'read_ci') {
await getCITypeAttributesByTypeIds({ type_ids: this.CITypeId }).then((res) => {
this.canSearchPreferenceAttrList = res.attributes.filter((item) => item.value_type !== '6')
})
}
if (this.filerPerimissions[row.rid]) {
const _tempValue = this.filerPerimissions[row.rid][this.filterKey]
if (_tempValue && _tempValue.length) {
this.radioValue = 2
if (this.colType === 'read_attr') {
this.selectedAttr = _tempValue
} else {
this.expression = `q=${_tempValue}`
this.form = {
name: this.filerPerimissions[row.rid].name || '',
}
this.$nextTick(() => {
this.$refs.filterComp.visibleChange(true)
})
}
}
}
},
async handleOk() {
if (this.radioValue === 1) {
await grantCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? [] : undefined,
ci_filter: this.colType === 'read_ci' ? '' : undefined,
})
} else if (this.radioValue === 2) {
if (this.colType === 'read_ci') {
this.$refs.filterComp.handleSubmit()
}
await grantCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? this.selectedAttr : undefined,
ci_filter: this.colType === 'read_ci' ? this.expression.slice(2) : undefined,
name: this.colType === 'read_ci' ? this.form.name : undefined,
})
} else {
const _tempValue = this.filerPerimissions?.[this.row.rid]?.[this.filterKey]
await revokeCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? _tempValue : undefined,
ci_filter: this.colType === 'read_ci' ? _tempValue : undefined,
})
}
this.$emit('updateTableDataRead', this.row, this.radioValue === 1 || this.radioValue === 2)
this.handleCancel()
},
handleCancel() {
this.radioValue = 1
this.selectedAttr = []
if (this.$refs.form) {
this.$refs.form.resetFields()
}
this.visible = false
},
setExpFromFilter(filterExp) {
let expression = ''
if (filterExp) {
expression = `q=${filterExp}`
}
this.expression = expression
},
changeRadioValue(value) {
if (this.id_filter) {
this.$message.warning(this.$t('cmdb.serviceTree.grantedByServiceTreeTips'))
} else {
this.radioValue = value
}
},
},
}
</script>
<style></style>
<template>
<a-modal :width="680" :title="title" :visible="visible" @ok="handleOk" @cancel="handleCancel">
<CustomRadio
:radioList="[
{ value: 1, label: $t('cmdb.components.all') },
{ value: 2, label: $t('cmdb.components.customize'), layout: 'vertical' },
{ value: 3, label: $t('cmdb.components.none') },
]"
:value="radioValue"
@change="changeRadioValue"
>
<template slot="extra_2" v-if="radioValue === 2">
<treeselect
v-if="colType === 'read_attr'"
v-model="selectedAttr"
:multiple="true"
:clearable="true"
searchable
:options="attrGroup"
:placeholder="$t('cmdb.ciType.selectAttributes')"
value-consists-of="LEAF_PRIORITY"
:limit="10"
:limitText="(count) => `+ ${count}`"
:normalizer="
(node) => {
return {
id: node.name || -1,
label: node.alias || node.name || $t('other'),
title: node.alias || node.name || $t('other'),
children: node.attributes,
}
}
"
appendToBody
zIndex="1050"
>
</treeselect>
<a-form-model
:model="form"
:rules="rules"
v-if="colType === 'read_ci'"
:labelCol="{ span: 2 }"
:wrapperCol="{ span: 10 }"
ref="form"
>
<a-form-model-item :label="$t('name')" prop="name">
<a-input v-model="form.name" />
</a-form-model-item>
<FilterComp
ref="filterComp"
:isDropdown="false"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
@setExpFromFilter="setExpFromFilter"
:expression="expression"
/>
<div class="read-ci-tip">{{ $t('cmdb.ciType.ciGrantTip') }}</div>
</a-form-model>
</template>
</CustomRadio>
</a-modal>
</template>
<script>
import { grantCiType, revokeCiType } from '../../api/CIType'
import { getCITypeAttributesByTypeIds } from '../../api/CITypeAttr'
import FilterComp from '@/components/CMDBFilterComp'
export default {
name: 'ReadGrantModal',
components: { FilterComp },
props: {
CITypeId: {
type: Number,
default: null,
},
},
inject: {
provide_attrGroup: {
from: 'attrGroup',
},
provide_filerPerimissions: {
from: 'filerPerimissions',
},
},
data() {
return {
visible: false,
colType: '',
row: {},
radioValue: 1,
radioStyle: {
display: 'block',
height: '30px',
lineHeight: '30px',
},
selectedAttr: [],
ruleList: [],
canSearchPreferenceAttrList: [],
expression: '',
form: {
name: '',
},
rules: {
name: [{ required: true, message: this.$t('cmdb.components.customizeFilterName') }],
},
}
},
computed: {
title() {
if (this.colType === 'read_attr') {
return this.$t('cmdb.components.attributeGrant')
}
return this.$t('cmdb.components.ciGrant')
},
attrGroup() {
return this.provide_attrGroup()
},
filerPerimissions() {
return this.provide_filerPerimissions()
},
filterKey() {
if (this.colType === 'read_attr') {
return 'attr_filter'
}
return 'ci_filter'
},
},
methods: {
async open(colType, row) {
this.visible = true
this.colType = colType
this.row = row
this.form = {
name: '',
}
if (this.colType === 'read_ci') {
await getCITypeAttributesByTypeIds({ type_ids: this.CITypeId }).then((res) => {
this.canSearchPreferenceAttrList = res.attributes.filter((item) => item.value_type !== '6')
})
}
if (this.filerPerimissions[row.rid]) {
const _tempValue = this.filerPerimissions[row.rid][this.filterKey]
if (_tempValue && _tempValue.length) {
this.radioValue = 2
if (this.colType === 'read_attr') {
this.selectedAttr = _tempValue
} else {
this.expression = `q=${_tempValue}`
this.form = {
name: this.filerPerimissions[row.rid].name || '',
}
this.$nextTick(() => {
this.$refs.filterComp.visibleChange(true)
})
}
}
}
},
async handleOk() {
if (this.radioValue === 1) {
await grantCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? [] : undefined,
ci_filter: this.colType === 'read_ci' ? '' : undefined,
})
} else if (this.radioValue === 2) {
if (this.colType === 'read_ci') {
this.$refs.filterComp.handleSubmit()
}
await grantCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? this.selectedAttr : undefined,
ci_filter: this.colType === 'read_ci' ? this.expression.slice(2) : undefined,
name: this.colType === 'read_ci' ? this.form.name : undefined,
})
} else {
const _tempValue = this.filerPerimissions?.[this.row.rid]?.[this.filterKey]
await revokeCiType(this.CITypeId, this.row.rid, {
perms: ['read'],
attr_filter: this.colType === 'read_attr' ? _tempValue : undefined,
ci_filter: this.colType === 'read_ci' ? _tempValue : undefined,
})
}
this.$emit('updateTableDataRead', this.row, this.radioValue === 1 || this.radioValue === 2)
this.handleCancel()
},
handleCancel() {
this.radioValue = 1
this.selectedAttr = []
if (this.$refs.form) {
this.$refs.form.resetFields()
}
this.visible = false
},
setExpFromFilter(filterExp) {
let expression = ''
if (filterExp) {
expression = `q=${filterExp}`
}
this.expression = expression
},
changeRadioValue(value) {
if (this.id_filter) {
this.$message.warning(this.$t('cmdb.serviceTree.grantedByServiceTreeTips'))
} else {
this.radioValue = value
}
},
},
}
</script>
<style lang="less" scoped>
.read-ci-tip {
font-size: 12px;
line-height: 22px;
color: #a5a9bc;
}
</style>

View File

@ -65,9 +65,7 @@
<a><a-icon type="question-circle"/></a>
</a-tooltip>
</a-input>
<a-tooltip :title="$t('reset')">
<a-button @click="reset">{{ $t('reset') }}</a-button>
</a-tooltip>
<a-button @click="reset">{{ $t('reset') }}</a-button>
<FilterComp
ref="filterComp"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList"
@ -310,6 +308,11 @@ export default {
height: 32px;
.search-form-bar-filter {
.ops_display_wrapper(transparent);
&:hover {
color: @primary-color;
}
.search-form-bar-filter-icon {
color: @primary-color;
font-size: 12px;

View File

@ -62,7 +62,7 @@ const cmdb_en = {
desc: 'Reverse order',
uniqueKey: 'Unique Identifies',
uniqueKeySelect: 'Please select a unique identifier',
uniqueKeyTips: 'json/password/computed/choice can not be unique identifies',
uniqueKeyTips: 'json/password/computed/selectList can not be unique identifies',
notfound: 'Can\'t find what you want?',
cannotDeleteGroupTips: 'There is data under this group and cannot be deleted!',
confirmDeleteGroup: 'Are you sure you want to delete group [{groupName}]?',
@ -142,7 +142,7 @@ const cmdb_en = {
selectCIType: 'Please select a CMDB CIType',
selectCITypeAttributes: 'Please select CIType attributes',
selectAttributes: 'Please select attributes',
choiceScriptDemo: 'class ChoiceValue(object):\n @staticmethod\n def values():\n """\n Execution entry, returns predefined value\n :return: Returns a list, the type of the value is the same as the type of the attribute\n For example:\n return ["online", "offline"]\n """\n return []',
choiceScriptDemo: 'class ChoiceValue(object):\n @staticmethod\n def values():\n """\n Execution entry, returns select list\n :return: Returns a list, the type of the value is the same as the type of the attribute\n For example:\n return ["online", "offline"]\n """\n return []',
valueExisted: 'The current value already exists!',
addRelation: 'Add Relation',
sourceCIType: 'Source CIType',
@ -306,6 +306,7 @@ const cmdb_en = {
departmentCascadeDisplay: 'Cascade Display',
filterUsers: 'Filter Users',
enum: 'Enum',
ciGrantTip: `Filter conditions can be changed dynamically using {{}} referenced variables, currently user variables are supported, such as {{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`,
},
components: {
unselectAttributes: 'Unselected',
@ -391,7 +392,7 @@ const cmdb_en = {
tips2: '1. Click to download the template, and users can customize the header of the template file, including model properties and model associations',
// eslint-disable-next-line no-template-curly-in-string
tips3: '2. The red color in the template file represents the model relationship, such as the $Product. Product Name (${Model Name}. {Attribute Name}) column, which establishes the relationship with the product.',
tips4: '3. In the download template Excel file, the predefined values of attributes will be set as dropdown options. Please note that due to the limitations of Excel itself, a single dropdown box is limited to a maximum of 255 characters. If it exceeds 255 characters, we will not set the dropdown options for this attribute',
tips4: `3. The download template excel file will have the property's drop-down list enumeration configured as a drop-down option. Please note that due to the limitations of Excel itself, a single dropdown box is limited to a maximum of 255 characters. If it exceeds 255 characters, we will not set the dropdown options for this attribute`,
tips5: '4. When using Excel templates, please ensure that a single file does not exceed 5000 lines.',
},
preference: {
@ -650,7 +651,7 @@ if __name__ == "__main__":
tips4: 'At least one field must be selected',
tips5: 'Search name | alias',
tips6: 'Speed up retrieval, full-text search possible, no need to use conditional filtering\n\n json/link/password currently does not support indexing \n\nText characters longer than 190 cannot be indexed',
tips7: 'The form of expression is a drop-down box, and the value must be in the predefined value',
tips7: 'Whether to configure a select list',
tips8: 'Multiple values, such as intranet IP',
tips9: 'For front-end only',
tips10: 'Other attributes of the CIType are computed using expressions\n\nA code snippet computes the returned value.',

View File

@ -62,7 +62,7 @@ const cmdb_zh = {
desc: '倒序',
uniqueKey: '唯一标识',
uniqueKeySelect: '请选择唯一标识',
uniqueKeyTips: 'json、密码、计算属性、预定义值属性不能作为唯一标识',
uniqueKeyTips: 'json、密码、计算属性、下拉列表属性不能作为唯一标识',
notfound: '找不到想要的?',
cannotDeleteGroupTips: '该分组下有数据, 不能删除!',
confirmDeleteGroup: '确定要删除分组 【{groupName}】 吗?',
@ -142,7 +142,7 @@ const cmdb_zh = {
selectCIType: '请选择CMDB模型',
selectCITypeAttributes: '请选择模型属性',
selectAttributes: '请选择属性',
choiceScriptDemo: 'class ChoiceValue(object):\n @staticmethod\n def values():\n """\n 执行入口, 返回预定义值\n :return: 返回一个列表, 值的类型同属性的类型\n 例如:\n return ["在线", "下线"]\n """\n return []',
choiceScriptDemo: 'class ChoiceValue(object):\n @staticmethod\n def values():\n """\n 执行入口, 返回下拉列表\n :return: 返回一个列表, 值的类型同属性的类型\n 例如:\n return ["在线", "下线"]\n """\n return []',
valueExisted: '当前值已存在!',
addRelation: '新增关系',
sourceCIType: '源模型',
@ -306,6 +306,7 @@ const cmdb_zh = {
departmentCascadeDisplay: '部门级联显示',
filterUsers: '筛选用户',
enum: '枚举',
ciGrantTip: `筛选条件可使用{{}}引用变量实现动态变化,目前支持用户变量,如{{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`,
},
components: {
unselectAttributes: '未选属性',
@ -390,7 +391,7 @@ const cmdb_zh = {
tips2: '1. 点击下载模板,用户可以自定义模板文件的表头,包括模型属性、模型关联',
// eslint-disable-next-line no-template-curly-in-string
tips3: '2. 模板文件中红色为模型关系,如$产品.产品名(${模型名}.{属性名})这一列就可建立和产品之间的关系',
tips4: '3. 下载模板excel文件中会将属性的预定义值置为下拉选项请注意受excel本身的限制单个下拉框限制了最多255个字符如果超过255个字符我们不会设置该属性的下拉选项',
tips4: '3. 下载模板excel文件中会将属性的下拉列表枚举配置置为下拉选项请注意受excel本身的限制单个下拉框限制了最多255个字符如果超过255个字符我们不会设置该属性的下拉选项',
tips5: '4. 在使用excel模板时请确保单个文件不超过5000行',
},
preference: {
@ -649,7 +650,7 @@ if __name__ == "__main__":
tips4: '必须至少选择一个字段',
tips5: '搜索 名称 | 别名',
tips6: '加快检索, 可以全文搜索, 无需使用条件过滤\n\n json、链接、密码目前不支持建索引 \n\n文本字符长度超过190不能建索引',
tips7: '表现形式是下拉框, 值必须在预定义值里',
tips7: '是否配置下拉列表',
tips8: '多值, 比如内网IP',
tips9: '仅针对前端',
tips10: '模型的其他属性通过表达式的方式计算出来\n\n一个代码片段计算返回的值',

View File

@ -92,6 +92,10 @@ export default {
font-size: 14px;
font-weight: 400;
&:hover {
color: @primary-color;
}
&:not(:first-child) {
border-left: solid 1px @border-color-base;
}
@ -99,6 +103,10 @@ export default {
&_active {
background-color: @primary-color;
color: #FFFFFF;
&:hover {
color: #FFFFFF;
}
}
}
}

View File

@ -107,4 +107,12 @@ export default {
.grant-config-wrap {
overflow: auto;
}
.ops-tab.ant-tabs {
/deep/ .ant-tabs-bar {
.ant-tabs-tab:hover {
color: @primary-color;
}
}
}
</style>

View File

@ -1,14 +1,16 @@
<template>
<div class="relation-table" :style="{ padding: '0 20px 20px' }">
<a-button
v-if="!isInGrantComp"
style="margin-bottom: 10px"
@click="handleCreate"
type="primary"
size="small"
icon="plus"
>{{ $t('cmdb.ciType.addRelation') }}</a-button
>
<div v-if="!isInGrantComp" class="relation-table-add">
<a-button
type="primary"
@click="handleCreate"
ghost
class="ops-button-ghost"
>
<ops-icon type="veops-increase" />
{{ $t('create') }}
</a-button>
</div>
<vxe-table
ref="xTable"
stripe
@ -653,6 +655,12 @@ export default {
/deep/ .vxe-cell {
max-height: max-content !important;
}
&-add {
margin-bottom: 10px;
display: flex;
justify-content: flex-end;
}
}
.table-attribute-row {
display: inline-flex;

View File

@ -1,13 +1,15 @@
<template>
<div class="ci-types-triggers">
<div style="margin-bottom: 10px">
<div class="ci-types-triggers-add">
<a-button
type="primary"
@click="handleAddTrigger"
size="small"
icon="plus"
>{{ $t('cmdb.ciType.newTrigger') }}</a-button
ghost
class="ops-button-ghost"
>
<ops-icon type="veops-increase" />
{{ $t('create') }}
</a-button>
</div>
<ops-table
stripe
@ -134,5 +136,11 @@ export default {
<style lang="less" scoped>
.ci-types-triggers {
padding: 0 20px 20px;
&-add {
margin-bottom: 10px;
display: flex;
justify-content: flex-end;
}
}
</style>

View File

@ -344,6 +344,10 @@ export default {
cursor: pointer;
flex-shrink: 0;
&:hover {
color: @primary-color;
}
&_active {
background-color: @primary-color_3;
color: @primary-color;