优化
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
<script setup lang="ts">
|
||||
import { Search, RotateCcw } from '@lucide/vue'
|
||||
import { computed, inject, ref, watch } from 'vue'
|
||||
import { Search, RotateCcw, Settings2 } from '@lucide/vue'
|
||||
import LayoutPreferenceList, { type LayoutPreferenceItem } from './LayoutPreferenceList.vue'
|
||||
import {
|
||||
UI_PREFERENCE_SCOPE,
|
||||
readLayoutPreference,
|
||||
removeLayoutPreference,
|
||||
writeLayoutPreference,
|
||||
type LayoutPreferenceSnapshot,
|
||||
} from '@/shared/utils/uiLayoutPreference'
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
@@ -16,7 +25,7 @@ export interface QueryOption {
|
||||
export interface QueryField {
|
||||
key: string
|
||||
type: QueryFieldType
|
||||
label?: string
|
||||
label: string
|
||||
width?: string | number
|
||||
placeholder?: string
|
||||
options?: QueryOption[]
|
||||
@@ -26,6 +35,8 @@ export interface QueryField {
|
||||
const props = withDefaults(defineProps<{
|
||||
ariaLabel: string
|
||||
fields: QueryField[]
|
||||
availableFields?: QueryField[]
|
||||
preferenceKey?: string
|
||||
searchText?: string
|
||||
resetText?: string
|
||||
searchOnReset?: boolean
|
||||
@@ -40,6 +51,69 @@ const emit = defineEmits<{
|
||||
search: [model: QueryModel]
|
||||
reset: [model: QueryModel]
|
||||
}>()
|
||||
const preferenceScope = inject(UI_PREFERENCE_SCOPE, computed(() => 'anonymous'))
|
||||
const preference = ref<LayoutPreferenceSnapshot>({ version: 1, order: [], hidden: [] })
|
||||
const preferenceFields = computed(() => props.availableFields ?? props.fields)
|
||||
const preferenceFieldKeys = computed(() => preferenceFields.value.map((field) => field.key))
|
||||
const preferenceEnabled = computed(() => Boolean(props.preferenceKey))
|
||||
|
||||
function fieldLabel(field: QueryField) {
|
||||
const ariaLabel = field.props?.['aria-label']
|
||||
return field.label || (typeof ariaLabel === 'string' ? ariaLabel : '') || field.placeholder || field.key
|
||||
}
|
||||
|
||||
function applyPreference() {
|
||||
preference.value = readLayoutPreference(
|
||||
'query',
|
||||
preferenceScope.value,
|
||||
props.preferenceKey || '',
|
||||
preferenceFieldKeys.value,
|
||||
)
|
||||
}
|
||||
|
||||
watch(
|
||||
[preferenceScope, () => props.preferenceKey, () => preferenceFieldKeys.value.join('\u0000')],
|
||||
applyPreference,
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
const orderedPreferenceFields = computed(() => {
|
||||
const fieldsByKey = new Map(preferenceFields.value.map((field) => [field.key, field]))
|
||||
return preference.value.order.flatMap((key) => {
|
||||
const field = fieldsByKey.get(key)
|
||||
return field ? [field] : []
|
||||
})
|
||||
})
|
||||
const orderedFields = computed(() => {
|
||||
const visibleKeys = new Set(props.fields.map((field) => field.key))
|
||||
return orderedPreferenceFields.value.filter((field) => visibleKeys.has(field.key))
|
||||
})
|
||||
const preferenceItems = computed<LayoutPreferenceItem[]>(() => orderedPreferenceFields.value.map((field) => ({
|
||||
key: field.key,
|
||||
label: fieldLabel(field),
|
||||
visible: true,
|
||||
hideable: false,
|
||||
movable: true,
|
||||
})))
|
||||
|
||||
function persistPreference(order: string[]) {
|
||||
preference.value = { version: 1, order, hidden: [] }
|
||||
writeLayoutPreference('query', preferenceScope.value, props.preferenceKey || '', preference.value)
|
||||
}
|
||||
|
||||
function moveField(key: string, targetIndex: number) {
|
||||
const order = [...preference.value.order]
|
||||
const currentIndex = order.indexOf(key)
|
||||
if (currentIndex < 0) return
|
||||
order.splice(currentIndex, 1)
|
||||
order.splice(Math.min(Math.max(targetIndex, 0), order.length), 0, key)
|
||||
persistPreference(order)
|
||||
}
|
||||
|
||||
function resetPreference() {
|
||||
removeLayoutPreference('query', preferenceScope.value, props.preferenceKey || '')
|
||||
applyPreference()
|
||||
}
|
||||
|
||||
function updateField(key: string, value: QueryValue) {
|
||||
model.value = { ...model.value, [key]: value }
|
||||
@@ -87,7 +161,7 @@ defineExpose({ search, reset })
|
||||
:aria-label="ariaLabel"
|
||||
>
|
||||
<div class="query-toolbar__filters">
|
||||
<div v-for="field in fields" :key="field.key" class="query-toolbar__field" :style="fieldStyle(field)">
|
||||
<div v-for="field in orderedFields" :key="field.key" class="query-toolbar__field" :style="fieldStyle(field)">
|
||||
<el-input
|
||||
v-if="field.type === 'input'"
|
||||
:model-value="model[field.key] as string"
|
||||
@@ -127,6 +201,12 @@ defineExpose({ search, reset })
|
||||
<el-button type="primary" @click="search"><Search :size="16" />{{ searchText }}</el-button>
|
||||
<el-button @click="reset"><RotateCcw :size="16" />{{ resetText }}</el-button>
|
||||
<slot name="actions" />
|
||||
<el-popover v-if="preferenceEnabled" placement="bottom-end" :width="340" trigger="click" popper-class="cc-layout-preference-popper">
|
||||
<template #reference>
|
||||
<el-button aria-label="调整筛选布局" title="调整筛选布局"><Settings2 :size="16" /></el-button>
|
||||
</template>
|
||||
<LayoutPreferenceList :items="preferenceItems" @move="moveField" @reset="resetPreference" />
|
||||
</el-popover>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -138,5 +218,6 @@ defineExpose({ search, reset })
|
||||
.query-toolbar__field :deep(.el-input), .query-toolbar__field :deep(.el-select), .query-toolbar__field :deep(.el-date-editor) { width: 100%; max-width: 100%; min-width: 0; }
|
||||
.query-toolbar__actions { display: flex; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-start; gap: 8px; }
|
||||
.query-toolbar__actions :deep(.el-button + .el-button) { margin-left: 0; }
|
||||
:global(.cc-layout-preference-popper) { max-width: calc(100vw - 24px); }
|
||||
@media (max-width: 720px) { .query-toolbar { align-items: stretch; flex-direction: column; } .query-toolbar__filters { width: 100%; flex-direction: column; } .query-toolbar__field { width: 100%; } .query-toolbar__actions { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); width: 100%; } .query-toolbar__actions :deep(.el-button) { min-height: 40px; margin-left: 0; } }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user