perf: 完善过滤

This commit is contained in:
ibuler 2024-10-23 18:52:50 +08:00
parent 6e894c31a1
commit 4fabdfdc5f
10 changed files with 194 additions and 165 deletions

View File

@ -158,15 +158,21 @@ export default {
options: [ options: [
{ {
label: '最近发现', label: '最近发现',
value: '' filter: {
name: 'asdf'
}
}, },
{ {
label: '最近被登录', label: '最近被登录',
value: '' filter: {
username: 'root'
}
}, },
{ {
label: '最近修改', label: '最近修改',
value: '' filter: {
username: 'admin'
}
}, },
{ {
label: '最近改密', label: '最近改密',

View File

@ -1,18 +1,16 @@
<template> <template>
<el-card shadow="never"> <div>
<div slot="header" class="summary-header"> <div class="summary-header">
<span class="header-title">{{ title }}</span> <span class="title">{{ title }}</span>
</div> </div>
<slot> <slot>
<h1 class="no-margins"> <h3 class="no-margins ">
<span v-if="body.disabled" class="disabled-link">{{ body.count }}</span> <span class="num" @click="handleClick">
<router-link v-else :to="body.route"> {{ iCount }}
<span>{{ body.count }}</span> </span>
</router-link> </h3>
</h1>
<small>{{ body.comment }}</small>
</slot> </slot>
</el-card> </div>
</template> </template>
<script> <script>
@ -23,56 +21,84 @@ export default {
type: String, type: String,
default: '' default: ''
}, },
rightSideLabel: {
type: Object,
default: () => ({})
},
body: { body: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
count: {
type: [Number, String],
default: 0
},
route: {
type: [String, Object],
default: ''
},
callback: {
type: Function,
default: () => {
}
},
disabled: {
type: Boolean,
default: false
}
},
data() {
return {}
},
computed: {
iCount() {
return this.body.count || this.count
},
iRoute() {
return this.body.route || this.route
},
iDisabled() {
return this.body.disabled === undefined ? this.disabled : this.body.disabled
}
},
methods: {
handleClick() {
if (this.iDisabled) {
return
}
if (this.iRoute) {
this.$router.push(this.iRoute)
return
}
this.callback()
} }
} }
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.pull-right { .summary-header {
float: right !important; color: var(--color-icon-primary);
}
.header-title { .title {
font-size: 14px; font-style: normal;
margin: 0 0 7px;
font-weight: 600; font-weight: 600;
font-size: 12px;
text-transform: uppercase;
line-height: 1.2;
} }
}
.right-side ::v-deep .el-tag { .no-margins {
font-weight: 600; margin: 0 !important;
padding: 3px 8px;
text-shadow: none;
line-height: 1;
}
h1 { .num {
font-size: 30px; font-style: normal;
font-weight: 100; font-weight: 500;
} font-size: 24px;
line-height: 40px;
color: var(--color-text-primary);
cursor: pointer;
.el-card__body { &:hover {
background-color: #ffffff; color: var(--color-primary);
color: inherit; }
padding: 15px 20px 20px 20px !important;
border-color: #e7eaec;
border-image: none;
border-style: solid solid none;
border-width: 1px 0;
}
.no-margins {
margin: 0 !important;
}
.disabled-link {
color: #428bca;
} }
}
</style> </style>

View File

@ -2,10 +2,16 @@
<div v-if="filters || summary" :class="isExpand ? 'expand': 'shrink' " class="quick-filter"> <div v-if="filters || summary" :class="isExpand ? 'expand': 'shrink' " class="quick-filter">
<div v-show="isExpand" class="quick-filter-wrap"> <div v-show="isExpand" class="quick-filter-wrap">
<div v-show="filters" class="quick-filter-zone"> <div v-show="filters" class="quick-filter-zone">
<div v-for="category in filters" :key="category.label" class="item-zone"> <div v-for="category in iFilters" :key="category.label" class="item-zone">
<h5>{{ category.label }}</h5> <h5>{{ category.label }}</h5>
<div class="filter-options"> <div class="filter-options">
<span v-for="option in category.options" :key="option.label" class="item"> <span
v-for="option in category.options"
:key="option.label"
:class="option.active ? 'active' : ''"
class="item"
@click="handleClick(option)"
>
{{ option.label }} {{ option.label }}
</span> </span>
</div> </div>
@ -13,7 +19,7 @@
</div> </div>
<div v-show="summary" class="summary-zone"> <div v-show="summary" class="summary-zone">
<span v-for="item of summary" :key="item.title"> <span v-for="item of summary" :key="item.title">
<SummaryCard :body="item.body" :title="item.title" /> <SummaryCard :count="item.count" :title="item.title" @click="handleSummaryClick(item)" />
</span> </span>
</div> </div>
</div> </div>
@ -27,7 +33,7 @@
</template> </template>
<script> <script>
import SummaryCard from '@/views/dashboard/components/SummaryCard.vue' import SummaryCard from '@/components/Cards/SummaryCard'
export default { export default {
name: 'QuickFilter', name: 'QuickFilter',
@ -48,9 +54,13 @@ export default {
}, },
data() { data() {
return { return {
isExpand: this.expand isExpand: this.expand,
iFilters: this.cleanFilters(),
filtered: {},
activeFilters: []
} }
}, },
computed: {},
watch: { watch: {
isExpand(val) { isExpand(val) {
this.$emit('expand', val) this.$emit('expand', val)
@ -59,8 +69,49 @@ export default {
mounted() { mounted() {
}, },
methods: { methods: {
cleanFilters() {
return this.filters.map(category => {
return {
...category,
options: category.options.map(option => {
return {
category: category.label,
...option,
active: false,
filter: option.filter || {}
}
})
}
})
},
toggle() { toggle() {
this.isExpand = !this.isExpand this.isExpand = !this.isExpand
},
handleClick(option) {
if (!option.active) {
this.activeFilters = this.activeFilters.filter(item => {
const conflict = Object.keys(item.filter).some(key => {
return Object.keys(option.filter).includes(key)
})
if (conflict) {
item.active = false
}
return !conflict
})
this.activeFilters.push(option)
} else {
this.activeFilters = this.activeFilters.filter(item => {
return item.label !== option.label && item.category !== option.category
})
}
option.active = !option.active
this.activeFilters.forEach(item => {
this.filtered = { ...item.filter }
})
this.$emit('filter', this.filtered)
},
handleSummaryClick(item) {
this.$emit('filter', item)
} }
} }
} }
@ -119,6 +170,11 @@ export default {
font-size: 12px; font-size: 12px;
cursor: pointer; cursor: pointer;
&.active {
color: var(--color-primary);
font-weight: 500;
}
&:hover { &:hover {
color: var(--color-primary); color: var(--color-primary);
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<QuickFilter :filters="quickFilters" :summary="quickSummary" @filter="handleQuickFilter" /> <QuickFilter :filters="quickFilters" :summary="quickSummary" @filter="filter" />
<TableAction <TableAction
v-if="hasActions" v-if="hasActions"
:date-pick="handleDateChange" :date-pick="handleDateChange"
@ -219,8 +219,24 @@ export default {
}) })
}, },
methods: { methods: {
handleQuickFilter() { handleQuickFilter(option) {
if (option.route) {
this.$router.push(option.route)
return
}
if (option.filter) {
const filter = { ...option.filter }
if (option.active) {
for (const key in filter) {
filter[key] = ''
}
}
this.filter(option.filter)
return
}
if (option.callback) {
option.callback(option.active)
}
}, },
handleActionInitialDone() { handleActionInitialDone() {
setTimeout(() => { setTimeout(() => {

View File

@ -55,25 +55,23 @@ export default {
quickSummary: [ quickSummary: [
{ {
title: '最近一周发现', title: '最近一周发现',
body: { count: 10,
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }}, filter: {
count: 10, name: 'admin'
disabled: 0
} }
}, },
{ {
title: '最近一月发现', title: '最近一月发现',
body: { count: 321,
route: { name: `SessionList`, params: { activeMenu: 'OnlineList' }}, filter: {
count: 321, username: 'admin'
disabled: 0
} }
}, },
{ {
title: '待确认', title: '待确认',
body: { count: 544,
count: 544, filter: {
disabled: true username: 'admin'
} }
} }
], ],

View File

@ -15,7 +15,7 @@
<script> <script>
import Title from '../components/Title.vue' import Title from '../components/Title.vue'
import SummaryCard from '../components/SummaryCard' import SummaryCard from '@/components/Cards/SummaryCard'
export default { export default {
components: { Title, SummaryCard }, components: { Title, SummaryCard },

View File

@ -15,7 +15,7 @@
<script> <script>
import Title from '../components/Title.vue' import Title from '../components/Title.vue'
import SummaryCard from '../components/SummaryCard' import SummaryCard from '@/components/Cards/SummaryCard'
export default { export default {
components: { Title, SummaryCard }, components: { Title, SummaryCard },

View File

@ -15,7 +15,7 @@
<script> <script>
import Title from './Title.vue' import Title from './Title.vue'
import SummaryCard from './SummaryCard' import SummaryCard from '@/components/Cards/SummaryCard'
export default { export default {
components: { Title, SummaryCard }, components: { Title, SummaryCard },
@ -85,15 +85,18 @@ export default {
.box { .box {
padding: 20px; padding: 20px;
background: #FFFFFF; background: #FFFFFF;
.content { .content {
.el-col { .el-col {
padding-left: 16px; padding-left: 16px;
border-left: 1px solid #EFF0F1; border-left: 1px solid #EFF0F1;
&:first-child { &:first-child {
padding-left: 0; padding-left: 0;
border-left: none; border-left: none;
} }
} }
.sub { .sub {
font-style: normal; font-style: normal;
font-weight: 400; font-weight: 400;
@ -101,6 +104,7 @@ export default {
line-height: 20px; line-height: 20px;
color: #646A73; color: #646A73;
} }
.num { .num {
font-style: normal; font-style: normal;
font-weight: 500; font-weight: 500;

View File

@ -1,71 +0,0 @@
<template>
<div>
<div class="summary-header">
<span class="title">{{ title }}</span>
</div>
<slot>
<h3 class="no-margins">
<span v-if="body.disabled" class="num">
{{ body.count }}
</span>
<router-link v-else :to="body.route">
<span class="num disabled-link">{{ body.count }}</span>
</router-link>
</h3>
</slot>
</div>
</template>
<script>
export default {
name: 'SummaryCard',
props: {
title: {
type: String,
default: ''
},
rightSideLabel: {
type: Object,
default: () => ({})
},
body: {
type: Object,
default: () => ({})
}
}
}
</script>
<style lang="scss" scoped>
.summary-header {
color: var(--color-icon-primary);
.title {
font-style: normal;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
line-height: 1.2;
}
}
.no-margins {
margin: 0 !important;
.num {
font-style: normal;
font-weight: 500;
font-size: 24px;
line-height: 40px;
color: var(--color-text-primary);
}
.disabled-link {
cursor: pointer;
&:hover {
color: var(--color-primary);
}
}
}
</style>

View File

@ -4,18 +4,20 @@
<Title :config="config" /> <Title :config="config" />
</div> </div>
<div class="content"> <div class="content">
<el-row type="flex" justify="space-between"> <SummaryCard
<el-col v-for="item of items" :key="item.title" :md="8" :sm="12" :xs="12"> v-for="item of items"
<SummaryCard :title="item.title" :body="item.body" /> :key="item.title"
</el-col> :body="item.body"
</el-row> :title="item.title"
class="summary-card"
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import Title from '../components/Title.vue' import Title from '../components/Title.vue'
import SummaryCard from '../components/SummaryCard' import SummaryCard from '@/components/Cards/SummaryCard'
export default { export default {
components: { Title, SummaryCard }, components: { Title, SummaryCard },
@ -35,8 +37,7 @@ export default {
} }
}, },
data() { data() {
return { return {}
}
} }
} }
</script> </script>
@ -45,28 +46,21 @@ export default {
.box { .box {
padding: 20px; padding: 20px;
background: #FFFFFF; background: #FFFFFF;
.content { .content {
.el-col { display: flex;
justify-content: space-between;
padding: 0 10px;
.summary-card {
padding-left: 16px; padding-left: 16px;
border-left: 1px solid #EFF0F1; border-left: 1px solid #EFF0F1;
&:first-child { &:first-child {
padding-left: 0; padding-left: 0;
border-left: none; border-left: none;
} }
} }
.sub {
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 20px;
color: #646A73;
}
.num {
font-style: normal;
font-weight: 500;
font-size: 24px;
cursor: pointer;
}
} }
} }
</style> </style>