Merge pull request #606 from veops/dev_ui_240828

feat(ui): update ui
This commit is contained in:
Leo Song 2024-08-28 16:55:45 +08:00 committed by GitHub
commit ad91d208b8
19 changed files with 959 additions and 258 deletions

View File

@ -54,6 +54,108 @@
<div class="content unicode" style="display: block;"> <div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box"> <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"> <li class="dib">
<span class="icon iconfont">&#xe998;</span> <span class="icon iconfont">&#xe998;</span>
<div class="name">veops-department</div> <div class="name">veops-department</div>
@ -5520,9 +5622,9 @@
<pre><code class="language-css" <pre><code class="language-css"
>@font-face { >@font-face {
font-family: 'iconfont'; font-family: 'iconfont';
src: url('iconfont.woff2?t=1724653006782') format('woff2'), src: url('iconfont.woff2?t=1724834571283') format('woff2'),
url('iconfont.woff?t=1724653006782') format('woff'), url('iconfont.woff?t=1724834571283') format('woff'),
url('iconfont.ttf?t=1724653006782') format('truetype'); url('iconfont.ttf?t=1724834571283') format('truetype');
} }
</code></pre> </code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3> <h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -5548,6 +5650,159 @@
<div class="content font-class"> <div class="content font-class">
<ul class="icon_lists dib-box"> <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"> <li class="dib">
<span class="icon iconfont veops-department"></span> <span class="icon iconfont veops-department"></span>
<div class="name"> <div class="name">
@ -13747,6 +14002,142 @@
<div class="content symbol"> <div class="content symbol">
<ul class="icon_lists dib-box"> <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"> <li class="dib">
<svg class="icon svg-icon" aria-hidden="true"> <svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#veops-department"></use> <use xlink:href="#veops-department"></use>

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 3857903 */ font-family: "iconfont"; /* Project id 3857903 */
src: url('iconfont.woff2?t=1724653006782') format('woff2'), src: url('iconfont.woff2?t=1724834571283') format('woff2'),
url('iconfont.woff?t=1724653006782') format('woff'), url('iconfont.woff?t=1724834571283') format('woff'),
url('iconfont.ttf?t=1724653006782') format('truetype'); url('iconfont.ttf?t=1724834571283') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,74 @@
-moz-osx-font-smoothing: grayscale; -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 { .veops-department:before {
content: "\e998"; content: "\e998";
} }

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,125 @@
"css_prefix_text": "", "css_prefix_text": "",
"description": "", "description": "",
"glyphs": [ "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", "icon_id": "41570722",
"name": "veops-department", "name": "veops-department",

Binary file not shown.

View File

@ -31,7 +31,7 @@ export default {
text-align: center; text-align: center;
border-radius: 4px; border-radius: 4px;
&:hover { &: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; color: @layout-header-font-selected-color;
} }
} }

View File

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

View File

