Merge pull request #663 from veops/dev_ui_241224

feat(ui): update style
This commit is contained in:
Leo Song 2024-12-24 15:23:33 +08:00 committed by GitHub
commit b669775cd6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
50 changed files with 1136 additions and 961 deletions

View File

@ -106,7 +106,7 @@
<CIReferenceAttr
v-if="getAttr(item.property).is_reference && (item.exp === 'is' || item.exp === '~is')"
:style="{ width: '175px' }"
class="select-filter-component"
class="select-filter-component ops-select-bg"
:referenceTypeId="getAttr(item.property).reference_type_id"
:disabled="disabled"
v-model="item.value"
@ -114,7 +114,7 @@
<a-select
v-else-if="getAttr(item.property).is_bool && (item.exp === 'is' || item.exp === '~is')"
v-model="item.value"
class="select-filter-component"
class="select-filter-component ops-select-bg"
:style="{ width: '175px' }"
:disabled="disabled"
:placeholder="$t('placeholder2')"
@ -398,7 +398,6 @@ export default {
/deep/ .ant-select-selection {
height: 24px;
background: #f7f8fa;
line-height: 24px;
border: none;

View File

@ -1,302 +1,302 @@
<template>
<div>
<a-popover
v-if="isDropdown"
v-model="visible"
trigger="click"
:placement="placement"
overlayClassName="table-filter"
@visibleChange="visibleChange"
>
<slot name="popover_item">
<a-button type="primary" ghost>{{ $t('cmdbFilterComp.conditionFilter') }}<a-icon type="filter"/></a-button>
</slot>
<template slot="content">
<Expression
:needAddHere="needAddHere"
v-model="ruleList"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
:disabled="disabled"
/>
<a-divider :style="{ margin: '10px 0' }" />
<div style="width:554px">
<a-space :style="{ display: 'flex', justifyContent: 'flex-end' }">
<a-button type="primary" size="small" @click="handleSubmit">{{ $t('confirm') }}</a-button>
<a-button size="small" @click="handleClear">{{ $t('clear') }}</a-button>
</a-space>
</div>
</template>
</a-popover>
<Expression
:needAddHere="needAddHere"
v-else
v-model="ruleList"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
:disabled="disabled"
/>
</div>
</template>
<script>
import { v4 as uuidv4 } from 'uuid'
import Expression from './expression.vue'
import { advancedExpList, compareTypeList } from './constants'
export default {
name: 'FilterComp',
components: { Expression },
props: {
canSearchPreferenceAttrList: {
type: Array,
required: true,
default: () => [],
},
expression: {
type: String,
default: '',
},
regQ: {
type: String,
default: '(?<=q=).+(?=&)|(?<=q=).+$',
},
placement: {
type: String,
default: 'bottomRight',
},
isDropdown: {
type: Boolean,
default: true,
},
needAddHere: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
advancedExpList,
compareTypeList,
visible: false,
ruleList: [],
filterExp: '',
}
},
methods: {
visibleChange(open, isInitOne = true) {
// isInitOne 初始化exp为空时ruleList是否默认给一条
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
: null
if (open && exp) {
const expArray = exp.split(',').map((item) => {
let has_not = ''
const key = item.split(':')[0]
const val = item
.split(':')
.slice(1)
.join(':')
let type, property, exp, value, min, max, compareType
if (key.includes('-')) {
type = 'or'
if (key.includes('~')) {
property = key.substring(2)
has_not = '~'
} else {
property = key.substring(1)
}
} else {
type = 'and'
if (key.includes('~')) {
property = key.substring(1)
has_not = '~'
} else {
property = key
}
}
const in_reg = /(?<=\().+(?=\))/g
const range_reg = /(?<=\[).+(?=\])/g
const compare_reg = /(?<=>=|<=|>(?!=)|<(?!=)).+/
if (val === '*') {
exp = has_not + 'value'
value = ''
} else if (in_reg.test(val)) {
exp = has_not + 'in'
value = val.match(in_reg)[0]
} else if (range_reg.test(val)) {
exp = has_not + 'range'
value = val.match(range_reg)[0]
min = value.split('_TO_')[0]
max = value.split('_TO_')[1]
} else if (compare_reg.test(val)) {
exp = has_not + 'compare'
value = val.match(compare_reg)[0]
const _compareType = val.substring(0, val.match(compare_reg)['index'])
const idx = compareTypeList.findIndex((item) => item.label === _compareType)
compareType = compareTypeList[idx].value
} else if (!val.includes('*')) {
exp = has_not + 'is'
value = val
} else {
const resList = [
['contain', /(?<=\*).*(?=\*)/g],
['end_with', /(?<=\*).+/g],
['start_with', /.+(?=\*)/g],
]
for (let i = 0; i < 3; i++) {
const reg = resList[i]
if (reg[1].test(val)) {
exp = has_not + reg[0]
value = val.match(reg[1])[0]
break
}
}
}
return {
id: uuidv4(),
type,
property,
exp,
value,
min,
max,
compareType,
}
})
this.ruleList = [...expArray]
} else if (open) {
const _canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((attr) => !attr.is_password)
this.ruleList = isInitOne
? [
{
id: uuidv4(),
type: 'and',
property:
_canSearchPreferenceAttrList && _canSearchPreferenceAttrList.length
? _canSearchPreferenceAttrList[0].name
: undefined,
exp: 'is',
value: null,
},
]
: []
}
},
handleClear() {
this.ruleList = [
{
id: uuidv4(),
type: 'and',
property: this.canSearchPreferenceAttrList[0].name,
exp: 'is',
value: null,
},
]
this.filterExp = ''
this.visible = false
this.$emit('setExpFromFilter', this.filterExp)
},
handleSubmit() {
if (this.ruleList && this.ruleList.length) {
this.ruleList[0].type = 'and' // 增删后以防万一第一个不是and
this.filterExp = ''
const expList = this.ruleList.map((rule) => {
let singleRuleExp = ''
let _exp = rule.exp
if (rule.type === 'or') {
singleRuleExp += '-'
}
if (rule.exp.includes('~')) {
singleRuleExp += '~'
_exp = rule.exp.split('~')[1]
}
singleRuleExp += `${rule.property}:`
if (_exp === 'is') {
singleRuleExp += `${rule.value ?? ''}`
}
if (_exp === 'contain') {
singleRuleExp += `*${rule.value ?? ''}*`
}
if (_exp === 'start_with') {
singleRuleExp += `${rule.value ?? ''}*`
}
if (_exp === 'end_with') {
singleRuleExp += `*${rule.value ?? ''}`
}
if (_exp === 'value') {
singleRuleExp += `*`
}
if (_exp === 'in') {
singleRuleExp += `(${rule.value ?? ''})`
}
if (_exp === 'range') {
singleRuleExp += `[${rule.min}_TO_${rule.max}]`
}
if (_exp === 'compare') {
const idx = compareTypeList.findIndex((item) => item.value === rule.compareType)
singleRuleExp += `${compareTypeList[idx].label}${rule.value ?? ''}`
}
return singleRuleExp
})
this.filterExp = expList.join(',')
this.$emit('setExpFromFilter', this.filterExp)
} else {
this.$emit('setExpFromFilter', '')
}
this.visible = false
},
},
}
</script>
<style lang="less" scoped>
.table-filter {
.table-filter-add {
margin-top: 10px;
& > a {
padding: 2px 8px;
&:hover {
background-color: #f0faff;
border-radius: 5px;
}
}
}
.table-filter-extra-icon {
padding: 0px 2px;
&:hover {
display: inline-block;
border-radius: 5px;
background-color: #f0faff;
}
}
}
</style>
<style lang="less">
.table-filter-extra-operation {
.ant-popover-inner-content {
padding: 3px 4px;
.operation {
cursor: pointer;
width: 90px;
height: 30px;
line-height: 30px;
padding: 3px 4px;
border-radius: 5px;
transition: all 0.3s;
&:hover {
background-color: #f0faff;
}
> .anticon {
margin-right: 10px;
}
}
}
}
</style>
<template>
<div>
<a-popover
v-if="isDropdown"
v-model="visible"
trigger="click"
:placement="placement"
overlayClassName="table-filter"
@visibleChange="visibleChange"
>
<slot name="popover_item">
<a-button type="primary" ghost>{{ $t('cmdbFilterComp.conditionFilter') }}<a-icon type="filter"/></a-button>
</slot>
<template slot="content">
<Expression
:needAddHere="needAddHere"
v-model="ruleList"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
:disabled="disabled"
/>
<a-divider :style="{ margin: '10px 0' }" />
<div style="width:554px">
<a-space :style="{ display: 'flex', justifyContent: 'flex-end' }">
<a-button type="primary" size="small" @click="handleSubmit">{{ $t('confirm') }}</a-button>
<a-button size="small" @click="handleClear">{{ $t('clear') }}</a-button>
</a-space>
</div>
</template>
</a-popover>
<Expression
:needAddHere="needAddHere"
v-else
v-model="ruleList"
:canSearchPreferenceAttrList="canSearchPreferenceAttrList.filter((attr) => !attr.is_password)"
:disabled="disabled"
/>
</div>
</template>
<script>
import { v4 as uuidv4 } from 'uuid'
import Expression from './expression.vue'
import { advancedExpList, compareTypeList } from './constants'
export default {
name: 'FilterComp',
components: { Expression },
props: {
canSearchPreferenceAttrList: {
type: Array,
required: true,
default: () => [],
},
expression: {
type: String,
default: '',
},
regQ: {
type: String,
default: '(?<=q=).+(?=&)|(?<=q=).+$',
},
placement: {
type: String,
default: 'bottomRight',
},
isDropdown: {
type: Boolean,
default: true,
},
needAddHere: {
type: Boolean,
default: false,
},
disabled: {
type: Boolean,
default: false,
},
},
data() {
return {
advancedExpList,
compareTypeList,
visible: false,
ruleList: [],
filterExp: '',
}
},
methods: {
visibleChange(open, isInitOne = true) {
// isInitOne 初始化exp为空时ruleList是否默认给一条
// const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
const exp = this.expression.match(new RegExp(this.regQ, 'g'))
? this.expression.match(new RegExp(this.regQ, 'g'))[0]
: null
if (open && exp) {
const expArray = exp.split(',').map((item) => {
let has_not = ''
const key = item.split(':')[0]
const val = item
.split(':')
.slice(1)
.join(':')
let type, property, exp, value, min, max, compareType
if (key.includes('-')) {
type = 'or'
if (key.includes('~')) {
property = key.substring(2)
has_not = '~'
} else {
property = key.substring(1)
}
} else {
type = 'and'
if (key.includes('~')) {
property = key.substring(1)
has_not = '~'
} else {
property = key
}
}
const in_reg = /(?<=\().+(?=\))/g
const range_reg = /(?<=\[).+(?=\])/g
const compare_reg = /(?<=>=|<=|>(?!=)|<(?!=)).+/
if (val === '*') {
exp = has_not + 'value'
value = ''
} else if (in_reg.test(val)) {
exp = has_not + 'in'
value = val.match(in_reg)[0]
} else if (range_reg.test(val)) {
exp = has_not + 'range'
value = val.match(range_reg)[0]
min = value.split('_TO_')[0]
max = value.split('_TO_')[1]
} else if (compare_reg.test(val)) {
exp = has_not + 'compare'
value = val.match(compare_reg)[0]
const _compareType = val.substring(0, val.match(compare_reg)['index'])
const idx = compareTypeList.findIndex((item) => item.label === _compareType)
compareType = compareTypeList[idx].value
} else if (!val.includes('*')) {
exp = has_not + 'is'
value = val
} else {
const resList = [
['contain', /(?<=\*).*(?=\*)/g],
['end_with', /(?<=\*).+/g],
['start_with', /.+(?=\*)/g],
]
for (let i = 0; i < 3; i++) {
const reg = resList[i]
if (reg[1].test(val)) {
exp = has_not + reg[0]
value = val.match(reg[1])[0]
break
}
}
}
return {
id: uuidv4(),
type,
property,
exp,
value,
min,
max,
compareType,
}
})
this.ruleList = [...expArray]
} else if (open) {
const _canSearchPreferenceAttrList = this.canSearchPreferenceAttrList.filter((attr) => !attr.is_password)
this.ruleList = isInitOne
? [
{
id: uuidv4(),
type: 'and',
property:
_canSearchPreferenceAttrList && _canSearchPreferenceAttrList.length
? _canSearchPreferenceAttrList[0].name
: undefined,
exp: 'is',
value: null,
},
]
: []
}
},
handleClear() {
this.ruleList = [
{
id: uuidv4(),
type: 'and',
property: this.canSearchPreferenceAttrList[0].name,
exp: 'is',
value: null,
},
]
this.filterExp = ''
this.visible = false
this.$emit('setExpFromFilter', this.filterExp)
},
handleSubmit() {
if (this.ruleList && this.ruleList.length) {
this.ruleList[0].type = 'and' // 增删后以防万一第一个不是and
this.filterExp = ''
const expList = this.ruleList.map((rule) => {
let singleRuleExp = ''
let _exp = rule.exp
if (rule.type === 'or') {
singleRuleExp += '-'
}
if (rule.exp.includes('~')) {
singleRuleExp += '~'
_exp = rule.exp.split('~')[1]
}
singleRuleExp += `${rule.property}:`
if (_exp === 'is') {
singleRuleExp += `${rule.value ?? ''}`
}
if (_exp === 'contain') {
singleRuleExp += `*${rule.value ?? ''}*`
}
if (_exp === 'start_with') {
singleRuleExp += `${rule.value ?? ''}*`
}
if (_exp === 'end_with') {
singleRuleExp += `*${rule.value ?? ''}`
}
if (_exp === 'value') {
singleRuleExp += `*`
}
if (_exp === 'in') {
singleRuleExp += `(${rule.value ?? ''})`
}
if (_exp === 'range') {
singleRuleExp += `[${rule.min}_TO_${rule.max}]`
}
if (_exp === 'compare') {
const idx = compareTypeList.findIndex((item) => item.value === rule.compareType)
singleRuleExp += `${compareTypeList[idx].label}${rule.value ?? ''}`
}
return singleRuleExp
})
this.filterExp = expList.join(',')
this.$emit('setExpFromFilter', this.filterExp)
} else {
this.$emit('setExpFromFilter', '')
}
this.visible = false
},
},
}
</script>
<style lang="less" scoped>
.table-filter {
.table-filter-add {
margin-top: 10px;
& > a {
padding: 2px 8px;
&:hover {
background-color: @primary-color_5;
border-radius: 5px;
}
}
}
.table-filter-extra-icon {
padding: 0px 2px;
&:hover {
display: inline-block;
border-radius: 5px;
background-color: #f0faff;
}
}
}
</style>
<style lang="less">
.table-filter-extra-operation {
.ant-popover-inner-content {
padding: 3px 4px;
.operation {
cursor: pointer;
width: 90px;
height: 30px;
line-height: 30px;
padding: 3px 4px;
border-radius: 5px;
transition: all 0.3s;
&:hover {
background-color: #f0faff;
}
> .anticon {
margin-right: 10px;
}
}
}
}
</style>

View File

@ -341,7 +341,7 @@ export default {
},
}
</script>
<style scoped>
<style lang="less" scoped>
.pop_btn {
text-align: right;
margin-top: 24px;

View File

@ -226,16 +226,16 @@ export default {
right: 4px;
display: none;
&:hover {
color: #1f78d1;
color: @primary-color;
}
}
&:hover .ant-transfer-list-icon {
display: inline;
background-color: #c0eaff;
background-color: @primary-color_4;
border-radius: 4px;
}
}
.ant-transfer-list-content-item-selected {
background-color: #f0faff;
background-color: ~'@{primary-color_8}35';
}
</style>

