20260907224521
This commit is contained in:
1 parent
1b596ffa5b
commit
2f5eac079e
4 files changed
+510
-294
No files matched your search
@@ -5,6 +5,7 @@ import {
|
||||
Columns3,
|
||||
Download,
|
||||
Ellipsis,
|
||||
GripVertical,
|
||||
Maximize2,
|
||||
Plus,
|
||||
Printer,
|
||||
@@ -252,6 +253,7 @@ const advancedNodes = reactive([])
|
||||
const advancedGroups = reactive([])
|
||||
const advancedSnapshot = ref(null)
|
||||
const draggingFieldKey = ref('')
|
||||
const dragOverFieldKey = ref('')
|
||||
const allAdvancedNodes = computed(() => advancedNodes.concat(advancedGroups.flatMap((group) => group.nodes)))
|
||||
function hasNodeValue(value) {
|
||||
return Array.isArray(value) ? value.some((item) => item !== '' && item !== null && item !== undefined) : value !== '' && value !== null && value !== undefined
|
||||
@@ -280,6 +282,13 @@ const extraQuickConditionCount = computed(() => extraQuickSearchFields.value.fil
|
||||
if (field.type === 'numrange') return searchForm[`${field.key}Min`] || searchForm[`${field.key}Max`]
|
||||
return searchForm[field.key] !== '' && searchForm[field.key] !== null && searchForm[field.key] !== undefined
|
||||
}).length)
|
||||
// 常用区已填条件总数:高级模式的说明条要用 —— 告诉用户这些值还在,只是不参与
|
||||
const quickConditionCount = computed(() => quickSearchFields.value.filter((field) => {
|
||||
if (field.type === 'numrange') return searchForm[`${field.key}Min`] || searchForm[`${field.key}Max`]
|
||||
return searchForm[field.key] !== '' && searchForm[field.key] !== null && searchForm[field.key] !== undefined
|
||||
}).length)
|
||||
// 高级模式下常用区强制收起:保留上下文(知道有哪几个常用条件),但不占版面
|
||||
const showAllQuickFields = computed(() => quickSearchExpanded.value && activeQueryMode.value === 'quick')
|
||||
const advancedSearchFields = computed(() =>
|
||||
searchFields.value.filter((field) => field.queryable !== false && queryPrefs[field.key]?.area !== 'hidden'),
|
||||
)
|
||||
@@ -434,12 +443,27 @@ function resetQuickQuery() {
|
||||
Object.assign(searchForm, makeEmptyForm())
|
||||
if (activeQueryMode.value === 'quick') queryApplied.value = false
|
||||
}
|
||||
function startFieldDrag(field) {
|
||||
function startFieldDrag(field, event) {
|
||||
draggingFieldKey.value = field.key
|
||||
// Firefox 下不写 dataTransfer 不会触发 drop,同时声明「移动」语义拿到正确的光标
|
||||
if (event?.dataTransfer) {
|
||||
event.dataTransfer.effectAllowed = 'move'
|
||||
event.dataTransfer.setData('text/plain', field.key)
|
||||
}
|
||||
}
|
||||
function endFieldDrag() {
|
||||
// 必须清理:否则在空白处松手后残留的 key 会让下一次 drop 误排序
|
||||
draggingFieldKey.value = ''
|
||||
dragOverFieldKey.value = ''
|
||||
}
|
||||
function rowDragClass(field) {
|
||||
if (draggingFieldKey.value === field.key) return 'is-dragging'
|
||||
if (dragOverFieldKey.value === field.key && draggingFieldKey.value !== field.key) return 'is-drop-target'
|
||||
return ''
|
||||
}
|
||||
function dropField(field, area) {
|
||||
const sourceKey = draggingFieldKey.value
|
||||
draggingFieldKey.value = ''
|
||||
endFieldDrag()
|
||||
if (!sourceKey || sourceKey === field.key || queryPrefs[sourceKey]?.area !== area) return
|
||||
const rows = searchFields.value.filter((item) => item.queryable !== false && queryPrefs[item.key]?.area === area)
|
||||
.toSorted((a, b) => queryPrefs[a.key].order - queryPrefs[b.key].order)
|
||||
@@ -605,11 +629,22 @@ function onMoreAction({ key }) {
|
||||
|
||||
<template>
|
||||
<div class="dashboard-page">
|
||||
<!-- 页面常用查询:字段来自模块默认配置,并可由用户个性化调整 -->
|
||||
<!-- 搜索区:常用条件来自模块默认配置,并可由用户个性化调整 -->
|
||||
<section class="table-card search-card">
|
||||
<div class="list-search">
|
||||
<template v-if="activeQueryMode === 'quick'">
|
||||
<div v-for="field in (quickSearchExpanded ? quickSearchFields : quickSearchFields.slice(0, QUICK_VISIBLE_LIMIT))" :key="field.key" class="search-field">
|
||||
<!-- 查询设置:卡片级配置,绝对定位在右上角 —— 不占流内高度,
|
||||
也不随字段增减、模式切换位移 -->
|
||||
<Button type="ghost" class="settings-button search-card__settings" title="调整常用条件与高级条件的显示和顺序" @click="openQueryDrawer('settings')">
|
||||
<Settings2 :size="15" /> 查询设置
|
||||
</Button>
|
||||
<!-- 高级模式:常用条件「降权」而不是消失,也不加遮罩 ——
|
||||
遮罩在交互语义上是「阻塞/锁定」,而这里只是「不参与本次查询」。
|
||||
只在你真的填了常用条件时才占这一行:没填值时降权区是空的,不解释也不会困惑 -->
|
||||
<div v-if="activeQueryMode === 'advanced' && quickConditionCount" class="mode-notice">
|
||||
<span class="mode-notice__dot" />
|
||||
<span>顶部已填的 {{ quickConditionCount }} 个常用条件暂不参与本次高级查询,改用简单查询后重新生效。</span>
|
||||
</div>
|
||||
<div class="list-search" :class="{ 'list-search--muted': activeQueryMode === 'advanced' }">
|
||||
<div v-for="field in (showAllQuickFields ? quickSearchFields : quickSearchFields.slice(0, QUICK_VISIBLE_LIMIT))" :key="field.key" class="search-field">
|
||||
<label class="search-field__label">{{ field.label }}</label>
|
||||
<Input
|
||||
v-if="field.type === 'input'"
|
||||
@@ -635,36 +670,44 @@ function onMoreAction({ key }) {
|
||||
<Input v-model="searchForm[`${field.key}Max`]" class="search-field__control--mini" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 操作区只放「执行」类动作;模式切换统一在卡片头的分段控件上,
|
||||
不再让按钮在不同模式下变形 -->
|
||||
<div class="list-search__actions">
|
||||
<template v-if="activeQueryMode === 'quick'">
|
||||
<Button type="primary" @click="onSearch">{{ t('demo.action.search') }}</Button>
|
||||
<Button type="outline" @click="resetQuickQuery">{{ t('demo.action.reset') }}</Button>
|
||||
<Button v-if="extraQuickSearchFields.length" type="ghost" class="quick-more-button" @click="quickSearchExpanded = !quickSearchExpanded">
|
||||
{{ quickSearchExpanded ? '收起常用条件' : `更多常用条件(${extraQuickSearchFields.length})` }}
|
||||
<span v-if="!quickSearchExpanded && extraQuickConditionCount" class="query-count">{{ extraQuickConditionCount }}</span>
|
||||
<ChevronDown :size="14" :class="{ 'is-up': quickSearchExpanded }" />
|
||||
</Button>
|
||||
<Button type="ghost" class="advanced-query-button" @click="selectQueryMode('advanced')">
|
||||
<SlidersHorizontal :size="14" />
|
||||
高级查询
|
||||
<span v-if="advancedConditionCount" class="query-count">{{ advancedConditionCount }}</span>
|
||||
</Button>
|
||||
<div class="action-group">
|
||||
<Button type="primary" @click="onSearch">{{ t('demo.action.search') }}</Button>
|
||||
<Button type="outline" @click="resetQuickQuery">{{ t('demo.action.reset') }}</Button>
|
||||
</div>
|
||||
<div class="action-group">
|
||||
<Button v-if="extraQuickSearchFields.length" type="ghost" class="quick-more-button" @click="quickSearchExpanded = !quickSearchExpanded">
|
||||
{{ quickSearchExpanded ? '收起条件' : '更多条件' }}
|
||||
<span v-if="!quickSearchExpanded && extraQuickConditionCount" class="query-count">{{ extraQuickConditionCount }}</span>
|
||||
<ChevronDown :size="14" :class="{ 'is-up': quickSearchExpanded }" />
|
||||
</Button>
|
||||
<Button type="ghost" class="advanced-query-button advanced-query-button--ghost" @click="selectQueryMode('advanced')">
|
||||
<SlidersHorizontal :size="14" />
|
||||
高级查询
|
||||
<span v-if="advancedConditionCount" class="query-count">{{ advancedConditionCount }}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<Button type="ghost" class="advanced-query-button" @click="openQueryDrawer('conditions')">
|
||||
<SlidersHorizontal :size="14" /> 编辑高级查询
|
||||
<span v-if="advancedConditionCount" class="query-count">{{ advancedConditionCount }}</span>
|
||||
</Button>
|
||||
<Button type="ghost" class="return-quick-button" @click="returnToQuickQuery">改用普通查询</Button>
|
||||
<Button type="outline" @click="resetAllQueries">清除查询</Button>
|
||||
<div class="action-group">
|
||||
<Button type="outline" class="advanced-query-button" @click="openQueryDrawer('conditions')">
|
||||
<SlidersHorizontal :size="14" /> 编辑高级查询
|
||||
<span v-if="advancedConditionCount" class="query-count">{{ advancedConditionCount }}</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="action-group">
|
||||
<Button type="ghost" @click="returnToQuickQuery">改用简单查询</Button>
|
||||
<Button type="ghost" @click="resetAllQueries">清除查询</Button>
|
||||
</div>
|
||||
</template>
|
||||
<Button type="ghost" class="settings-button" title="设置常用查询" @click="openQueryDrawer('settings')"><Settings2 :size="15" /> 设置</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="queryApplied && querySummary.length" class="active-query-bar">
|
||||
<span class="active-query-label">{{ activeQueryMode === 'quick' ? '普通查询生效' : '高级查询生效' }}</span>
|
||||
<span v-for="item in querySummary" :key="item.id" class="active-query-item"><span>{{ item.text }}</span><button type="button" aria-label="移除条件" @click="removeSummaryItem(item)">×</button></span>
|
||||
<span class="active-query-label">{{ activeQueryMode === 'quick' ? '简单查询生效' : '高级查询生效' }}</span>
|
||||
<span v-for="item in querySummary" :key="item.id" class="active-query-item" :title="item.text"><span>{{ item.text }}</span><button type="button" aria-label="移除条件" @click="removeSummaryItem(item)">×</button></span>
|
||||
<button class="clear-query" @click="resetAllQueries">清除全部</button>
|
||||
</div>
|
||||
</section>
|
||||
@@ -742,19 +785,22 @@ function onMoreAction({ key }) {
|
||||
</div>
|
||||
|
||||
<!-- 查询 Drawer:高级条件与查询设置使用独立入口,共用 Drawer 外壳 -->
|
||||
<div v-if="drawerOpen" class="query-drawer-mask" @click.self="closeQueryDrawer">
|
||||
<aside class="query-drawer">
|
||||
<div v-if="drawerOpen" class="query-drawer-mask" :class="{ 'query-drawer-mask--light': drawerTab === 'settings' }" @click.self="closeQueryDrawer">
|
||||
<aside class="query-drawer" :class="{ 'query-drawer--narrow': drawerTab === 'settings' }">
|
||||
<div class="query-drawer__head">
|
||||
<div>
|
||||
<strong>{{ drawerTab === 'conditions' ? '高级查询' : '查询设置' }}</strong>
|
||||
<span class="query-drawer__sub">{{ drawerTab === 'conditions' ? '设置本次查询需要满足的条件' : '调整常用条件的显示和顺序' }}</span>
|
||||
<span class="query-drawer__sub">{{ drawerTab === 'conditions' ? '设置本次查询需要满足的条件,将替代常用条件' : '调整常用条件的显示和顺序,改动即时生效' }}</span>
|
||||
</div>
|
||||
<button class="query-drawer__close" aria-label="关闭" @click="closeQueryDrawer">×</button>
|
||||
</div>
|
||||
<div v-if="drawerTab === 'conditions'" class="query-drawer__body">
|
||||
<div class="drawer-section-title">当前条件</div>
|
||||
<div class="ast-root"><span>满足</span><select v-model="advancedLogic"><option value="and">全部条件</option><option value="or">任一条件</option></select></div>
|
||||
<div v-if="!advancedNodes.length && !advancedGroups.length" class="ast-empty">暂无条件,请从下方添加</div>
|
||||
<div v-if="!advancedNodes.length && !advancedGroups.length" class="ast-empty">
|
||||
<p>暂无条件</p>
|
||||
<Button type="primary" @click="addAdvancedNode">+ 添加条件</Button>
|
||||
</div>
|
||||
<div v-for="node in advancedNodes" :key="node.id" class="ast-row">
|
||||
<div class="ast-field-wrap">
|
||||
<select v-model="node.field" class="ast-field" @change="onNodeFieldChange(node)">
|
||||
@@ -791,20 +837,19 @@ function onMoreAction({ key }) {
|
||||
<Button type="ghost" @click="group.nodes.push(createAdvancedNode(advancedSearchFields[0]?.key || 'creator'))">+ 条件</Button>
|
||||
</div>
|
||||
<div class="ast-hint"><LockKeyhole :size="14" /> 无权限字段不会出现在字段选择器中</div>
|
||||
<div class="drawer-actions"><Button type="outline" @click="addAdvancedNode">+ 添加条件</Button><Button type="outline" @click="addAdvancedGroup">+ 添加条件组</Button></div>
|
||||
<div class="drawer-actions"><Button type="outline" @click="addAdvancedNode">+ 添加条件</Button><Button type="outline" @click="addAdvancedGroup">+ 添加条件组</Button><Button type="ghost" class="clear-conditions" @click="resetAdvancedQuery">清空条件</Button></div>
|
||||
</div>
|
||||
<div v-else class="query-drawer__body settings-body">
|
||||
<div class="drawer-section-title">我的查询布局 <span>只影响当前用户</span></div>
|
||||
<div class="settings-note">拖动调整常用条件顺序,也可以把字段移到高级查询或隐藏。</div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>页面常用查询</strong><span>直接显示在列表顶部</span></div><div v-for="field in searchFields.filter((item) => queryPrefs[item.key].area === 'quick').toSorted((a, b) => queryPrefs[a.key].order - queryPrefs[b.key].order)" :key="field.key" class="setting-row" draggable="true" @dragstart="startFieldDrag(field)" @dragover.prevent @drop="dropField(field, 'quick')"><span class="drag-handle">⋮⋮</span><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFirstQuick(field)">设为第一个</button><button class="setting-more" @click="setFieldArea(field,'advanced')">移到高级</button></div></div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>仅高级查询</strong><span>不占页面空间</span></div><div v-for="field in searchFields.filter((item) => queryPrefs[item.key].area === 'advanced').toSorted((a, b) => queryPrefs[a.key].order - queryPrefs[b.key].order)" :key="field.key" class="setting-row" draggable="true" @dragstart="startFieldDrag(field)" @dragover.prevent @drop="dropField(field, 'advanced')"><span class="drag-handle">⋮⋮</span><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFieldArea(field,'quick')">移到常用</button><button class="setting-more" @click="setFieldArea(field,'hidden')">隐藏</button></div></div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>已隐藏字段</strong><span>可恢复到高级查询</span></div><div v-for="field in searchFields.filter((item) => item.queryable !== false && queryPrefs[item.key].area === 'hidden')" :key="field.key" class="setting-row"><span class="drag-handle">⋮⋮</span><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFieldArea(field,'advanced')">恢复到高级</button></div><div v-if="!searchFields.some((item) => item.queryable !== false && queryPrefs[item.key].area === 'hidden')" class="setting-empty">暂无隐藏字段</div></div>
|
||||
<div class="settings-note">拖动调整常用条件顺序,也可以把字段移到高级条件或隐藏。</div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>页面常用条件</strong><span>直接显示在列表顶部</span></div><div v-for="field in searchFields.filter((item) => queryPrefs[item.key].area === 'quick').toSorted((a, b) => queryPrefs[a.key].order - queryPrefs[b.key].order)" :key="field.key" class="setting-row" :class="rowDragClass(field)" draggable="true" @dragstart="startFieldDrag(field, $event)" @dragover.prevent="dragOverFieldKey = field.key" @dragleave="dragOverFieldKey = ''" @drop="dropField(field, 'quick')" @dragend="endFieldDrag"><GripVertical :size="14" class="drag-handle" /><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFirstQuick(field)">设为第一个</button><button class="setting-more" @click="setFieldArea(field,'advanced')">移到高级</button></div></div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>仅高级条件</strong><span>不占页面空间</span></div><div v-for="field in searchFields.filter((item) => queryPrefs[item.key].area === 'advanced').toSorted((a, b) => queryPrefs[a.key].order - queryPrefs[b.key].order)" :key="field.key" class="setting-row" :class="rowDragClass(field)" draggable="true" @dragstart="startFieldDrag(field, $event)" @dragover.prevent="dragOverFieldKey = field.key" @dragleave="dragOverFieldKey = ''" @drop="dropField(field, 'advanced')" @dragend="endFieldDrag"><GripVertical :size="14" class="drag-handle" /><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFieldArea(field,'quick')">移到常用</button><button class="setting-more" @click="setFieldArea(field,'hidden')">隐藏</button></div></div>
|
||||
<div class="setting-group"><div class="setting-group__head"><strong>已隐藏字段</strong><span>可恢复到高级条件</span></div><div v-for="field in searchFields.filter((item) => item.queryable !== false && queryPrefs[item.key].area === 'hidden')" :key="field.key" class="setting-row"><GripVertical :size="14" class="drag-handle" /><span class="setting-label">{{ field.label }}</span><button class="setting-first" @click="setFieldArea(field,'advanced')">恢复到高级</button></div><div v-if="!searchFields.some((item) => item.queryable !== false && queryPrefs[item.key].area === 'hidden')" class="setting-empty">暂无隐藏字段</div></div>
|
||||
<div class="setting-group setting-group--muted"><div class="setting-group__head"><strong>不可用字段</strong><span>字段权限限制</span></div><div v-for="field in searchFields.filter((item) => item.queryable === false)" :key="field.key" class="setting-row is-disabled"><LockKeyhole :size="14" /><span class="setting-label">{{ field.label }}</span><span class="setting-disabled">无查询权限</span></div></div>
|
||||
</div>
|
||||
<div class="query-drawer__foot">
|
||||
<span v-if="drawerTab === 'conditions'" class="ast-foot-note">已配置 {{ advancedConditionCount }} 个条件</span>
|
||||
<template v-if="drawerTab === 'conditions'">
|
||||
<Button type="ghost" @click="resetAdvancedQuery">清空条件</Button>
|
||||
<Button type="outline" @click="closeQueryDrawer">取消</Button>
|
||||
<Button type="primary" @click="applyAdvancedQuery">应用查询</Button>
|
||||
</template>
|
||||
@@ -853,17 +898,32 @@ function onMoreAction({ key }) {
|
||||
不参与 flex:1 分配、不需要内部滚动。
|
||||
container-type:让 .list-search 的容器查询跟「卡片内容宽」而非视口宽 */
|
||||
.search-card {
|
||||
position: relative;
|
||||
flex: none;
|
||||
min-height: 0;
|
||||
overflow: visible;
|
||||
padding: 12px 16px 8px;
|
||||
container-type: inline-size;
|
||||
}
|
||||
.advanced-query-button { gap: 5px; color: var(--fms-text-secondary); }
|
||||
.advanced-query-button:hover { color: var(--fms-primary); }
|
||||
/* 右上角固定位:绝对定位不占流内高度(查询区本身就不宽裕),
|
||||
右缘与内容区(padding 16)对齐 */
|
||||
.search-card__settings { position: absolute; top: 10px; right: 16px; z-index: 1; }
|
||||
/* 高级模式:常用条件降权(低透明度 + 去饱和 + 禁用交互)而不是消失、也不是遮罩。
|
||||
遮罩的语义是「阻塞/锁定」,这里只是「不参与本次查询」。
|
||||
只降权 .search-field,操作区按钮保持可用 */
|
||||
.list-search--muted .search-field {
|
||||
opacity: 0.45;
|
||||
filter: saturate(0.5);
|
||||
pointer-events: none;
|
||||
}
|
||||
/* 说明条压到最薄:它只在有已填常用条件时才出现,不该再抢版面 */
|
||||
.search-card .mode-notice { margin: 0; padding: 6px 10px; }
|
||||
.advanced-query-button { gap: 5px; }
|
||||
/* ghost(常用模式下的入口)用次要色,不与「查询/重置」抢视觉;
|
||||
outline(高级模式下的主操作)保持主色 */
|
||||
.advanced-query-button--ghost { color: var(--fms-text-secondary); }
|
||||
.advanced-query-button--ghost:hover { color: var(--fms-primary); }
|
||||
.advanced-query-button .query-count { margin-left: 2px; }
|
||||
.return-quick-button { color: var(--fms-text-secondary); }
|
||||
.return-quick-button:hover { color: var(--fms-primary); }
|
||||
|
||||
/* ---- ① 搜索区:固定格宽 + 顶部标签 ---- */
|
||||
.list-search {
|
||||
@@ -936,17 +996,25 @@ function onMoreAction({ key }) {
|
||||
/* 查询/重置/展开:占据流末尾的格子,靠该行右缘对齐(不拉伸占满格子)。
|
||||
展开切换是纯文字 + 旋转箭头,视觉重量低于两个实体按钮,
|
||||
暗示它是「调整形状」而不是「执行动作」 */
|
||||
/* 操作区分「执行 / 扩展 / 配置」三组:组间距 12 > 组内间距 8,
|
||||
配置组 margin-left:auto 钉在行尾 —— 模式切换、字段增减时它的位置都不动 */
|
||||
.list-search__actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
grid-column: 1 / -1;
|
||||
gap: 8px;
|
||||
gap: 12px;
|
||||
justify-self: start;
|
||||
align-self: end;
|
||||
flex-wrap: wrap;
|
||||
min-width: 0;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.action-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
}
|
||||
.quick-more-button { gap: 5px; }
|
||||
.quick-more-button svg { transition: transform 160ms ease; }
|
||||
.quick-more-button svg.is-up { transform: rotate(180deg); }
|
||||
@@ -1101,6 +1169,9 @@ function onMoreAction({ key }) {
|
||||
.active-query-item button:hover { color: var(--fms-danger); }
|
||||
.clear-query { flex: none; border: 0; background: transparent; color: var(--fms-primary); font-size: 12px; }
|
||||
.query-drawer-mask { position: fixed; z-index: 50; inset: 0; background: rgb(31 35 41 / 32%); }
|
||||
/* 设置面板:遮罩压到最浅,让左侧搜索区保持可见 ——
|
||||
调顺序、移分组时能直接看到常用区的实时变化,不用关掉才知道结果 */
|
||||
.query-drawer-mask--light { background: rgb(31 35 41 / 8%); }
|
||||
.query-drawer {
|
||||
display: flex;
|
||||
width: min(760px, 100%);
|
||||
@@ -1110,6 +1181,8 @@ function onMoreAction({ key }) {
|
||||
background: var(--fms-card, #fff);
|
||||
box-shadow: -12px 0 36px rgb(31 35 41 / 15%);
|
||||
}
|
||||
/* 设置面板收窄,给左侧搜索区留出可视空间(条件面板仍需 760px 排布三段式条件行) */
|
||||
.query-drawer--narrow { width: min(420px, 92%); }
|
||||
.query-drawer__head { display: flex; flex: none; align-items: flex-start; justify-content: space-between; padding: 18px 20px 14px; border-bottom: 1px solid var(--fms-border-soft, #f0f1f3); }
|
||||
.query-drawer__head strong { display: block; color: var(--fms-text); font-size: 16px; }
|
||||
.query-drawer__sub { display: block; margin-top: 4px; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
@@ -1122,9 +1195,11 @@ function onMoreAction({ key }) {
|
||||
.drawer-section-title span { color: var(--fms-text-secondary); font-size: 12px; font-weight: 400; }
|
||||
.ast-root { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
.ast-root select, .ast-row select { height: 34px; border: 1px solid var(--fms-border); border-radius: 4px; background: var(--fms-card); color: var(--fms-text); padding: 0 9px; outline: none; }
|
||||
.ast-empty { margin: 8px 0 12px; padding: 18px 12px; border: 1px dashed var(--fms-border); border-radius: 5px; color: var(--fms-text-secondary); font-size: 12px; text-align: center; }
|
||||
.ast-empty { display: flex; flex-direction: column; align-items: center; gap: 10px; margin: 8px 0 12px; padding: 22px 12px; border: 1px dashed var(--fms-border); border-radius: 5px; color: var(--fms-text-secondary); font-size: 12px; text-align: center; }
|
||||
.ast-empty p { margin: 0; }
|
||||
.ast-row { display: grid; grid-template-columns: minmax(160px, 1.25fr) 150px minmax(130px, 1fr) 30px; gap: 8px; align-items: center; margin-bottom: 8px; }
|
||||
.ast-group { margin: 12px 0; padding: 10px; border: 1px solid #dfe6ef; border-radius: 6px; background: #fbfcfe; }
|
||||
/* 条件组:左侧粗竖线表达嵌套层级,让「这一组是一个整体」一眼可辨 */
|
||||
.ast-group { margin: 12px 0; padding: 10px; border: 1px solid #dfe6ef; border-left: 3px solid #b9d3f5; border-radius: 6px; background: #fbfcfe; }
|
||||
.ast-group__head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
.ast-group__head select { height: 30px; }
|
||||
.ast-group__head button { margin-left: auto; border: 0; background: transparent; color: var(--fms-danger); font-size: 12px; cursor: pointer; }
|
||||
@@ -1140,6 +1215,9 @@ function onMoreAction({ key }) {
|
||||
.ast-remove:hover { background: #fff1f0; color: var(--fms-danger); }
|
||||
.ast-hint { display: flex; align-items: center; gap: 6px; margin: 12px 0; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
.drawer-actions { display: flex; gap: 8px; padding-top: 12px; border-top: 1px dashed var(--fms-border); }
|
||||
/* 清空条件:从 footer 挪到条件列表底部并靠右,避免和「取消/应用」两个放弃类动作挤在一起误点 */
|
||||
.clear-conditions { margin-left: auto; color: var(--fms-text-secondary) !important; }
|
||||
.clear-conditions:hover { color: var(--fms-danger) !important; }
|
||||
.query-drawer__foot { display: flex; flex: none; align-items: center; justify-content: flex-end; gap: 8px; padding: 12px 20px; border-top: 1px solid var(--fms-border-soft, #f0f1f3); }
|
||||
.ast-foot-note { flex: 1; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
.settings-note { margin-bottom: 14px; padding: 9px 10px; border: 1px solid #e8edf3; border-radius: 5px; background: #f7f9fc; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
@@ -1149,6 +1227,10 @@ function onMoreAction({ key }) {
|
||||
.setting-group__head strong { color: var(--fms-text); font-size: 13px; }.setting-group__head span { color: var(--fms-text-secondary); font-size: 11px; }
|
||||
.setting-row { display: flex; align-items: center; gap: 8px; min-height: 42px; padding: 0 12px; border-bottom: 1px solid var(--fms-border-soft); }.setting-row:last-child { border-bottom: 0; }
|
||||
.setting-empty { padding: 12px; color: var(--fms-text-secondary); font-size: 12px; }
|
||||
.drag-handle { color: #a3acb8; letter-spacing: -2px; }.setting-label { flex: 1; min-width: 0; color: var(--fms-text); }.setting-row button { border: 0; background: transparent; color: var(--fms-primary); font-size: 12px; }.setting-row button:hover { text-decoration: underline; }.setting-more { color: var(--fms-text-secondary) !important; }.setting-row.is-disabled { color: var(--fms-disabled-text); }.setting-row.is-disabled .setting-label { color: var(--fms-disabled-text); }.setting-disabled { color: var(--fms-disabled-text); font-size: 12px; }
|
||||
.drag-handle { flex: none; color: #a3acb8; cursor: grab; }
|
||||
/* 拖拽排序的视觉反馈:源行半透明 + 目标行顶部插入指示线,
|
||||
否则用户拖的时候不知道会插到哪 */
|
||||
.setting-row.is-dragging { opacity: 0.45; background: #f2f7ff; }
|
||||
.setting-row.is-drop-target { box-shadow: inset 0 2px 0 0 var(--fms-primary, #1677ff); }.setting-label { flex: 1; min-width: 0; color: var(--fms-text); }.setting-row button { border: 0; background: transparent; color: var(--fms-primary); font-size: 12px; }.setting-row button:hover { text-decoration: underline; }.setting-more { color: var(--fms-text-secondary) !important; }.setting-row.is-disabled { color: var(--fms-disabled-text); }.setting-row.is-disabled .setting-label { color: var(--fms-disabled-text); }.setting-disabled { color: var(--fms-disabled-text); font-size: 12px; }
|
||||
@media (max-width: 760px) { .query-drawer__body { padding-inline: 12px; }.query-drawer__head, .query-drawer__foot { padding-inline: 12px; }.ast-row { grid-template-columns: 1fr 1fr; }.ast-row .ast-value { grid-column: 1 / span 2; }.ast-remove { justify-self: end; margin-top: -38px; } .active-query-bar { flex-wrap: wrap; } }
|
||||
</style>
|
||||
Reference in new issue
Block a user