20260922224136

This commit is contained in:
oneao committed 2026-09-22 22:41:36 +08:00
1 parent c8dad8d4a6
commit 0abe3706c8
113 files changed
+5057 -2771

No files matched your search

@@ -492,7 +492,6 @@ function controlPropsOf(row) {
v-for="section in sections"
:key="section.key"
:title="section.title"
:variant="section.title ? 'plain' : 'line'"
:collapsible="false"
:columns="24"
>
@@ -50,9 +50,13 @@ const extraConditionCount = computed(
extraQuickItems.value.filter((item) => hasConditionValue(filters[item.field.b_field])).length,
)
/* 条件列宽上限:4 列整行 = 4×288 + 3×16(列间距)= 1200px,不含右侧操作区。
窗口不够宽时列会等比收缩、只是到不了上限;改这里需同步 .query-grid 的兜底值 */
const GRID_MAX_COLUMN_WIDTH = 288
/** 网格列数按实际可见条件数收缩(最多 4 列):只有一个条件时不应占满 4 列宽 */
const gridStyle = computed(() => ({
gridTemplateColumns: `repeat(${Math.min(Math.max(visibleQuickItems.value.length, 1), 4)}, minmax(0, 200px))`,
gridTemplateColumns: `repeat(${Math.min(Math.max(visibleQuickItems.value.length, 1), 4)}, minmax(0, ${GRID_MAX_COLUMN_WIDTH}px))`,
}))
function initializeDrafts() {
@@ -85,9 +89,11 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true })
<!-- 条件字段走组件库 Form/FormItem:label 排版与全系统一致(并跟随全局布局配置),
Form 根用 display:contents 透明化,真正参与 .query-grid 网格的是里面的 FormItem -->
<div class="query-grid" :style="gridStyle">
<!-- 横向布局下标签按内容收缩(定宽会让短标签拖出一段空白),
长标签由 .query-field 里的 max-width 截断,不会独占整列 -->
<Form class="query-fields" :model="filters" label-width="auto" label-align="left">
<!-- 横向布局下标签定宽 72px(约 5 个汉字)、右对齐:标签右缘与控件左缘严格对齐,
一行内所有控件起始位置一致(与全系统表单同一观感);
4 列网格每列上限 288px(整行 1200px),控件区因此有 216px;
超长字段名由 .query-field 里的省略号截断 -->
<Form class="query-fields" :model="filters" label-width="72px" label-align="right">
<FormItem
v-for="item in visibleQuickItems"
:key="item.field.b_field"
@@ -155,12 +161,13 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true })
align-items: flex-end;
gap: 16px;
}
/* 常用条件网格:一行最多 4 个、每列最大 200px;列数按实际条件数收缩(行内 style 控制),窄屏可收缩 */
/* 常用条件网格:一行最多 4 个、每列最大 288px(整行 1200px,列数与上限由行内 style 下发,
此处只是兜底);窗口不够宽时网格整体收缩、各列等比变窄,不横向溢出 */
.query-grid {
display: grid;
flex: 0 1 auto;
min-width: 0;
grid-template-columns: repeat(4, minmax(0, 200px));
grid-template-columns: repeat(4, minmax(0, 288px));
gap: 8px 16px;
align-items: end;
}
@@ -182,10 +189,10 @@ watch(() => props.queryItems, initializeDrafts, { immediate: true })
white-space: nowrap;
text-overflow: ellipsis;
}
/* 横向:宽度由内容决定(Form 传 label-width="auto"),只兜上限让超长字段名截断、
不把控件挤没;标签与控件的间距从组件库默认 12px 收到 6px */
/* 横向:宽度来自 Form 的 label-width="72px"(定宽,短标签也占满);
标签右对齐由 label-align="right" 在 Form 上传入,这里只把标签与控件的间距
从组件库默认 12px 收到 6px,给控件留出更多宽度 */
.query-fields.fms-form-horizontal .query-field :deep(.fms-form-item-label) {
max-width: 72px;
padding-right: 6px;
}
/* 操作区:紧跟字段右侧、排成一行,右对齐;分「执行」「查询方式/配置」两组,中间竖分隔线 */
@@ -7,7 +7,8 @@
* 通过重新 provide columns 覆盖上下文,使组内 FormItem 的 span 自动按组内宫格计算。
* - FormItem 仍通过 provide/inject 拿到 Form 的 model/rules 校验上下文,组件不拦截。
* - 可选折叠功能(collapsible),默认展开,折叠/展开状态由内部管理或父级 v-model 控制。
* - variant 控制标题视觉风格:line(左竖线 + 右折叠图标,默认)| plain(纯文字标题)。
* - 视觉:整组为一张卡片,标题即卡头(淡底 + 下边框),折叠图标在标题文字左侧
* (收起朝右 / 展开朝下)。与表单设计器的分组卡片语言一致。
*/
import { computed, inject, provide, ref } from 'vue'
import { ChevronDown } from '@lucide/vue'
@@ -16,12 +17,6 @@ import { normalizeGap, fluidColumnGap } from './form-utils'
const props = defineProps({
/** 分组标题;为空则不渲染标题行 */
title: { type: String, default: '' },
/** 标题视觉风格:line(左竖线+右折叠图标)| plain(纯文字) */
variant: {
type: String,
default: 'line',
validator: (value) => ['line', 'plain'].includes(value),
},
/** 组内宫格列数;默认继承外层 Form 的 columns(=1 时组内不建栅格,子项直接堆叠) */
columns: { type: Number, default: null },
/** 在外层 Form 宫格中的占格数;默认 1/-1 占满整行,可设 24 等实现并排 */
@@ -79,7 +74,7 @@ function toggleCollapse() {
</script>
<template>
<div class="fms-form-group" :class="`fms-form-group--${variant}`" :style="groupStyle">
<div class="fms-form-group" :style="groupStyle">
<div
v-if="title"
class="fms-form-group__title"
@@ -87,13 +82,13 @@ function toggleCollapse() {
:title="collapsible ? (expanded ? '点击收起' : '点击展开') : undefined"
@click="toggleCollapse"
>
<span class="fms-form-group__title-text">{{ title }}</span>
<ChevronDown
v-if="collapsible"
:size="14"
class="fms-form-group__collapse-icon"
:class="{ 'is-collapsed': !expanded }"
/>
<span class="fms-form-group__title-text">{{ title }}</span>
</div>
<!-- 折叠用 grid-template-rows 做 0fr ↔ 1fr 过渡:height: auto 无法过渡,
而 v-show 的 display 切换会让过渡直接失效,所以改由 class 控制行高。
@@ -107,18 +102,25 @@ function toggleCollapse() {
</template>
<style scoped lang="scss">
/* 组:不描边——宿主本身就是白卡 / 弹窗,再画一圈会和宿主形成「框套框」;
分层交给卡头淡底 + 一层极轻投影。与表单设计器的分组卡片(.mm-fdesign__section)同族 */
.fms-form-group {
min-width: 0;
border-radius: 8px;
background: var(--fms-card);
box-shadow: 0 1px 2px rgba(39, 54, 70, 0.05);
}
/* ========== 标题:line 风格(默认)========== */
/* ========== 卡头:通栏淡底(无分隔线,淡底与白底的分界即边界) ========== */
.fms-form-group__title {
grid-column: 1 / -1;
display: flex;
align-items: center;
margin: 0 0 8px;
padding: 4px 0 8px 0;
font-size: 14px;
gap: 8px;
padding: 7px 12px;
/* 上圆角跟随卡片:不然有色卡头会顶着卡片的直角 90°,圆角内侧露出白底三角 */
border-radius: 8px 8px 0 0;
background: var(--fms-secondary-hover);
font-size: 12px;
font-weight: 600;
color: var(--fms-text);
line-height: 18px;
@@ -126,35 +128,37 @@ function toggleCollapse() {
&.is-collapsible {
cursor: pointer;
transition: background-color var(--fms-duration-fast) var(--fms-ease-standard);
}
/* 悬停:主色淡 tint(深色下 --fms-secondary 与 --fms-secondary-hover 同值,直接用没有反馈) */
&.is-collapsible:hover {
background: color-mix(in srgb, var(--fms-primary) 8%, var(--fms-secondary-hover));
}
}
/* line 风格:左竖线 + 文字,折叠图标贴右 */
.fms-form-group--line .fms-form-group__title-text {
flex: 1;
min-width: 0;
padding-left: 8px;
border-left: 3px solid var(--fms-primary);
}
/* plain 风格:纯文字,无竖线;可折叠时图标仍贴右 */
.fms-form-group--plain .fms-form-group__title-text {
.fms-form-group__title-text {
flex: 1;
min-width: 0;
}
.fms-form-group__collapse-icon {
flex: none;
margin-left: 8px;
color: var(--fms-text-secondary);
/* 展开 / 收起时箭头翻转,短过渡避免硬跳 */
transition: transform var(--fms-duration-fast) var(--fms-ease-standard);
/* 展开 / 收起时箭头翻转;时长与内容折叠一致,避免箭头先转完、内容还在动 */
transition: transform var(--fms-duration-base) var(--fms-ease-standard);
}
.fms-form-group__collapse-icon.is-collapsed {
transform: rotate(-90deg);
}
/* 折叠后只剩卡头这一条淡底色块:四角都收圆,否则下缘平齐像被截断。
(无描边时形状全靠圆角表达,展开态仍是上圆下直,接住下面的内容区) */
.fms-form-group:has(.fms-form-group__collapse.is-collapsed) .fms-form-group__title {
border-radius: 8px;
}
/* ========== 折叠外壳 ========== */
/* 单行 grid,靠 grid-template-rows 在 1fr / 0fr 之间过渡实现高度动画。
用 grid 而不是 height:height: auto 不可过渡;也不用 v-show 的 display 切换,
@@ -162,11 +166,16 @@ function toggleCollapse() {
.fms-form-group__collapse {
display: grid;
grid-template-rows: 1fr;
/* 内容内边距放在折叠外壳上:卡头才能通栏到底(放卡片根上会被卡头挡住左右两侧) */
padding: 12px 12px 8px;
transition: grid-template-rows var(--fms-duration-base) var(--fms-ease-standard);
}
.fms-form-group__collapse.is-collapsed {
grid-template-rows: 0fr;
/* 行高压到 0 不会压掉自身的 padding:不归零折叠后会多出一条空白 */
padding-top: 0;
padding-bottom: 0;
}
/* 行高被压缩时子项要真能收起来:min-height: 0(允许被压)+ 裁剪(裁掉溢出)。
@@ -10,8 +10,8 @@ const props = defineProps({
default: 'horizontal',
validator: (v) => ['horizontal', 'vertical'].includes(v),
},
/** 分割线是否仅在 hover / 聚焦 / 拖拽时显示,默认常显 */
barOnHover: { type: Boolean, default: false },
/** 分割线是否仅在 hover / 聚焦 / 拖拽时显示,默认非常显 */
barOnHover: { type: Boolean, default: true },
})
const emit = defineEmits(['resize-start', 'resize', 'resize-end'])