View File

@ -58,10 +58,7 @@
:title="$t('acl.visualRole')"
:width="120"
align="center"
:filters="[
{ label: $t('yes'), value: 1 },
{ label: $t('no'), value: 0 },
]"
:filters="visualRoleFilters"
:filterMultiple="false"
:filter-method="
({ value, row }) => {
@ -155,6 +152,10 @@ export default {
pageSizeOptions: ['20', '50', '100', '200'],
searchName: '',
filterTableValue: { user_role: 1, user_only: 0 },
visualRoleFilters: [
{ label: this.$t('yes'), value: 1 },
{ label: this.$t('no'), value: 0 }
]
}
},
computed: {

View File

@ -187,7 +187,7 @@ export default {
width: 12px;
height: 12px;
background-color: @primary-color;
border: solid 3px #E2E7FC;
border: solid 3px @primary-color_4;
border-radius: 50%;
}

View File

@ -1,150 +1,156 @@
<template>
<div class="ci-type-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="filterTableData"
:max-height="`${tableHeight}px`"
:row-style="(params) => getCurrentRowStyle(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<ReadCheckbox
v-if="['read'].includes(col.split('_')[0])"
:value="row[col.split('_')[0]]"
:valueKey="col"
:rid="row.rid"
@openReadGrantModal="() => openReadGrantModal(col, row)"
/>
<a-checkbox v-else-if="col === 'grant'" :checked="row[col]" @click="clickGrant(col, row)"></a-checkbox>
<a-checkbox @change="(e) => handleChange(e, col, row)" v-else v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
<template #empty>
<div v-if="loading()" style="height: 200px; line-height: 200px;color:#2F54EB">
<a-icon type="loading" /> {{ $t('loading') }}
</div>
<div v-else>
<img :style="{ width: '100px' }" :src="require('@/assets/data_empty.png')" />
<div>{{ $t('noData') }}</div>
</div>
</template>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import _ from 'lodash'
import { permMap } from './constants.js'
import { grantCiType, revokeCiType } from '../../api/CIType'
import ReadCheckbox from './readCheckbox.vue'
import { getCurrentRowStyle } from './utils'
export default {
name: 'CiTypeGrant',
components: { ReadCheckbox },
inject: ['loading', 'isModal'],
props: {
CITypeId: {
type: Number,
default: null,
},
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'ci_type',
},
addedRids: {
type: Array,
default: () => [],
},
},
computed: {
filterTableData() {
const _tableData = this.tableData.filter((data) => {
const _intersection = _.intersection(
Object.keys(data),
this.columns.map((col) => col.split('_')[0])
)
return _intersection && _intersection.length
})
return _.uniqBy(_tableData, (item) => item.rid)
},
columns() {
if (this.grantType === 'ci_type') {
return ['config', 'grant']
}
return ['read_attr', 'read_ci', 'create', 'update', 'delete']
},
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowStyle,
async handleChange(e, col, row) {
if (e.target.checked) {
await grantCiType(this.CITypeId, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
} else {
await revokeCiType(this.CITypeId, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
}
},
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
openReadGrantModal(col, row) {
this.$emit('openReadGrantModal', col, row)
},
clickGrant(col, row, rowIndex) {
if (!row[col]) {
this.handleChange({ target: { checked: true } }, col, row)
const _idx = this.tableData.findIndex((item) => item.rid === row.rid)
this.$set(this.tableData, _idx, { ...this.tableData[_idx], grant: true })
} else {
const that = this
this.$confirm({
title: that.$t('warning'),
content: that.$t('cmdb.components.confirmRevoke', { name: `${row.name}` }),
onOk() {
that.handleChange({ target: { checked: false } }, col, row)
const _idx = that.tableData.findIndex((item) => item.rid === row.rid)
that.$set(that.tableData, _idx, { ...that.tableData[_idx], grant: false })
},
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-type-grant {
padding: 10px 0;
}
</style>
<template>
<div class="ci-type-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="filterTableData"
:max-height="`${tableHeight}px`"
:row-class-name="(params) => getCurrentRowClass(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<ReadCheckbox
v-if="['read'].includes(col.split('_')[0])"
:value="row[col.split('_')[0]]"
:valueKey="col"
:rid="row.rid"
@openReadGrantModal="() => openReadGrantModal(col, row)"
/>
<a-checkbox v-else-if="col === 'grant'" :checked="row[col]" @click="clickGrant(col, row)"></a-checkbox>
<a-checkbox @change="(e) => handleChange(e, col, row)" v-else v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
<template #empty>
<div v-if="loading()" class="ci-type-grant-loading">
<a-icon type="loading" /> {{ $t('loading') }}
</div>
<div v-else>
<img :style="{ width: '100px' }" :src="require('@/assets/data_empty.png')" />
<div>{{ $t('noData') }}</div>
</div>
</template>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import _ from 'lodash'
import { permMap } from './constants.js'
import { grantCiType, revokeCiType } from '../../api/CIType'
import ReadCheckbox from './readCheckbox.vue'
import { getCurrentRowClass } from './utils'
export default {
name: 'CiTypeGrant',
components: { ReadCheckbox },
inject: ['loading', 'isModal'],
props: {
CITypeId: {
type: Number,
default: null,
},
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'ci_type',
},
addedRids: {
type: Array,
default: () => [],
},
},
computed: {
filterTableData() {
const _tableData = this.tableData.filter((data) => {
const _intersection = _.intersection(
Object.keys(data),
this.columns.map((col) => col.split('_')[0])
)
return _intersection && _intersection.length
})
return _.uniqBy(_tableData, (item) => item.rid)
},
columns() {
if (this.grantType === 'ci_type') {
return ['config', 'grant']
}
return ['read_attr', 'read_ci', 'create', 'update', 'delete']
},
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowClass,
async handleChange(e, col, row) {
if (e.target.checked) {
await grantCiType(this.CITypeId, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
} else {
await revokeCiType(this.CITypeId, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
}
},
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
openReadGrantModal(col, row) {
this.$emit('openReadGrantModal', col, row)
},
clickGrant(col, row, rowIndex) {
if (!row[col]) {
this.handleChange({ target: { checked: true } }, col, row)
const _idx = this.tableData.findIndex((item) => item.rid === row.rid)
this.$set(this.tableData, _idx, { ...this.tableData[_idx], grant: true })
} else {
const that = this
this.$confirm({
title: that.$t('warning'),
content: that.$t('cmdb.components.confirmRevoke', { name: `${row.name}` }),
onOk() {
that.handleChange({ target: { checked: false } }, col, row)
const _idx = that.tableData.findIndex((item) => item.rid === row.rid)
that.$set(that.tableData, _idx, { ...that.tableData[_idx], grant: false })
},
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-type-grant {
padding: 10px 0;
&-loading {
height: 200px;
line-height: 200px;
color: @primary-color;
}
}
</style>

View File

@ -366,5 +366,9 @@ export default {
.btn-wave-hover(@primary-color_4, -1);
}
.grant-table-row-focus {
background-color: @primary-color_8;
}
}
</style>

View File

@ -1,98 +1,98 @@
<template>
<div class="ci-relation-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="tableData"
:max-height="`${tableHeight}px`"
:row-style="(params) => getCurrentRowStyle(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<a-checkbox @change="(e) => handleChange(e, col, row)" v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import { permMap } from './constants.js'
import { grantRelationView, revokeRelationView } from '../../api/preference.js'
import { getCurrentRowStyle } from './utils'
export default {
name: 'RelationViewGrant',
inject: ['loading', 'isModal'],
props: {
resourceTypeName: {
type: String,
default: '',
},
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'relation_view',
},
addedRids: {
type: Array,
default: () => [],
},
},
data() {
return {
columns: ['read', 'grant'],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowStyle,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
handleChange(e, col, row) {
if (e.target.checked) {
grantRelationView(row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
} else {
revokeRelationView(row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-relation-grant {
padding: 10px 0;
}
</style>
<template>
<div class="ci-relation-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="tableData"
:max-height="`${tableHeight}px`"
:row-class-name="(params) => getCurrentRowClass(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<a-checkbox @change="(e) => handleChange(e, col, row)" v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import { permMap } from './constants.js'
import { grantRelationView, revokeRelationView } from '../../api/preference.js'
import { getCurrentRowClass } from './utils'
export default {
name: 'RelationViewGrant',
inject: ['loading', 'isModal'],
props: {
resourceTypeName: {
type: String,
default: '',
},
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'relation_view',
},
addedRids: {
type: Array,
default: () => [],
},
},
data() {
return {
columns: ['read', 'grant'],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowClass,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
handleChange(e, col, row) {
if (e.target.checked) {
grantRelationView(row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
} else {
revokeRelationView(row.rid, { perms: [col], name: this.resourceTypeName }).catch(() => {
this.$emit('getTableData')
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-relation-grant {
padding: 10px 0;
}
</style>

View File

@ -8,7 +8,7 @@
:data="tableData"
:max-height="`${tableHeight}px`"
:scroll-y="{enabled: true}"
:row-style="(params) => getCurrentRowStyle(params, addedRids)"
:row-class-name="(params) => getCurrentRowClass(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
@ -27,7 +27,7 @@
<script>
import { permMap } from './constants.js'
import { grantTopologyView, revokeTopologyView } from '@/modules/cmdb/api/topology.js'
import { getCurrentRowStyle } from './utils'
import { getCurrentRowClass } from './utils'
export default {
name: 'TopologyViewGrant',
inject: ['loading', 'isModal'],
@ -73,7 +73,7 @@ export default {
}
},
methods: {
getCurrentRowStyle,
getCurrentRowClass,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},

View File

@ -1,100 +1,100 @@
<template>
<div class="ci-relation-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="tableData"
:max-height="`${tableHeight}px`"
:row-style="(params) => getCurrentRowStyle(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<a-checkbox @change="(e) => handleChange(e, col, row)" v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import { permMap } from './constants.js'
import { grantTypeRelation, revokeTypeRelation } from '../../api/CITypeRelation.js'
import { getCurrentRowStyle } from './utils'
export default {
name: 'TypeRelationGrant',
inject: ['loading', 'isModal'],
props: {
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'type_relation',
},
typeRelationIds: {
type: Array,
default: null,
},
addedRids: {
type: Array,
default: () => [],
},
},
data() {
return {
columns: ['create', 'grant', 'delete'],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowStyle,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
handleChange(e, col, row) {
const first = this.typeRelationIds[0]
const second = this.typeRelationIds[1]
if (e.target.checked) {
grantTypeRelation(first, second, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
} else {
revokeTypeRelation(first, second, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-relation-grant {
padding: 10px 0;
}
</style>
<template>
<div class="ci-relation-grant">
<vxe-table
ref="xTable"
size="mini"
stripe
class="ops-stripe-table"
:data="tableData"
:max-height="`${tableHeight}px`"
:row-class-name="(params) => getCurrentRowClass(params, addedRids)"
>
<vxe-column field="name"></vxe-column>
<vxe-column v-for="col in columns" :key="col" :field="col" :title="permMap[col]">
<template #default="{row}">
<a-checkbox @change="(e) => handleChange(e, col, row)" v-model="row[col]"></a-checkbox>
</template>
</vxe-column>
</vxe-table>
<a-space>
<span class="grant-button" @click="grantDepart">{{ $t('cmdb.components.grantUser') }}</span>
<span class="grant-button" @click="grantRole">{{ $t('cmdb.components.grantRole') }}</span>
</a-space>
</div>
</template>
<script>
import { permMap } from './constants.js'
import { grantTypeRelation, revokeTypeRelation } from '../../api/CITypeRelation.js'
import { getCurrentRowClass } from './utils'
export default {
name: 'TypeRelationGrant',
inject: ['loading', 'isModal'],
props: {
tableData: {
type: Array,
default: () => [],
},
grantType: {
type: String,
default: 'type_relation',
},
typeRelationIds: {
type: Array,
default: null,
},
addedRids: {
type: Array,
default: () => [],
},
},
data() {
return {
columns: ['create', 'grant', 'delete'],
}
},
computed: {
windowHeight() {
return this.$store.state.windowHeight
},
tableHeight() {
if (this.isModal) {
return (this.windowHeight - 104) / 2
}
return (this.windowHeight - 104) / 2 - 116
},
permMap() {
return permMap()
}
},
methods: {
getCurrentRowClass,
grantDepart() {
this.$emit('grantDepart', this.grantType)
},
grantRole() {
this.$emit('grantRole', this.grantType)
},
handleChange(e, col, row) {
const first = this.typeRelationIds[0]
const second = this.typeRelationIds[1]
if (e.target.checked) {
grantTypeRelation(first, second, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
} else {
revokeTypeRelation(first, second, row.rid, { perms: [col] }).catch(() => {
this.$emit('getTableData')
})
}
},
},
}
</script>
<style lang="less" scoped>
.ci-relation-grant {
padding: 10px 0;
}
</style>

View File

@ -16,12 +16,8 @@
<template v-for="(item, index) in preferenceSearchList.slice(0, 3)">
<span
v-if="item.name.length > 6"
class="preference-search-tag"
:class="['preference-search-tag', item.id === currentPreferenceSearch ? 'preference-search-tag-focus' : '']"
:key="`${item.id}_${index}`"
:style="{
backgroundColor: item.id === currentPreferenceSearch ? '#2f54eb' : '',
color: item.id === currentPreferenceSearch ? '#fff' : '',
}"
>
<a-tooltip :title="item.name">
<span @click="clickPreferenceSearch(item)">{{ `${item.name.slice(0, 6)}...` }}</span>
@ -33,11 +29,7 @@
<span
v-else
:key="`${item.id}_${index}`"
class="preference-search-tag"
:style="{
backgroundColor: item.id === currentPreferenceSearch ? '#2f54eb' : '',
color: item.id === currentPreferenceSearch ? '#fff' : '',
}"
:class="['preference-search-tag', item.id === currentPreferenceSearch ? 'preference-search-tag-focus' : '']"
>
<span @click="clickPreferenceSearch(item)">{{ item.name }}</span>
<a-popconfirm :title="$t('cmdb.ciType.confirmDelete2')" @confirm="deletePreferenceSearch(item)">
@ -193,6 +185,11 @@ export default {
&:hover {
color: @primary-color;
}
&-focus {
background-color: @primary-color;
color: #FFFFFF !important;
}
}
.preference-search-delete {
color: #a9a9a9;

View File

@ -53,7 +53,7 @@
<a-icon
type="search"
slot="suffix"
:style="{ color: fuzzySearch ? '#2f54eb' : '#d9d9d9', cursor: 'pointer' }"
:class="['search-form-bar-input-icon', fuzzySearch ? 'search-form-bar-input-icon-focus' : '']"
@click="emitRefresh"
/>
<a-tooltip slot="prefix" placement="bottom" :overlayStyle="{ maxWidth: '550px', whiteSpace: 'pre-line' }">
@ -308,6 +308,16 @@ export default {
justify-content: space-between;
align-items: center;
height: 32px;
&-input-icon {
cursor: pointer;
color: #d9d9d9;
&-focus {
color: @primary-color;
}
}
.search-form-bar-filter {
.ops_display_wrapper(transparent);

View File

@ -315,8 +315,9 @@ const cmdb_en = {
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}}`,
searchInputTip: 'Please search for resource keywords',
columnSearchInputTip: '192.168.1.1\n192.168.1.2\n192.168.1.3',
rowSearchMode: 'Single Row Search',
columnSearchMode: 'Multi Row Search',
rowSearchMode: 'Single Row',
columnSearchMode: 'Multi Row',
columnSearchTip: 'Supports retrieval of short texts only',
resourceSearch: 'Resource Search',
recentSearch: 'Recent Search',
myCollection: 'My Collection',

View File

@ -315,8 +315,9 @@ const cmdb_zh = {
ciGrantTip: `筛选条件可使用{{}}引用变量实现动态变化,目前支持用户变量,如{{user.uid}},{{user.username}},{{user.email}},{{user.nickname}}`,
searchInputTip: '请搜索资源关键字',
columnSearchInputTip: '192.168.1.1\n192.168.1.2\n192.168.1.3',
rowSearchMode: '单行搜索',
columnSearchMode: '多行搜索',
rowSearchMode: '单行',
columnSearchMode: '多行',
columnSearchTip: '仅支持检索短文本',
resourceSearch: '资源搜索',
recentSearch: '最近搜索',
myCollection: '我的收藏',

View File

@ -14,7 +14,7 @@
<p v-html="$t('cmdb.batch.drawTips1')"></p>
<p v-html="$t('cmdb.batch.drawTips2')"></p>
<div v-for="item in fileList" :key="item.name" class="cmdb-batch-upload-dragger-file">
<span><a-icon type="file" :style="{ color: '#2F54EB', marginRight: '5px' }" />{{ item.name }}</span>
<span><a-icon type="file" class="cmdb-batch-upload-dragger-file-icon"/>{{ item.name }}</span>
<a-progress :status="progressStatus" :percent="percent" />
</div>
</a-upload-dragger>
@ -92,12 +92,7 @@ export default {
}
.ant-upload.ant-upload-drag {
border: none;
background: linear-gradient(90deg, @text-color_5 50%, transparent 0) repeat-x,
linear-gradient(90deg, @text-color_5 50%, transparent 0) repeat-x,
linear-gradient(0deg, @text-color_5 50%, transparent 0) repeat-y,
linear-gradient(0deg, @text-color_5 50%, transparent 0) repeat-y;
background-size: 15px 1px, 15px 1px, 1px 15px, 1px 15px;
background-position: 0 0, 0 100%, 0 0, 100% 0;
background: ~'linear-gradient(90deg, @{text-color_5} 50%, transparent 0) repeat-x 0 0 / 15px 1px, linear-gradient(90deg, @{text-color_5} 50%, transparent 0) repeat-x 0 100% / 15px 1px, linear-gradient(0deg, @{text-color_5} 50%, transparent 0) repeat-y 0 0 / 1px 15px, linear-gradient(0deg, @{text-color_5} 50%, transparent 0) repeat-y 100% 0 / 1px 15px';
.ant-upload-drag-container > i {
font-size: 60px;
}
@ -106,13 +101,7 @@ export default {
}
&:hover {
background: linear-gradient(90deg, @primary-color_2 50%, transparent 0) repeat-x,
linear-gradient(90deg, @primary-color_2 50%, transparent 0) repeat-x,
linear-gradient(0deg, @primary-color_2 50%, transparent 0) repeat-y,
linear-gradient(0deg, @primary-color_2 50%, transparent 0) repeat-y;
background-size: 15px 1px, 15px 1px, 1px 15px, 1px 15px;
background-position: 0 0, 0 100%, 0 0, 100% 0;
background-color: @primary-color_7;
background: ~'linear-gradient(90deg, @{primary-color_2} 50%, transparent 0) repeat-x 0 0 / 15px 1px, linear-gradient(90deg, @{primary-color_2} 50%, transparent 0) repeat-x 0 100% / 15px 1px, linear-gradient(0deg, @{primary-color_2} 50%, transparent 0) repeat-y 0 0 / 1px 15px, linear-gradient(0deg, @{primary-color_2} 50%, transparent 0) repeat-y 100% 0 / 1px 15px, @{primary-color_7}';
}
}
.ant-upload.ant-upload-drag .ant-upload-drag-container {
@ -139,6 +128,11 @@ export default {
white-space: nowrap;
margin-right: 10px;
}
&-icon {
color: @primary-color;
margin-right: 5px;
}
}
.cmdb-batch-upload-tips {
width: 50%;

View File

@ -47,8 +47,8 @@
<a-descriptions layout="horizontal" bordered size="small" :column="2">
<a-descriptions-item v-for="item in propertyList" :key="item.property" :label="item.label">
<ops-icon
:style="{ color: property[item.property] ? '#7f97fa' : '', fontSize: '10px' }"
:type="`ops-${item.property}-disabled`"
:class="['attribute-card-footer-icon', property[item.property] ? 'attribute-card-footer-icon-mark' : '']"
/>
</a-descriptions-item>
<a-descriptions-item label></a-descriptions-item>
@ -58,7 +58,7 @@
<ops-icon
v-for="item in propertyList.filter((p) => property[p.property])"
:key="item.property"
:style="{ color: '#7f97fa', fontSize: '10px' }"
class="attribute-card-footer-icon attribute-card-footer-icon-mark"
:type="`ops-${item.property}-disabled`"
/>
</a-space>
@ -247,13 +247,13 @@ export default {
.attribute-card {
width: 172px;
height: 75px;
background: @primary-color_6;
background-color: @primary-color_6;
border-radius: 2px;
position: relative;
margin-bottom: 16px;
transition: all 0.3s;
&:hover {
box-shadow: 0 4px 12px #4e5ea066;
box-shadow: 0 4px 12px @primary-color_8;
.attribute-card-operation {
visibility: visible !important;
}
@ -342,6 +342,15 @@ export default {
padding: 2px 0 2px 5px;
}
}
.attribute-card-footer-icon {
font-size: 10px;
&-mark {
color: @primary-color_2;
}
}
.attribute-card-inherited {
background: @primary-color_7;
.attribute-card-footer {
@ -356,10 +365,10 @@ export default {
justify-content: center;
cursor: pointer;
position: relative;
background-color: inherit;
background-color: inherit !important;
&:hover {
box-shadow: none;
background-color: @primary-color_6;
box-shadow: none !important;
background-color: @primary-color_6 !important;
}
&:after {
content: '';

View File

@ -140,7 +140,7 @@
:type="ci.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ ci.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ ci.name[0].toUpperCase() }}</span>
</span>
</div>
<span class="ci-types-left-detail-title">{{ ci.alias || ci.name }}</span>

View File

@ -35,7 +35,7 @@
:title="$t('cmdb.ciType.choiceWebhookTips')"
>
<a-icon
style="position:absolute;top:3px;left:-17px;color:#2f54eb;"
class="tab-webhook-filter-icon"
type="question-circle"
theme="filled"
/>
@ -553,7 +553,7 @@ export default {
&-tag {
background-color: #E1EFFF;
color: #2F54EB;
color: @primary-color;
font-size: 10px;
font-weight: 400;
padding: 0 3px;
@ -575,6 +575,13 @@ export default {
}
}
.tab-webhook-filter-icon {
position: absolute;
top: 3px;
left: -17px;
color: @primary-color;
}
.script-tip {
font-size: 12px;
line-height: 22px;

View File

@ -363,7 +363,7 @@ export default {
width: 12px;
height: 12px;
background-color: @primary-color;
border: solid 3px #E2E7FC;
border: solid 3px @primary-color_4;
border-radius: 50%
}

View File

@ -31,7 +31,7 @@
<vxe-column field="source_ci_type_name" :title="$t('cmdb.ciType.sourceCIType')"></vxe-column>
<vxe-column field="relation_type" :title="$t('cmdb.ciType.relationType')">
<template #default="{row}">
<span style="color:#2f54eb" v-if="row.isParent">{{ $t('cmdb.ciType.isParent') }}</span>
<span class="primary-color" v-if="row.isParent">{{ $t('cmdb.ciType.isParent') }}</span>
{{ row.relation_type }}
</template>
</vxe-column>
@ -700,7 +700,7 @@ export default {
}
/deep/ .relation-table-parent {
background-color: #f5f8ff !important;
background-color: @primary-color_5 !important;
}
}
</style>

View File

@ -24,7 +24,7 @@
<vxe-column field="attr_ids" :title="$t('cmdb.ciType.attributes')" :edit-render="{}">
<template #default="{ row }">
<template v-for="(attr, index) in row.attr_ids">
<span :key="attr" :style="{ color: '#2f54eb' }">{{ getDisplayName(attr) }}</span>
<span :key="attr" class="primary-color">{{ getDisplayName(attr) }}</span>
<span :key="`_${attr}`" v-if="index !== row.attr_ids.length - 1"> + </span>
</template>
</template>

View File

@ -19,7 +19,7 @@
:type="ciType.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ ciType.name[0].toUpperCase() }}</span>
</div>
<span :style="{ ...options.fontConfig }">{{ toThousands(data) }}</span>
</div>

View File

@ -148,7 +148,7 @@
:type="ciType.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ ciType.name[0].toUpperCase() }}</span>
</template>
<span :style="{ color: '#000' }"> {{ form.name }}</span>
</div>
@ -800,7 +800,7 @@ export default {
}
}
.chart-right-type-box-selected {
background-color: #e5f1ff;
background-color: @primary-color_3;
}
}
.chart-width {

View File

@ -63,7 +63,7 @@
:type="getCiType(item).icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ getCiType(item).name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ getCiType(item).name[0].toUpperCase() }}</span>
</template>
<span :style="{ color: item.options.chartType === 'count' ? item.options.fontColor : '#000' }">{{
item.options.name

View File

@ -268,18 +268,18 @@ export default {
margin-right: 2px;
font-size: 12px;
font-weight: 400;
color: #3F75FF;
color: #2F54EB;
}
&-icon {
font-size: 12px;
color: #3F75FF;
color: #2F54EB;
}
}
&:hover {
background-color: #FFFFFF;
box-shadow: 0px 22px 33px 0px rgba(41, 65, 126, 0.25);
box-shadow: ~'0px 22px 33px 0px @{primary-color}15';
z-index: 2;
.rack-grid-item-name {

View File

@ -58,15 +58,11 @@
>
<ops-icon
:type="treeNodeData.icon"
class="dcim-tree-node-icon"
:style="{ color: treeNodeData.iconColor }"
:class="['dcim-tree-node-icon', treeNodeData.dcimType === DCIM_TYPE.REGION ? 'primary-color' : '']"
/>
<a-tooltip :title="treeNodeData.title">
<span
class="dcim-tree-node-title"
:style="{
color: treeKey === treeNodeData.key ? '#2F54EB' : ''
}"
:class="['dcim-tree-node-title', treeKey === treeNodeData.key ? 'primary-color' : '']"
>
{{ treeNodeData.title }}
</span>
@ -164,6 +160,7 @@ export default {
DCIM_TYPE.REGION,
DCIM_TYPE.IDC
],
DCIM_TYPE,
viewDetailCITypeId: 0,
viewDetailAttrObj: {},
@ -365,6 +362,7 @@ export default {
&-icon {
font-size: 12px;
flex-shrink: 0;
color: #A5A9BC;
}
&-title {

View File

@ -117,8 +117,8 @@
}"
@click="addDevice(index)"
>
<ops-icon
type="monitor-add"
<a-icon
type="plus-circle"
class="rack-container-main-list-gap-icon"
/>
<span
@ -492,12 +492,13 @@ export default {
&-icon {
font-size: 12px;
display: none;
color: @primary-color;
}
&-text {
font-size: 12px;
font-weight: 400;
color: rgba(0, 87, 255, 0.80);
color: @primary-color;
margin-left: 6px;
display: none;
}
@ -508,7 +509,7 @@ export default {
}
&:hover {
background-color: #D5DDEE;
background-color: @primary-color_4;
.rack-container-main-list-gap-icon {
display: inline-block;

View File

@ -165,7 +165,7 @@ export default {
display: inline-block;
width: 180px;
height: 105px;
box-shadow: 0px 2px 8px rgba(122, 140, 204, 0.25);
box-shadow: 0px 2px 8px @primary-color_3;
border-radius: 4px;
position: relative;
margin-bottom: 40px;
@ -297,7 +297,7 @@ export default {
&, &.discovery-card-small {
&:hover {
box-shadow: 0px 6px 20px 0px rgba(122, 140, 204, 0.30);
box-shadow: 0px 6px 20px 0px @primary-color_3;
}
}
@ -314,7 +314,7 @@ export default {
}
&:hover {
box-shadow: 0px 6px 28px 0px rgba(122, 140, 204, 0.30);
box-shadow: 0px 6px 28px 0px @primary-color_3;
}
}
}

View File

@ -70,7 +70,7 @@
class="setting-discovery-add"
@click="handleOpenEditDrawer(null, 'add', DISCOVERY_CATEGORY_TYPE.PLUGIN)"
>
<a-icon type="plus-circle" theme="twoTone" />
<a-icon class="setting-discovery-add-icon" type="plus-circle" />
<span class="setting-discovery-add-text">
{{ $t('cmdb.ad.addPlugin') }}
</span>
@ -380,6 +380,10 @@ export default {
justify-content: center;
cursor: pointer;
&-icon {
color: @primary-color_9;
}
&-text {
color: @text-color_3;
font-size: 12px;

View File

@ -24,7 +24,7 @@
:type="ciType.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ ciType.name[0].toUpperCase() }}</span>
</span>
<span :title="ciType.alias || ciType.name" class="cmdb-adc-side-name">{{ ciType.alias || ciType.name }}</span>
</div>

View File

@ -26,10 +26,7 @@
/>
<a-tooltip :title="treeNodeData.title">
<span
class="ipam-tree-node-title"
:style="{
color: treeKey === treeNodeData.key ? '#2F54EB' : ''
}"
:class="['ipam-tree-node-title', treeKey === treeNodeData.key ? 'primary-color' : '']"
>
{{ treeNodeData.title }}
</span>

View File

@ -20,7 +20,7 @@
<vxe-column
field="relation_type_id"
:title="$t('cmdb.custom_dashboard.relation')"
:filters="[{ data: '' }]"
:filters="relationTypeList"
:filter-multiple="false"
>
<template #default="{ row }">
@ -144,7 +144,7 @@ export default {
return {
drawerVisible: false,
tableData: [],
relationTypeList: null,
relationTypeList: [],
type2attributes: {},
tableAttrList: [],
}
@ -201,13 +201,6 @@ export default {
async getRelationTypes() {
const res = await getRelationTypes()
this.relationTypeList = res.map((item) => ({ value: item.id, label: item.name }))
const $table = this.$refs.xTable
if ($table) {
const nameColumn = $table.getColumnByField('relation_type_id')
if (nameColumn) {
$table.setFilter(nameColumn, this.relationTypeList)
}
}
},
// 转换关联关系
handleConstraint(constraintId) {
@ -359,5 +352,9 @@ export default {
&-action {
margin-left: 5px;
}
/deep/ .ant-select-selection {
box-shadow: none;
}
}
</style>

View File

@ -30,7 +30,7 @@
<span>{{ column.title }}</span>
<a-popover trigger="click" placement="bottom">
<a-icon class="filter" type="filter" theme="filled" />
<a slot="content">
<a class="filter-content" slot="content">
<a-input
:placeholder="$t('cmdb.history.userTips')"
size="small"
@ -453,4 +453,10 @@ export default {
color: #606266;
}
}
.filter-content {
display: flex;
align-items: center;
column-gap: 8px;
}
</style>

View File

@ -28,7 +28,7 @@
<span>{{ column.title }}</span>
<a-popover trigger="click" placement="bottom">
<a-icon class="filter" type="filter" theme="filled" />
<a slot="content">
<a class="filter-content" slot="content">
<a-input
:placeholder="$t('cmdb.history.userTips')"
size="small"
@ -47,7 +47,7 @@
<span>{{ column.title }}</span>
<a-popover trigger="click" placement="bottom">
<a-icon class="filter" type="filter" theme="filled" />
<a slot="content">
<a class="filter-content" slot="content">
<a-select
v-model="queryParams.operate_type"
:placeholder="$t('cmdb.history.filterOperate')"
@ -445,4 +445,10 @@ export default {
color: #606266;
}
}
.filter-content {
display: flex;
align-items: center;
column-gap: 8px;
}
</style>

View File

@ -26,7 +26,7 @@
<span>{{ column.title }}</span>
<a-popover trigger="click" placement="bottom">
<a-icon class="filter" type="filter" theme="filled" />
<a slot="content">
<a class="filter-content" slot="content">
<a-select
v-model="queryParams.operate_type"
:placeholder="$t('cmdb.history.filterOperate')"
@ -563,4 +563,10 @@ export default {
p {
margin-bottom: 0;
}
.filter-content {
display: flex;
align-items: center;
column-gap: 8px;
}
</style>

View File

@ -654,11 +654,11 @@ export default {
height: 155px;
border-radius: @border-radius-box;
background-color: #fff;
box-shadow: 0px 2px 8px rgba(149, 160, 208, 0.25);
box-shadow: ~'0px 2px 8px @{primary-color}15';
margin: 0 20px 20px 0;
padding: 12px;
&:hover {
box-shadow: 4px 25px 30px rgba(50, 89, 134, 0.25);
box-shadow: ~'4px 25px 30px @{primary-color}15';
transform: scale(1.1);
}
.cmdb-preference-header {
@ -733,10 +733,10 @@ export default {
align-items: center;
gap: 3px;
font-size: 12px;
color: rgba(0, 0, 0, 0.76);
color: @text-color_1;
&:hover {
color: #1890ff;
color: @primary-color;
}
}

View File

@ -13,12 +13,11 @@
<div class="search-condition-control">
<treeselect
:value="sourceCIType"
class="custom-treeselect custom-treeselect-bgcAndBorder filter-content-ciTypes"
class="custom-treeselect custom-treeselect-white filter-content-ciTypes"
:style="{
width: '100%',
zIndex: '1000',
'--custom-height': '32px',
'--custom-bg-color': '#FFF',
'--custom-multiple-lineHeight': '32px',
}"
:multiple="false"
@ -699,14 +698,14 @@ export default {
cursor: pointer;
&:hover {
background-color: #D9E4FA;
background-color: @primary-color_4;
.search-condition-favor-name {
color: #2F54EB;
color: @primary-color;
}
.search-condition-favor-close {
color: #2F54EB;
color: @primary-color;
}
}
}
@ -737,10 +736,10 @@ export default {
}
&:hover {
background-color: #D9E4FA;
background-color: @primary-color_4;
.search-condition-hide-icon {
color: #2F54EB;
color: @primary-color_4;
}
}
}

View File

@ -656,15 +656,15 @@ export default {
&:hover {
.relation-search-expand-handle {
background-color: #D9E4FA;
background-color: @primary-color_4;
}
.relation-search-expand-icon {
color: #2F54EB;
color: @primary-color;
}
.relation-search-expand-text {
color: #2F54EB;
color: @primary-color;
}
}
}

View File

@ -327,7 +327,7 @@ export default {
&-header {
width: 100%;
height: 75px;
background-color: #EBF0F9;
background-color: @primary-color_3;
overflow: hidden;
position: relative;
display: flex;
@ -342,7 +342,7 @@ export default {
right: -20px;
top: 0px;
transform: rotate(40deg);
background: rgba(248, 249, 253, 0.60);
background-color: @primary-color_5;
}
&-line-2 {
@ -352,7 +352,7 @@ export default {
right: -110px;
top: 0px;
transform: rotate(40deg);
background: rgba(248, 249, 253, 0.60);
background-color: @primary-color_5;
}
&-row {

View File

@ -431,7 +431,7 @@ export default {
}
&:hover {
box-shadow: 0px 2px 12px 0px rgba(147, 168, 223, 0.20);
box-shadow: ~'0px 2px 12px 0px @{primary-color}15';
.list-card-collect {
display: inline-block;

View File

@ -1,36 +1,48 @@
<template>
<div :class="['search-input', classType ? 'search-input-' + classType : '', { 'column-search-mode': isColumnSearch }]">
<div :class="['search-input', classType ? 'search-input-' + classType : '']">
<div class="search-area">
<div v-show="!isColumnSearch" class="input-wrapper">
<a-input
:value="searchValue"
class="search-input-component"
:placeholder="$t('cmdb.ciType.searchInputTip')"
@change="handleChangeSearchValue"
@pressEnter="saveCondition(true, 'normal')"
/>
<a-input
v-show="searchMode === SEARCH_MODE.NORMAL"
:value="searchValue"
class="search-input-component"
:placeholder="$t('cmdb.ciType.searchInputTip')"
@change="handleChangeSearchValue"
@pressEnter="saveCondition(true)"
>
<a-icon
class="search-icon"
slot="prefix"
type="search"
@click="saveCondition(true, 'normal')"
@click="saveCondition(true)"
/>
</div>
</a-input>
<div v-show="isColumnSearch" class="textarea-wrapper">
<div class="textarea-container">
<a-textarea
:value="searchValue"
class="column-search-component"
:rows="4"
:placeholder="$t('cmdb.ciType.columnSearchInputTip')"
@change="handleChangeColumnSearchValue"
@pressEnter="handlePressEnter"
/>
<div
v-show="searchMode === SEARCH_MODE.COLUMN"
class="search-textarea-component"
>
<a-textarea
:value="searchValue"
:autosize="{
minRows: 3,
maxRows: 3,
}"
:placeholder="$t('cmdb.ciType.columnSearchInputTip')"
@change="handleChangeSearchValue"
/>
<div class="search-textarea-icon-wrap">
<a-icon
class="search-icon"
type="search"
@click="saveCondition(true, 'column')"
@click="saveCondition(true)"
/>
<a-tooltip :title="$t('cmdb.ciType.columnSearchTip')">
<a-icon
type="info-circle"
class="search-icon"
/>
</a-tooltip>
</div>
</div>
@ -46,11 +58,26 @@
@saveCondition="saveCondition"
/>
<div class="column-search-btn" @click="toggleColumnSearch">
<a-icon class="column-search-btn-icon" type="menu" />
<span class="column-search-btn-title">
{{ isColumnSearch ? $t('cmdb.ciType.rowSearchMode') : $t('cmdb.ciType.columnSearchMode') }}
<div class="search-mode-switch">
<span
v-for="(item) in searchModeList"
:key="item.value"
:class="['search-mode-switch-item', searchMode === item.value ? 'search-mode-switch-item-active' : '']"
:style="{
width: isZh ? '40px' : '65px'
}"
@click="updateSearchMode(item.value)"
>
{{ $t(item.label) }}
</span>
<span
class="search-mode-switch-slide"
:style="{
left: searchMode === SEARCH_MODE.COLUMN ? (isZh ? '44px' : '69px') : '4px',
width: isZh ? '40px' : '65px'
}"
></span>
</div>
</div>
</div>
@ -68,6 +95,7 @@
</template>
<script>
import { SEARCH_MODE } from '../constants.js'
import FilterPopover from './filterPopover.vue'
export default {
@ -100,12 +128,31 @@ export default {
type: String,
default: ''
},
isColumnSearch: {
type: Boolean,
default: false
searchMode: {
type: String,
default: SEARCH_MODE.NORMAL
}
},
data() {
return {
SEARCH_MODE,
searchModeList: [
{
value: SEARCH_MODE.NORMAL,
label: 'cmdb.ciType.rowSearchMode'
},
{
value: SEARCH_MODE.COLUMN,
label: 'cmdb.ciType.columnSearchMode'
},
]
}
},
computed: {
isZh() {
return this.$i18n.locale === 'zh'
},
// 复制文字展示与实际文本复制内容区别在于未选择模型时不展示所有模型拼接数据
copyText() {
const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
@ -119,14 +166,15 @@ export default {
textArray.push(exp)
}
if (this.searchValue) {
let processedValue = this.searchValue
if (this.isColumnSearch) {
if (
this.searchMode === SEARCH_MODE.COLUMN &&
this.searchValue.includes('\n')
) {
const values = this.searchValue.split('\n').filter(v => v.trim())
if (values.length) {
processedValue = `(${values.join(';')})`
}
textArray.push(`(${values.join(';')})`)
} else {
textArray.push(`*${this.searchValue}*`)
}
textArray.push(`${!this.isColumnSearch ? '*' : ''}${processedValue}${!this.isColumnSearch ? '*' : ''}`)
}
return textArray.length ? `q=${textArray.join(',')}` : ''
@ -136,8 +184,8 @@ export default {
updateAllAttributesList(value) {
this.$emit('updateAllAttributesList', value)
},
saveCondition(isSubmit, searchType = 'normal') {
this.$emit('saveCondition', isSubmit, searchType)
saveCondition(isSubmit) {
this.$emit('saveCondition', isSubmit)
},
handleChangeSearchValue(e) {
const value = e.target.value
@ -163,9 +211,21 @@ export default {
ciTypeIds.push(...ids)
})
}
const copyText = `${ciTypeIds?.length ? `_type:(${ciTypeIds.join(';')})` : ''}${exp ? `,${exp}` : ''}${
searchValue ? `,${!this.isColumnSearch ? '*' : ''}${searchValue}${!this.isColumnSearch ? '*' : ''}` : ''
}`
let copySearchValue = ''
if (searchValue) {
if (
this.searchMode === SEARCH_MODE.COLUMN &&
this.searchValue.includes('\n')
) {
const values = searchValue.split('\n').filter(v => v.trim())
copySearchValue = `,(${values.join(';')})`
} else {
copySearchValue = `,*${searchValue}*`
}
}
const copyText = `${ciTypeIds?.length ? `_type:(${ciTypeIds.join(';')})` : ''}${exp ? `,${exp}` : ''}${copySearchValue}`
this.$copyText(copyText)
.then(() => {
@ -176,33 +236,8 @@ export default {
})
},
toggleColumnSearch() {
this.$emit('toggleSearchMode', !this.isColumnSearch)
this.saveCondition(false, !this.isColumnSearch ? 'column' : 'normal')
},
handleChangeColumnSearchValue(e) {
const value = e.target.value
this.changeFilter({
name: 'searchValue',
value
})
},
handlePressEnter(e) {
if (this.isColumnSearch) {
// 列搜索模式下按下 Enter 键时阻止默认行为并插入换行符
e.preventDefault()
const value = this.searchValue || ''
const cursorPosition = e.target.selectionStart
const newValue = value.slice(0, cursorPosition) + '\n' + value.slice(cursorPosition)
this.changeFilter({
name: 'searchValue',
value: newValue
})
} else {
this.saveCondition(true, 'normal')
}
updateSearchMode(mode) {
this.$emit('updateSearchMode', mode)
}
}
}
@ -211,115 +246,132 @@ export default {
<style lang="less" scoped>
.search-input {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
.search-area {
display: flex;
align-items: flex-start;
min-height: 48px;
width: 100%;
}
.input-wrapper {
position: relative;
flex-grow: 1;
.search-input-component {
height: 48px;
line-height: 48px;
border-radius: 48px;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #d9d9d9;
font-size: 14px;
border-radius: 8px;
/deep/ input {
height: 100%;
padding-right: 40px;
&:hover {
/deep/ .ant-input {
background-color: @primary-color_5;
}
}
/deep/ .ant-input {
border: none;
height: 48px;
line-height: 48px;
border-radius: 48px;
&:focus {
border: solid 1px @primary-color;
background-color: #FFFFFF !important;
}
}
}
.search-textarea-component {
position: relative;
.search-textarea-icon-wrap {
position: absolute;
top: 10px;
left: 12px;
display: flex;
flex-direction: column;
row-gap: 6px;
}
&:hover {
/deep/ .ant-input {
background-color: @primary-color_5;
}
}
/deep/ .ant-input {
border: none;
padding-left: 36px;
resize: none;
&:focus {
border: solid 1px @primary-color;
background-color: #FFFFFF !important;
}
}
}
.search-icon {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
color: #2F54EB;
color: @primary-color;
font-size: 14px;
cursor: pointer;
}
}
.textarea-wrapper {
flex-grow: 1;
.operation-area {
position: absolute;
display: flex;
align-items: center;
right: 0px;
top: 0px;
height: 48px;
transform: translateX(100%);
.textarea-container {
.search-mode-switch {
display: flex;
align-items: center;
height: 32px;
background-color: @primary-color_3;
border-radius: 32px;
position: relative;
width: 100%;
max-height: 200px;
padding: 0 4px;
margin-left: 14px;
cursor: pointer;
.column-search-component {
width: 100%;
max-height: 200px;
background-color: #FFFFFF;
border: 1px solid #d9d9d9;
font-size: 14px;
border-radius: 8px;
padding-right: 35px;
resize: none;
transition: all 0.3s;
&-item {
height: 24px;
width: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 400;
color: @text-color_2;
z-index: 1;
position: relative;
&:hover, &:focus {
border-color: #40a9ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
&-active {
color: @primary-color;
}
}
.search-icon {
&-slide {
position: absolute;
right: 12px;
top: 12px;
color: #2F54EB;
font-size: 14px;
cursor: pointer;
transition: left 0.2s;
border-radius: 24px;
background-color: #FFFFFF;
height: 24px;
top: 4px;
width: 40px;
z-index: 0;
}
}
}
.operation-area {
display: flex;
align-items: center;
height: 48px;
margin-left: 10px;
}
.column-search-btn {
flex-shrink: 0;
display: flex;
align-items: center;
margin-left: 13px;
cursor: pointer;
&-icon {
color: #2F54EB;
font-size: 12px;
}
&-title {
font-size: 14px;
font-weight: 400;
color: #2F54EB;
margin-left: 3px;
}
}
.expression-display {
display: flex;
align-items: center;
margin-left: 20px;
max-width: 30%;
max-width: 100%;
width: fit-content;
margin-top: 8px;
&-text {
width: 100%;
@ -335,16 +387,9 @@ export default {
}
}
.search-input-component,
.column-search-component {
&:hover {
border-color: #40a9ff;
}
&:focus {
border-color: #40a9ff;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
outline: none;
&-after {
.search-area {
max-width: 420px;
}
}
}

View File

@ -0,0 +1,4 @@
export const SEARCH_MODE = {
NORMAL: 'normal',
COLUMN: 'column'
}

View File

@ -15,11 +15,11 @@
:searchValue="searchValue"
:selectCITypeIds="selectCITypeIds"
:expression="expression"
:isColumnSearch="currentSearchType === 'column'"
:searchMode="currentSearchMode"
@changeFilter="changeFilter"
@updateAllAttributesList="updateAllAttributesList"
@saveCondition="saveCondition"
@toggleSearchMode="handleToggleSearchMode"
@updateSearchMode="updateSearchMode"
/>
<HistoryList
:recentList="recentList"
@ -48,11 +48,11 @@
:searchValue="searchValue"
:selectCITypeIds="selectCITypeIds"
:expression="expression"
:isColumnSearch="currentSearchType === 'column'"
:searchMode="currentSearchMode"
@changeFilter="changeFilter"
@updateAllAttributesList="updateAllAttributesList"
@saveCondition="saveCondition"
@toggleSearchMode="handleToggleSearchMode"
@updateSearchMode="updateSearchMode"
/>
<HistoryList
:recentList="recentList"
@ -127,6 +127,7 @@ import { getPreferenceSearch, savePreferenceSearch, getSubscribeAttributes, dele
import { searchAttributes, getCITypeAttributesByTypeIds } from '@/modules/cmdb/api/CITypeAttr'
import { searchCI } from '@/modules/cmdb/api/ci'
import { getCITypes } from '@/modules/cmdb/api/CIType'
import { SEARCH_MODE } from './constants.js'
import SearchInput from './components/searchInput.vue'
import HistoryList from './components/historyList.vue'
@ -176,7 +177,7 @@ export default {
showInstanceDetail: false,
detailCIId: -1,
detailCITypeId: -1,
currentSearchType: 'normal',
currentSearchMode: SEARCH_MODE.NORMAL,
}
},
computed: {
@ -245,9 +246,7 @@ export default {
}
},
async saveCondition(isSubmit, searchType = 'normal') {
this.currentSearchType = searchType
async saveCondition(isSubmit) {
if (
this.searchValue ||
this.expression ||
@ -261,7 +260,7 @@ export default {
option.searchValue === this.searchValue &&
option.expression === this.expression &&
_.isEqual(option.ciTypeIds, this.selectCITypeIds) &&
option.searchType === this.currentSearchType
option.searchMode === this.currentSearchMode
) {
needDeleteList.push(item.id)
} else {
@ -288,7 +287,7 @@ export default {
expression: this.expression,
ciTypeIds: this.selectCITypeIds,
ciTypeNames,
searchType: this.currentSearchType
searchMode: this.currentSearchMode
},
name: '__recent__'
})
@ -299,7 +298,7 @@ export default {
this.isSearch = true
this.currentPage = 1
this.hideDetail()
this.loadInstance(this.currentSearchType)
this.loadInstance()
}
},
@ -316,19 +315,11 @@ export default {
this.getRecentList()
},
async loadInstance(searchType = 'normal') {
const { selectCITypeIds, expression } = this
let { searchValue } = this
async loadInstance() {
const { selectCITypeIds, expression, searchValue } = this
const regQ = /(?<=q=).+(?=&)|(?<=q=).+$/g
const exp = expression.match(regQ) ? expression.match(regQ)[0] : null
if (searchType === 'column' && searchValue) {
const values = searchValue.split('\n').filter(v => v.trim())
if (values.length) {
searchValue = `(${values.join(';')})`
}
}
const ciTypeIds = [...selectCITypeIds]
if (!ciTypeIds.length) {
this.CITypeGroup.forEach((item) => {
@ -337,10 +328,21 @@ export default {
})
}
let querySearchValue = ''
if (searchValue) {
if (
this.currentSearchMode === SEARCH_MODE.COLUMN &&
searchValue.includes('\n')
) {
const values = searchValue.split('\n').filter(v => v.trim())
querySearchValue = `,(${values.join(';')})`
} else {
querySearchValue = `,*${searchValue}*`
}
}
const res = await searchCI({
q: `${ciTypeIds?.length ? `_type:(${ciTypeIds.join(';')})` : ''}${exp ? `,${exp}` : ''}${
searchValue ? `,${searchType === 'normal' ? '*' : ''}${searchValue}${searchType === 'normal' ? '*' : ''}` : ''
}`,
q: `${ciTypeIds?.length ? `_type:(${ciTypeIds.join(';')})` : ''}${exp ? `,${exp}` : ''}${querySearchValue}`,
count: this.pageSize,
page: this.currentPage,
sort: '_type'
@ -406,6 +408,7 @@ export default {
}
this.ciTabList = ciTabList
// 处理引用属性
const allAttr = []
subscribedRes.map((item) => {
allAttr.push(...item.attributes)
@ -493,21 +496,21 @@ export default {
this.searchValue = data?.searchValue || ''
this.expression = data?.expression || ''
this.selectCITypeIds = data?.ciTypeIds || []
this.currentSearchType = data?.searchType || 'normal'
this.currentSearchMode = data?.searchMode || 'normal'
this.hideDetail()
this.loadInstance(this.currentSearchType)
this.loadInstance()
},
handlePageSizeChange(_, pageSize) {
this.pageSize = pageSize
this.currentPage = 1
this.loadInstance(this.currentSearchType)
this.loadInstance()
},
changePage(page) {
this.currentPage = page
this.loadInstance(this.currentSearchType)
this.loadInstance()
},
changeFilter(data) {
@ -552,8 +555,8 @@ export default {
this.showDetail(data)
},
handleToggleSearchMode(isColumn) {
this.currentSearchType = isColumn ? 'column' : 'normal'
updateSearchMode(mode) {
this.currentSearchMode = mode
}
}
}
@ -567,7 +570,7 @@ export default {
&-before {
width: 100%;
max-width: 725px;
max-width: 718px;
height: 100%;
margin: 0 auto;
padding-top: 100px;

View File

@ -109,7 +109,7 @@
:type="topo.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ topo.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ topo.name[0].toUpperCase() }}</span>
</span>
</div>
<span class="topo-left-detail-title">{{ topo.alias || topo.name }}</span>

View File

@ -48,7 +48,7 @@
:type="ciType.icon.split('$$')[0]"
/>
</template>
<span :style="{ color: '#2f54eb' }" v-else>{{ ciType.name[0].toUpperCase() }}</span>
<span class="primary-color" v-else>{{ ciType.name[0].toUpperCase() }}</span>
</span>
<span class="tree-views-left-header-name">{{ ciType.alias || ciType.name }}</span>
<div class="actions">

View File

@ -824,6 +824,10 @@ body {
color: @primary-color !important;
}
.el-select-dropdown__item.hover {
background-color: @primary-color_5;
}
.ant-tabs-nav .ant-tabs-tab {
margin-right: 16px;
}
@ -969,7 +973,7 @@ body {
// 白色背景
.custom-treeselect-white {
.custom-vue-treeselect__control(
#fff,
~'#fff !important',
1px solid #d9d9d9,
none,
@primary-color
@ -1064,7 +1068,7 @@ body {
// }
.vxe-body--row {
&.row--stripe {
background-color: rgba(240, 245, 255, 0.4) !important;
background-color: @primary-color_6 !important;
border-top: 1px solid rgba(0, 0, 0, 0.1) !important;
border-radius: 5px !important;
> td {
@ -1097,6 +1101,7 @@ body {
&:focus {
background-color: @primary-color_7;
border: solid 1px @primary-color;
}
}
}
@ -1110,15 +1115,24 @@ body {
color: #333;
cursor: default;
}
.ant-input:focus,
.ant-input-number:focus,
.ant-input-number-focused {
box-shadow: none;
}
.ant-pagination-options-quick-jumper input:focus {
box-shadow: none;
}
// vxe-table checkbox 选中 highlight
.vxe-table--render-default .vxe-body--row.row--checked,
.vxe-table--render-default .vxe-body--row.row--radio {
background: aliceblue !important;
background: @primary-color_5 !important;
}
.vxe-table--render-default .vxe-body--row.row--hover.row--checked,
.vxe-table--render-default .vxe-body--row.row--hover.row--radio {
background: lightskyblue !important;
background: @primary-color_4 !important;
}
// vxe-table 颜色
@ -1179,6 +1193,15 @@ body {
border-color: @primary-color !important;
}
.vxe-table--render-default .vxe-body--row.row--hover,
.vxe-table--render-default .vxe-body--row.row--hover.row--stripe {
background-color: @primary-color_7;
}
.vxe-select-option:not(.is--disabled).is--hover {
background-color: @primary-color_5;
}
//批量操作
.ops-list-batch-action {
display: inline-block;
@ -1262,7 +1285,7 @@ body {
}
.ant-btn-primary:not(.ant-btn-background-ghost) {
.btn-wave-hover(#3F75FF);
.btn-wave-hover(@primary-color_9);
}
// button
@ -1296,6 +1319,35 @@ body {
}
}
.ops-select-bg {
.ant-select-selection {
background-color: @primary-color_7;
}
&:hover {
.ant-select-selection {
background-color: @primary-color_5;
}
}
.ant-select-focused {
.ant-select-selection {
background-color: @primary-color_7;
border: solid 1px @primary-color;
}
}
}
.ant-select-selection {
box-shadow: none !important;
}
// date picker
.ant-calendar-today .ant-calendar-date {
color: @primary-color;
border-color: @primary-color;
}
//dropdown
.ops-dropdown {
.ant-dropdown-menu-item:hover,
@ -1305,6 +1357,11 @@ body {
}
}
// radio
.ant-radio-input:focus + .ant-radio-inner {
box-shadow: none;
}
//modal
.ant-modal-content {
.ant-modal-close-x {
@ -1396,6 +1453,14 @@ body {
.el-input-number--small .el-input-number__decrease,
.el-input-number--small .el-input-number__increase {
width: 28px;
&:hover {
color: @primary-color;
&:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled) {
border-color: @primary-color;
}
}
}
.el-input-number--small {
@ -1466,3 +1531,16 @@ body {
.ant-form-explain{
font-size: 12px;
}
.ant-message-info .anticon,
.ant-message-loading .anticon {
color: @primary-color_9;
}
.primary-color {
color: @primary-color !important;
}
.primary-bg-color {
background-color: @primary-color;
}

View File

@ -10,6 +10,7 @@
@primary-color_6: #f9fbff;
@primary-color_7: #f7f8fa;
@primary-color_8: #b1c9ff;
@primary-color_9: #3F75FF;
@link-color: @primary-color;
@ -73,7 +74,8 @@
.btn-wave-hover(
@hoverBgColor,
@bgZIndex: 0
@bgZIndex: 0,
@duration: 0.3s
) {
position: relative;
overflow: hidden;
@ -99,10 +101,10 @@
transform: scale(0) translate(-50%, -50%);
transform-origin: left top;
-webkit-transition: -webkit-transform 0.3s ease-out;
transition: -webkit-transform 0.3s ease-out;
transition: transform 0.3s ease-out;
transition: transform 0.3s ease-out, -webkit-transform 0.3s ease-out;
-webkit-transition: -webkit-transform @duration ease-out;
transition: -webkit-transform @duration ease-out;
transition: transform @duration ease-out;
transition: transform @duration ease-out, -webkit-transform @duration ease-out;
}
&:not([disabled]):hover {

View File

@ -100,7 +100,7 @@
/>
</div>
<!-- 筛选框 -->
<div class="Screening-box" v-if="activeGroupIndex === 1" style="background-color: rgb(240, 245, 255)">
<div class="Screening-box" v-if="activeGroupIndex === 1">
<a-popover
@visibleChange="visibleChange"
trigger="click"
@ -1166,7 +1166,7 @@ export default {
.Screening-box {
margin-left: 10px;
display: inline-block;
.ops_display_wrapper(#fff);
.ops_display_wrapper(@primary-color_5);
.screening-box-scene-icon {
color: @primary-color;
font-size: 12px;

View File

@ -340,7 +340,7 @@ export default {
& > a {
padding: 2px 8px;
&:hover {
background-color: #f0faff;
background-color: @primary-color_5;
border-radius: 5px;
}
}