@ -10,10 +10,25 @@
<ops-icon class="common-settings-btn-icon" type="veops-setting" /> <ops-icon class="common-settings-btn-icon" type="veops-setting" />
<span class="common-settings-btn-text">{{ $t('settings') }}</span> <span class="common-settings-btn-text">{{ $t('settings') }}</span>
</span> </span>
<span class="locale" @click="changeLang">{{ locale === 'zh' ? '简中' : 'EN' }}</span>
<a-popover <a-popover
trigger="click" overlayClassName="lang-popover-wrap"
:overlayStyle="{ width: '150px' }" 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" placement="bottomRight"
overlayClassName="custom-user" overlayClassName="custom-user"
> >
@ -29,7 +44,7 @@
<span>{{ $t('topMenu.logout') }}</span> <span>{{ $t('topMenu.logout') }}</span>
</div> </div>
</template> </template>
<span class="action ant-dropdown-link user-dropdown-menu"> <span class="action ant-dropdown-link user-dropdown-menu user-info-wrap">
<a-avatar <a-avatar
v-if="avatar()" v-if="avatar()"
class="avatar" class="avatar"
@ -54,6 +69,20 @@ export default {
components: { components: {
DocumentLink, DocumentLink,
}, },
data() {
return {
languageList: [
{
title: '简中',
key: 'zh'
},
{
title: 'EN',
key: 'en'
},
]
}
},
computed: { computed: {
...mapState(['user', 'locale']), ...mapState(['user', 'locale']),
hasBackendPermission() { hasBackendPermission() {
@ -81,14 +110,9 @@ export default {
handleClick() { handleClick() {
this.$router.push('/setting') this.$router.push('/setting')
}, },
changeLang() { changeLang(lang) {
if (this.locale === 'zh') { this.SET_LOCALE(lang)
this.SET_LOCALE('en') this.$i18n.locale = lang
this.$i18n.locale = 'en'
} else {
this.SET_LOCALE('zh')
this.$i18n.locale = 'zh'
}
this.$nextTick(() => { this.$nextTick(() => {
setDocumentTitle(`${this.$t(this.$route.meta.title)} - ${domTitle}`) setDocumentTitle(`${this.$t(this.$route.meta.title)} - ${domTitle}`)
}) })
@ -124,6 +148,15 @@ export default {
color: @primary-color; color: @primary-color;
} }
} }
.lang-popover-wrap {
width: 70px;
padding: 0px;
.ant-popover-inner-content {
padding: 0px;
}
}
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
@ -150,6 +183,47 @@ export default {
font-weight: 400; font-weight: 400;
color: #4E5969; 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> </style>

View File

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

View File

@ -62,7 +62,7 @@ const cmdb_en = {
desc: 'Reverse order', desc: 'Reverse order',
uniqueKey: 'Unique Identifies', uniqueKey: 'Unique Identifies',
uniqueKeySelect: 'Please select a unique identifier', 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?', notfound: 'Can\'t find what you want?',
cannotDeleteGroupTips: 'There is data under this group and cannot be deleted!', cannotDeleteGroupTips: 'There is data under this group and cannot be deleted!',
confirmDeleteGroup: 'Are you sure you want to delete group [{groupName}]?', confirmDeleteGroup: 'Are you sure you want to delete group [{groupName}]?',
@ -142,7 +142,7 @@ const cmdb_en = {
selectCIType: 'Please select a CMDB CIType', selectCIType: 'Please select a CMDB CIType',
selectCITypeAttributes: 'Please select CIType attributes', selectCITypeAttributes: 'Please select CIType attributes',
selectAttributes: 'Please select 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!', valueExisted: 'The current value already exists!',
addRelation: 'Add Relation', addRelation: 'Add Relation',
sourceCIType: 'Source CIType', sourceCIType: 'Source CIType',
@ -306,6 +306,7 @@ const cmdb_en = {
departmentCascadeDisplay: 'Cascade Display', departmentCascadeDisplay: 'Cascade Display',
filterUsers: 'Filter Users', filterUsers: 'Filter Users',
enum: 'Enum', 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: { components: {
unselectAttributes: 'Unselected', 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', 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 // 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.', 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.', tips5: '4. When using Excel templates, please ensure that a single file does not exceed 5000 lines.',
}, },
preference: { preference: {
@ -650,7 +651,7 @@ if __name__ == "__main__":
tips4: 'At least one field must be selected', tips4: 'At least one field must be selected',
tips5: 'Search name | alias', 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', 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', tips8: 'Multiple values, such as intranet IP',
tips9: 'For front-end only', tips9: 'For front-end only',
tips10: 'Other attributes of the CIType are computed using expressions\n\nA code snippet computes the returned value.', 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: '倒序', desc: '倒序',
uniqueKey: '唯一标识', uniqueKey: '唯一标识',
uniqueKeySelect: '请选择唯一标识', uniqueKeySelect: '请选择唯一标识',
uniqueKeyTips: 'json、密码、计算属性、预定义值属性不能作为唯一标识', uniqueKeyTips: 'json、密码、计算属性、下拉列表属性不能作为唯一标识',
notfound: '找不到想要的?', notfound: '找不到想要的?',
cannotDeleteGroupTips: '该分组下有数据, 不能删除!', cannotDeleteGroupTips: '该分组下有数据, 不能删除!',
confirmDeleteGroup: '确定要删除分组 【{groupName}】 吗?', confirmDeleteGroup: '确定要删除分组 【{groupName}】 吗?',
@ -142,7 +142,7 @@ const cmdb_zh = {
selectCIType: '请选择CMDB模型', selectCIType: '请选择CMDB模型',
selectCITypeAttributes: '请选择模型属性', selectCITypeAttributes: '请选择模型属性',
selectAttributes: '请选择属性', 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: '当前值已存在!', valueExisted: '当前值已存在!',
addRelation: '新增关系', addRelation: '新增关系',
sourceCIType: '源模型', sourceCIType: '源模型',
@ -306,6 +306,7 @@ const cmdb_zh = {
departmentCascadeDisplay: '部门级联显示', departmentCascadeDisplay: '部门级联显示',
filterUsers: '筛选用户', filterUsers: '筛选用户',
enum: '枚举', enum: '枚举',
ciGrantTip: `筛选条件可使用{{}}引用变量实现动态变化,目前支持用户变量,如{{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`,
}, },
components: { components: {
unselectAttributes: '未选属性', unselectAttributes: '未选属性',
@ -390,7 +391,7 @@ const cmdb_zh = {
tips2: '1. 点击下载模板,用户可以自定义模板文件的表头,包括模型属性、模型关联', tips2: '1. 点击下载模板,用户可以自定义模板文件的表头,包括模型属性、模型关联',
// eslint-disable-next-line no-template-curly-in-string // eslint-disable-next-line no-template-curly-in-string
tips3: '2. 模板文件中红色为模型关系,如$产品.产品名(${模型名}.{属性名})这一列就可建立和产品之间的关系', tips3: '2. 模板文件中红色为模型关系,如$产品.产品名(${模型名}.{属性名})这一列就可建立和产品之间的关系',
tips4: '3. 下载模板excel文件中会将属性的预定义值置为下拉选项请注意受excel本身的限制单个下拉框限制了最多255个字符如果超过255个字符我们不会设置该属性的下拉选项', tips4: '3. 下载模板excel文件中会将属性的下拉列表枚举配置置为下拉选项请注意受excel本身的限制单个下拉框限制了最多255个字符如果超过255个字符我们不会设置该属性的下拉选项',
tips5: '4. 在使用excel模板时请确保单个文件不超过5000行', tips5: '4. 在使用excel模板时请确保单个文件不超过5000行',
}, },
preference: { preference: {
@ -649,7 +650,7 @@ if __name__ == "__main__":
tips4: '必须至少选择一个字段', tips4: '必须至少选择一个字段',
tips5: '搜索 名称 | 别名', tips5: '搜索 名称 | 别名',
tips6: '加快检索, 可以全文搜索, 无需使用条件过滤\n\n json、链接、密码目前不支持建索引 \n\n文本字符长度超过190不能建索引', tips6: '加快检索, 可以全文搜索, 无需使用条件过滤\n\n json、链接、密码目前不支持建索引 \n\n文本字符长度超过190不能建索引',
tips7: '表现形式是下拉框, 值必须在预定义值里', tips7: '是否配置下拉列表',
tips8: '多值, 比如内网IP', tips8: '多值, 比如内网IP',
tips9: '仅针对前端', tips9: '仅针对前端',
tips10: '模型的其他属性通过表达式的方式计算出来\n\n一个代码片段计算返回的值', tips10: '模型的其他属性通过表达式的方式计算出来\n\n一个代码片段计算返回的值',

View File

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

View File

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

View File

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

View File

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

View File

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