mirror of
https://github.com/jumpserver/lina.git
synced 2025-04-27 19:15:13 +00:00
commit
e58ec6057c
@ -57,7 +57,7 @@
|
||||
@click="handleClick(action)"
|
||||
>
|
||||
<el-tooltip :content="action.tip" :disabled="!action.tip" :open-delay="500" placement="top">
|
||||
<span>
|
||||
<span :title="action.tip">
|
||||
<span v-if="action.icon && !action.icon.startsWith('el-')" style="vertical-align: initial">
|
||||
<i v-if="action.icon.startsWith('fa')" :class="'fa ' + action.icon" />
|
||||
<svg-icon v-else :icon-class="action.icon" />
|
||||
@ -249,10 +249,11 @@ $color-drop-menu-border: #e4e7ed;
|
||||
align-items: flex-end;
|
||||
|
||||
.el-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 2px 6px;
|
||||
padding: 2px 5px;
|
||||
color: $btn-text-color;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
* {
|
||||
vertical-align: baseline !important;
|
||||
|
@ -223,6 +223,10 @@ export default {
|
||||
line-height: 30px;
|
||||
color: var(--color-text-primary);
|
||||
|
||||
span {
|
||||
display: unset;
|
||||
}
|
||||
|
||||
i {
|
||||
color: var(--color-icon-primary);
|
||||
}
|
||||
|
@ -34,14 +34,12 @@ class StrategyNormal extends StrategyAbstract {
|
||||
onSelectionChange(val) {
|
||||
this.elDataTable.selected = val
|
||||
}
|
||||
|
||||
/**
|
||||
* toggleRowSelection和clearSelection的表现与el-table一致
|
||||
*/
|
||||
toggleRowSelection(...args) {
|
||||
return this.elTable.toggleRowSelection(...args)
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
return this.elTable.clearSelection()
|
||||
}
|
||||
@ -65,24 +63,54 @@ class StrategyPersistSelection extends StrategyAbstract {
|
||||
*/
|
||||
onSelect(selection, row) {
|
||||
const isChosen = selection.indexOf(row) > -1
|
||||
|
||||
this.toggleRowSelection(row, isChosen)
|
||||
}
|
||||
/**
|
||||
* 用户切换当前页的多选
|
||||
*/
|
||||
onSelectAll(selection, selectable = () => true) {
|
||||
// 获取当前所有已选择的项
|
||||
const selectedRows = this.elDataTable.data.filter(r => selection.includes(r))
|
||||
const { id, selected, data } = this.elDataTable
|
||||
const selectableRows = data.filter(selectable)
|
||||
// const isSelected = !!selection.length
|
||||
|
||||
// 判断是否已全选
|
||||
const isSelected = this.elDataTable.data.every(r => selectable(r) && selectedRows.includes(r))
|
||||
// 创建已选择项的 id 集合,用于快速查找
|
||||
const selectedIds = new Set(selected.map(r => r[id]))
|
||||
const currentPageIds = new Set(selectableRows.map(row => row[id]))
|
||||
|
||||
this.elDataTable.data.forEach(r => {
|
||||
if (selectable(r)) {
|
||||
this.toggleRowSelection(r, isSelected)
|
||||
// 前页面的选中状态
|
||||
const currentPageSelectedCount = selectableRows.filter(row =>
|
||||
selectedIds.has(row[id])
|
||||
).length
|
||||
|
||||
// 判断是全选还是取消全选
|
||||
const shouldSelectAll = currentPageSelectedCount < selectableRows.length
|
||||
|
||||
this.elTable.clearSelection()
|
||||
|
||||
if (shouldSelectAll) {
|
||||
selectableRows.forEach(row => {
|
||||
if (!selectedIds.has(row[id])) selected.push(row)
|
||||
|
||||
this.elTable.toggleRowSelection(row, true)
|
||||
|
||||
// ! 这里需要触发事件,否则在 el-table 中无法触发 selection-change 事件
|
||||
this.elDataTable.$emit('toggle-row-selection', true, row)
|
||||
})
|
||||
} else {
|
||||
const newSelected = []
|
||||
|
||||
selected.forEach(row => {
|
||||
if (!currentPageIds.has(row[id])) {
|
||||
newSelected.push(row)
|
||||
} else {
|
||||
this.elDataTable.$emit('toggle-row-selection', false, row)
|
||||
}
|
||||
})
|
||||
|
||||
this.elDataTable.selected = newSelected
|
||||
}
|
||||
|
||||
this.elDataTable.$emit('selection-change', this.elDataTable.selected)
|
||||
}
|
||||
/**
|
||||
* toggleRowSelection和clearSelection管理elDataTable的selected数组
|
||||
@ -105,29 +133,26 @@ class StrategyPersistSelection extends StrategyAbstract {
|
||||
this.elDataTable.$emit('toggle-row-selection', isSelected, row)
|
||||
this.updateElTableSelection()
|
||||
}
|
||||
|
||||
clearSelection() {
|
||||
this.elDataTable.selected = []
|
||||
this.updateElTableSelection()
|
||||
}
|
||||
|
||||
/**
|
||||
* 将selected状态同步到el-table中
|
||||
*/
|
||||
updateElTableSelection() {
|
||||
const { data, id, selected } = this.elDataTable
|
||||
const selectedIds = new Set(selected.map(r => r[id]))
|
||||
|
||||
// 历史勾选的行已经不在当前页了,所以要将当前页的行数据和selected合并
|
||||
const mergeData = _.uniqWith([...data, ...selected], _.isEqual)
|
||||
this.elTable.clearSelection()
|
||||
|
||||
mergeData.forEach(r => {
|
||||
const isSelected = !!selected.find(r2 => r[id] === r2[id])
|
||||
data.forEach(row => {
|
||||
const shouldBeSelected = selectedIds.has(row[id])
|
||||
if (!this.elTable) return
|
||||
|
||||
if (!this.elTable) {
|
||||
return
|
||||
if (shouldBeSelected) {
|
||||
this.elTable.toggleRowSelection(row, true)
|
||||
}
|
||||
|
||||
this.elTable.toggleRowSelection(r, isSelected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +155,13 @@ export default {
|
||||
})
|
||||
},
|
||||
iExportOptions() {
|
||||
return assignIfNot(this.exportOptions, { url: this.tableUrl })
|
||||
/**
|
||||
* 原本是使用 assignIfNot 此函数内部使用 partialRight, 该函数
|
||||
* 只在目标对象的属性未定义时才从源对象复制属性,如果目标对象已经有值,则保留原值
|
||||
* 那如果首次点击的树节点,那么此时 url 就会被确定,后续点击的树节点,那么 url 就不会
|
||||
* 改变了
|
||||
*/
|
||||
return Object.assign({}, this.exportOptions, { url: this.tableUrl })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -17,7 +17,7 @@
|
||||
size="small"
|
||||
type="info"
|
||||
@click="handleTagClick(v,k)"
|
||||
@close="handleTagClose(k)"
|
||||
@close.stop="handleTagClose(k)"
|
||||
>
|
||||
<strong v-if="v.label">{{ v.label + ':' }}</strong>
|
||||
<span v-if="v.valueLabel">{{ v.valueLabel }}</span>
|
||||
@ -128,7 +128,7 @@ export default {
|
||||
deep: true
|
||||
},
|
||||
filterTags: {
|
||||
handler() {
|
||||
handler(newValue) {
|
||||
this.$emit('tag-search', this.filterMaps)
|
||||
},
|
||||
deep: true
|
||||
@ -137,6 +137,15 @@ export default {
|
||||
if (newValue === '' && oldValue !== '') {
|
||||
this.emptyCount = 1
|
||||
}
|
||||
},
|
||||
'$route'(to, from) {
|
||||
if (from.query !== to.query) {
|
||||
this.filterTags = {}
|
||||
if (to.query && Object.keys(to.query).length) {
|
||||
const routeFilter = this.checkInTableColumns(this.options)
|
||||
this.filterTagSearch(routeFilter)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
@ -79,6 +79,9 @@ export default {
|
||||
case 'account_template':
|
||||
url = '/api/v1/accounts/account-templates/'
|
||||
break
|
||||
case 'label':
|
||||
url = '/api/v1/labels/labels/'
|
||||
break
|
||||
case 'name_strategy':
|
||||
options = this.nameOptions
|
||||
break
|
||||
|
@ -6,6 +6,7 @@ export const resourceTypeOptions = [
|
||||
{ label: i18n.t('Node'), value: 'node' },
|
||||
{ label: i18n.t('Zone'), value: 'domain' },
|
||||
{ label: i18n.t('AccountTemplate'), value: 'account_template' },
|
||||
{ label: i18n.t('Tags'), value: 'label' },
|
||||
{ label: i18n.t('Strategy'), value: 'name_strategy' }
|
||||
]
|
||||
|
||||
|
@ -117,7 +117,7 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
|
||||
[vmware]: {
|
||||
name: vmware,
|
||||
title: 'VMware',
|
||||
attrs: ['host', 'port', 'username', 'password'],
|
||||
attrs: ['host', 'port', 'username', 'password', 'auto_sync_node'],
|
||||
image: require('@/assets/img/cloud/vmware.svg')
|
||||
},
|
||||
[nutanix]: {
|
||||
|
@ -10,17 +10,24 @@
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column :label="$tc('Ranking')" width="80px">
|
||||
<template v-slot="scope">
|
||||
<span>{{ scope.$index + 1 }}</span>
|
||||
<template v-slot="scope" #header>
|
||||
<el-tooltip :content="$t('Ranking')" placement="top" :open-delay="500">
|
||||
<span style="cursor: pointer;">{{ $t('Ranking') }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="i in config.columns"
|
||||
:key="i.prop"
|
||||
:label="i.label"
|
||||
:prop="i.prop"
|
||||
:width="i.width"
|
||||
/>
|
||||
>
|
||||
<template #header>
|
||||
<el-tooltip :content="i.label" placement="top" :open-delay="500">
|
||||
<span style="cursor: pointer;">{{ i.label }}</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -30,17 +30,35 @@ export default {
|
||||
let percentage = activeDecimal.dividedBy(totalDecimal).times(100)
|
||||
percentage = isNaN(percentage) ? 0 : percentage
|
||||
percentage = percentage.toFixed(2)
|
||||
|
||||
const formatTitle = (text) => {
|
||||
if (!text) return ''
|
||||
const maxLength = 23
|
||||
const lines = []
|
||||
for (let i = 0; i < text.length; i += maxLength) {
|
||||
lines.push(text.slice(i, i + maxLength))
|
||||
}
|
||||
return lines.join('\n')
|
||||
}
|
||||
|
||||
return {
|
||||
title: [
|
||||
{
|
||||
text: this.config.chartTitle,
|
||||
text: formatTitle(this.config.chartTitle),
|
||||
textStyle: {
|
||||
color: '#646A73',
|
||||
fontSize: 12
|
||||
fontSize: 12,
|
||||
lineHeight: 16,
|
||||
rich: {
|
||||
width: 100,
|
||||
overflow: 'break'
|
||||
}
|
||||
},
|
||||
textAlign: 'center',
|
||||
left: '48%',
|
||||
top: '32%'
|
||||
top: '32%',
|
||||
width: 100,
|
||||
overflow: 'break'
|
||||
},
|
||||
{
|
||||
left: '48%',
|
||||
|
@ -19,6 +19,7 @@
|
||||
type="info"
|
||||
/>
|
||||
<QuickActions
|
||||
v-if="biometricFeaturesActions.some(action => action.has)"
|
||||
:title="$tc('BiometricFeatures')"
|
||||
type="warning"
|
||||
:actions="biometricFeaturesActions"
|
||||
@ -85,13 +86,17 @@ export default {
|
||||
biometricFeaturesActions: [
|
||||
{
|
||||
title: this.$t('FacialFeatures'),
|
||||
has: this.$store.getters.publicSettings.FACE_RECOGNITION_ENABLED &&
|
||||
this.$store.getters.publicSettings.XPACK_LICENSE_EDITION_ULTIMATE,
|
||||
attrs: {
|
||||
type: 'primary',
|
||||
label: this.$store.state.users.profile.is_face_code_set ? this.$t('Unbind') : this.$t('Bind')
|
||||
},
|
||||
callbacks: {
|
||||
click: () => {
|
||||
const next_url = this.$store.state.users.profile.is_face_code_set ? '/core/auth/profile/face/disable/' : '/core/auth/profile/face/enable/'
|
||||
const next_url = this.$store.state.users.profile.is_face_code_set
|
||||
? '/core/auth/profile/face/disable/'
|
||||
: '/core/auth/profile/face/enable/'
|
||||
window.open(next_url, '_blank')
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user