refactor(module-management): R2c 表单设计面板 UI 归一

- 字段库搜索/占位符/栅格宽度/文本域高度输入 → ui Input(change 载荷改为值)
- 编辑方式切换 → ui RadioGroup;设计/数据视图切换 → ui Tabs(nav-only)
- 帮助气泡 → ui Popover(hover),删除自绘 help-pop/.mm-edit__help 样式
- 属性面板折叠/展开钮 → ui Button;状态开关×4 → ui Switch
- 分组名称内联编辑 → ui Input;确认/取消/齿轮/删除 → ui Button(type=ghost)
- 删除废弃 .mm-fdesign__toggle、.mm-edit__mode-btn、.mm-edit__view-btn 样式
- 适配 .mm-edit__mode / .mm-edit__view-switch 为紧凑字号
- 所有 Button 覆写样式加 .button 后缀(确保覆盖 ui Button 默认尺寸)
- 所有 Input 覆写样式加 .input-wrapper 后缀
- 替换 .mm-fdesign__span-control input[type=number] 为 .mm-fdesign__span-input.input-wrapper
This commit is contained in:
oneao committed 2026-08-28 17:00:00 +08:00
1 parent 8c506ae56c
commit 76b12cc5e1
1 file changed
+142 -323
@@ -26,8 +26,13 @@ import draggable from 'vuedraggable'
import { import {
Message, Message,
Button, Button,
Select,
Input, Input,
Popover,
Radio,
RadioGroup,
Select,
Switch,
Tabs,
Checkbox, Checkbox,
DatePicker, DatePicker,
Form, Form,
@@ -1306,12 +1311,12 @@ function onColspanChange(value) {
} }
// 数字输入框 change(失焦/回车)提交:与原值不同才真正写入 // 数字输入框 change(失焦/回车)提交:与原值不同才真正写入
function onColspanInput(event) { function onColspanInput(value) {
const row = selectedRow.value const row = selectedRow.value
if (!row || props.loading) return if (!row || props.loading) return
const value = Math.min(24, Math.max(1, Number(event.target.value) || 24)) const next = Math.min(24, Math.max(1, Number(value) || 24))
if (value === spanOf(row)) return if (next === spanOf(row)) return
onColspanChange(value) onColspanChange(next)
} }
function onHeightChange(value) { function onHeightChange(value) {
@@ -1322,12 +1327,12 @@ function onHeightChange(value) {
} }
/* 占位符:change(失焦/回车)提交,有变化才真正写入 */ /* 占位符:change(失焦/回车)提交,有变化才真正写入 */
function onPlaceholderChange(event) { function onPlaceholderChange(value) {
const row = selectedRow.value const row = selectedRow.value
if (!row || props.loading) return if (!row || props.loading) return
const value = event.target.value.trim() const next = String(value ?? '').trim()
if ((row.b_placeholder || '') === value) return if ((row.b_placeholder || '') === next) return
row.b_placeholder = value || null row.b_placeholder = next || null
emitUpdate() emitUpdate()
} }
@@ -1424,12 +1429,7 @@ onBeforeUnmount(() => {
:class="{ 'is-inspector-collapsed': inspectorCollapsed }" :class="{ 'is-inspector-collapsed': inspectorCollapsed }"
> >
<aside class="mm-fdesign__lib" aria-label="字段列表"> <aside class="mm-fdesign__lib" aria-label="字段列表">
<input <Input v-model="libSearch" class="mm-fdesign__lib-search" placeholder="搜索字段名 / 编码" />
v-model="libSearch"
class="mm-fdesign__lib-search"
type="text"
placeholder="搜索字段名 / 编码"
/>
<div class="mm-fdesign__lib-group"> <div class="mm-fdesign__lib-group">
<draggable <draggable
class="mm-fdesign__lib-list" class="mm-fdesign__lib-list"
@@ -1475,50 +1475,30 @@ onBeforeUnmount(() => {
<div class="mm-fdesign__main"> <div class="mm-fdesign__main">
<div class="mm-edit__head"> <div class="mm-edit__head">
<div class="mm-edit__head-left"> <div class="mm-edit__head-left">
<div class="mm-edit__mode" role="group" aria-label="编辑方式"> <RadioGroup
<button class="mm-edit__mode"
type="button" role="group"
class="mm-edit__mode-btn" aria-label="编辑方式"
:class="{ 'is-active': (editMode || 'form') === 'form' }" :model-value="editMode || 'form'"
title="主表:以表单形式编辑" :disabled="loading"
:disabled="loading" @update:model-value="onEditModeChange"
@click="onEditModeChange('form')" >
> <Radio value="form" title="主表:以表单形式编辑">主表表单</Radio>
主表表单 <Radio value="table" title="子表:以表格形式编辑">子表表格</Radio>
</button> </RadioGroup>
<button
type="button"
class="mm-edit__mode-btn"
:class="{ 'is-active': (editMode || 'form') === 'table' }"
title="子表:以表格形式编辑"
:disabled="loading"
@click="onEditModeChange('table')"
>
子表表格
</button>
</div>
</div> </div>
<div class="mm-edit__head-center"> <div class="mm-edit__head-center">
<div class="mm-edit__view-switch" role="tablist" aria-label="视图切换"> <Tabs
<button class="mm-edit__view-switch"
type="button" nav-only
class="mm-edit__view-btn" :items="[
:class="{ 'is-active': viewMode === 'design' }" { key: 'design', label: '设计' },
data-view="design" { key: 'data', label: '数据' },
@click="switchView('design')" ]"
> :model-value="viewMode"
设计 aria-label="视图切换"
</button> @update:model-value="switchView"
<button />
type="button"
class="mm-edit__view-btn"
:class="{ 'is-active': viewMode === 'data' }"
data-view="data"
@click="switchView('data')"
>
数据
</button>
</div>
</div> </div>
<div class="mm-edit__head-right"> <div class="mm-edit__head-right">
<Button type="outline" :disabled="loading" @click="addGroup"> <Button type="outline" :disabled="loading" @click="addGroup">
@@ -1527,9 +1507,11 @@ onBeforeUnmount(() => {
<Button type="ghost" :disabled="loading" @click="previewOpen = true"> <Button type="ghost" :disabled="loading" @click="previewOpen = true">
<Eye :size="14" /> 预览 <Eye :size="14" /> 预览
</Button> </Button>
<div class="mm-edit__help"> <Popover trigger="hover" placement="bottom-end" :arrow="false" :offset="8">
<span class="mm-edit__help-icon" aria-hidden="true">?</span> <template #trigger>
<div class="mm-edit__help-pop"> <span class="mm-edit__help-icon" aria-hidden="true">?</span>
</template>
<template #content>
<div class="mm-edit__help-title">快捷键</div> <div class="mm-edit__help-title">快捷键</div>
<ul class="mm-edit__help-list"> <ul class="mm-edit__help-list">
<li><kbd>Ctrl+C</kbd> 复制选中字段属性</li> <li><kbd>Ctrl+C</kbd> 复制选中字段属性</li>
@@ -1537,8 +1519,8 @@ onBeforeUnmount(() => {
<li><kbd>Ctrl+V</kbd> 粘贴属性到选中字段</li> <li><kbd>Ctrl+V</kbd> 粘贴属性到选中字段</li>
<li><kbd>Delete</kbd> 删除选中字段</li> <li><kbd>Delete</kbd> 删除选中字段</li>
</ul> </ul>
</div> </template>
</div> </Popover>
</div> </div>
</div> </div>
@@ -1584,7 +1566,7 @@ onBeforeUnmount(() => {
<GripVertical :size="13" /> <GripVertical :size="13" />
</button> </button>
<template v-if="editingGroupKey === section.key"> <template v-if="editingGroupKey === section.key">
<input <Input
ref="sectionEditInput" ref="sectionEditInput"
v-model="groupTitleDraft" v-model="groupTitleDraft"
class="mm-fdesign__section-edit" class="mm-fdesign__section-edit"
@@ -1596,24 +1578,24 @@ onBeforeUnmount(() => {
@blur="commitEditGroupTitle(section)" @blur="commitEditGroupTitle(section)"
/> />
<span class="mm-fdesign__section-edit-actions"> <span class="mm-fdesign__section-edit-actions">
<button <Button
type="button" type="ghost"
class="mm-fdesign__section-edit-btn" class="mm-fdesign__section-edit-btn"
title="确认" title="确认"
aria-label="确认修改分组名" aria-label="确认修改分组名"
@mousedown.prevent="commitEditGroupTitle(section)" @mousedown.prevent="commitEditGroupTitle(section)"
> >
<Check :size="13" /> <Check :size="13" />
</button> </Button>
<button <Button
type="button" type="ghost"
class="mm-fdesign__section-edit-btn" class="mm-fdesign__section-edit-btn"
title="取消" title="取消"
aria-label="取消修改分组名" aria-label="取消修改分组名"
@mousedown.prevent="cancelEditGroupTitle" @mousedown.prevent="cancelEditGroupTitle"
> >
<X :size="13" /> <X :size="13" />
</button> </Button>
</span> </span>
</template> </template>
<template v-else> <template v-else>
@@ -1631,25 +1613,25 @@ onBeforeUnmount(() => {
@click.stop="startEditGroupTitle(section)" @click.stop="startEditGroupTitle(section)"
>空</span> >空</span>
<span class="mm-edit__section-meta"> <span class="mm-edit__section-meta">
<button <Button
type="button" type="ghost"
class="mm-fdesign__section-btn" class="mm-fdesign__section-btn"
title="分组设置" title="分组设置"
aria-label="分组设置" aria-label="分组设置"
@click.stop="openSectionSettings(section)" @click.stop="openSectionSettings(section)"
> >
<Settings2 :size="13" /> <Settings2 :size="13" />
</button> </Button>
<button <Button
v-if="section.group" v-if="section.group"
type="button" type="ghost"
class="mm-fdesign__section-del" class="mm-fdesign__section-del"
title="删除分组(其下字段移至未分组)" title="删除分组(其下字段移至未分组)"
aria-label="删除分组" aria-label="删除分组"
@click.stop="deleteGroupDirect(section)" @click.stop="deleteGroupDirect(section)"
> >
<Trash2 :size="13" /> <Trash2 :size="13" />
</button> </Button>
</span> </span>
</template> </template>
</div> </div>
@@ -1741,15 +1723,15 @@ onBeforeUnmount(() => {
<EyeOff v-else :size="12" /> <EyeOff v-else :size="12" />
</button> </button>
</span> </span>
<button <Button
type="button" type="ghost"
class="mm-fdesign__tool-btn is-danger" class="mm-fdesign__tool-btn is-danger"
title="删除字段" title="删除字段"
aria-label="删除字段" aria-label="删除字段"
@click.stop="removeRow(row)" @click.stop="removeRow(row)"
> >
<Trash2 :size="12" /> <Trash2 :size="12" />
</button> </Button>
</div> </div>
<div class="mm-fdesign__field-control"> <div class="mm-fdesign__field-control">
<input <input
@@ -1865,30 +1847,30 @@ onBeforeUnmount(() => {
:class="{ 'is-collapsed': inspectorCollapsed }" :class="{ 'is-collapsed': inspectorCollapsed }"
aria-label="属性面板" aria-label="属性面板"
> >
<button <Button
v-if="inspectorCollapsed" v-if="inspectorCollapsed"
type="button" type="ghost"
class="mm-fdesign__panel-expand" class="mm-fdesign__panel-expand"
title="展开属性面板" title="展开属性面板"
aria-label="展开属性面板" aria-label="展开属性面板"
@click="inspectorCollapsed = false" @click="inspectorCollapsed = false"
> >
<PanelRightOpen :size="14" /> <PanelRightOpen :size="14" />
</button> </Button>
<template v-else> <template v-else>
<div class="mm-fdesign__subhead"> <div class="mm-fdesign__subhead">
<strong>属性</strong> <strong>属性</strong>
<span class="mm-fdesign__subhead-meta"> <span class="mm-fdesign__subhead-meta">
<span>{{ selectedRow ? fieldName(selectedRow) : '未选中字段' }}</span> <span>{{ selectedRow ? fieldName(selectedRow) : '未选中字段' }}</span>
<button <Button
type="button" type="ghost"
class="mm-fdesign__collapse" class="mm-fdesign__collapse"
title="折叠属性面板" title="折叠属性面板"
aria-label="折叠属性面板" aria-label="折叠属性面板"
@click="inspectorCollapsed = true" @click="inspectorCollapsed = true"
> >
<PanelRightClose :size="13" /> <PanelRightClose :size="13" />
</button> </Button>
</span> </span>
</div> </div>
<template v-if="selectedRow"> <template v-if="selectedRow">
@@ -1903,12 +1885,11 @@ onBeforeUnmount(() => {
</div> </div>
<div class="mm-fdesign__prop mm-fdesign__prop--full"> <div class="mm-fdesign__prop mm-fdesign__prop--full">
<label for="mm-fdesign-placeholder">占位符</label> <label for="mm-fdesign-placeholder">占位符</label>
<input <Input
id="mm-fdesign-placeholder" id="mm-fdesign-placeholder"
class="mm-fdesign__prop-input" class="mm-fdesign__prop-input"
type="text"
maxlength="100" maxlength="100"
:value="selectedRow.b_placeholder || ''" :model-value="selectedRow.b_placeholder || ''"
:disabled="loading" :disabled="loading"
placeholder="输入框内的浅色提示文字" placeholder="输入框内的浅色提示文字"
@change="onPlaceholderChange" @change="onPlaceholderChange"
@@ -1922,12 +1903,11 @@ onBeforeUnmount(() => {
> >
<label for="mm-fdesign-colspan">栅格宽度</label> <label for="mm-fdesign-colspan">栅格宽度</label>
<div class="mm-fdesign__span-control"> <div class="mm-fdesign__span-control">
<input <Input
id="mm-fdesign-colspan" id="mm-fdesign-colspan"
type="number" type="number"
min="1" class="mm-fdesign__span-input"
max="24" :model-value="spanOf(selectedRow)"
:value="spanOf(selectedRow)"
:disabled="loading" :disabled="loading"
aria-label="栅格宽度" aria-label="栅格宽度"
@change="onColspanInput" @change="onColspanInput"
@@ -1944,14 +1924,13 @@ onBeforeUnmount(() => {
:options="TEXTAREA_HEIGHT_OPTIONS" :options="TEXTAREA_HEIGHT_OPTIONS"
@update:model-value="onHeightChange" @update:model-value="onHeightChange"
/> />
<input <Input
type="number" type="number"
min="64" class="mm-fdesign__span-input"
max="480" :model-value="heightOf(selectedRow)"
:value="heightOf(selectedRow)"
:disabled="loading" :disabled="loading"
aria-label="自定义文本域高度" aria-label="自定义文本域高度"
@change="(event) => onHeightChange(event.target.value)" @change="onHeightChange"
/> />
</div> </div>
</div> </div>
@@ -1960,47 +1939,35 @@ onBeforeUnmount(() => {
<div class="mm-fdesign__toggles"> <div class="mm-fdesign__toggles">
<div class="mm-fdesign__toggle-line"> <div class="mm-fdesign__toggle-line">
<span>必填</span> <span>必填</span>
<button <Switch
type="button" :model-value="Number(selectedRow.b_required) === 1"
class="mm-fdesign__toggle"
:class="{ 'is-on': Number(selectedRow.b_required) === 1 }"
:aria-pressed="Number(selectedRow.b_required) === 1"
:disabled="loading" :disabled="loading"
@click="toggleInspector('b_required')" @update:model-value="() => toggleInspector('b_required')"
></button> />
</div> </div>
<div class="mm-fdesign__toggle-line"> <div class="mm-fdesign__toggle-line">
<span>只读</span> <span>只读</span>
<button <Switch
type="button" :model-value="Number(selectedRow.b_readonly) === 1"
class="mm-fdesign__toggle"
:class="{ 'is-on': Number(selectedRow.b_readonly) === 1 }"
:aria-pressed="Number(selectedRow.b_readonly) === 1"
:disabled="loading" :disabled="loading"
@click="toggleInspector('b_readonly')" @update:model-value="() => toggleInspector('b_readonly')"
></button> />
</div> </div>
<div class="mm-fdesign__toggle-line"> <div class="mm-fdesign__toggle-line">
<span>禁用</span> <span>禁用</span>
<button <Switch
type="button" :model-value="Number(selectedRow.b_disabled) === 1"
class="mm-fdesign__toggle"
:class="{ 'is-on': Number(selectedRow.b_disabled) === 1 }"
:aria-pressed="Number(selectedRow.b_disabled) === 1"
:disabled="loading" :disabled="loading"
@click="toggleInspector('b_disabled')" @update:model-value="() => toggleInspector('b_disabled')"
></button> />
</div> </div>
<div class="mm-fdesign__toggle-line"> <div class="mm-fdesign__toggle-line">
<span>显示</span> <span>显示</span>
<button <Switch
type="button" :model-value="Number(selectedRow.b_visible) === 1"
class="mm-fdesign__toggle"
:class="{ 'is-on': Number(selectedRow.b_visible) === 1 }"
:aria-pressed="Number(selectedRow.b_visible) === 1"
:disabled="loading" :disabled="loading"
@click="toggleInspector('b_visible')" @update:model-value="() => toggleInspector('b_visible')"
></button> />
</div> </div>
</div> </div>
<div class="mm-fdesign__prop-group">操作</div> <div class="mm-fdesign__prop-group">操作</div>
@@ -2248,82 +2215,17 @@ onBeforeUnmount(() => {
justify-content: flex-end; justify-content: flex-end;
} }
/* 编辑方式:ui RadioGroup(紧凑字号) */
.mm-edit__mode { .mm-edit__mode {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 3px;
border: 1px solid var(--fms-border);
border-radius: var(--fms-control-radius);
background: var(--fms-secondary);
}
/* 编辑方式分段按钮(主表表单 / 子表表格) */
.mm-edit__mode-btn {
height: 26px;
padding: 0 12px;
border: none;
border-radius: 4px;
background: transparent;
color: var(--fms-text-secondary);
font-size: 12px; font-size: 12px;
white-space: nowrap;
cursor: pointer;
&.is-active {
background: var(--fms-card);
color: var(--fms-text);
font-weight: 600;
box-shadow: 0 1px 3px rgba(30, 45, 64, 0.12);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
} }
/* 视图切换:ui Tabs nav-only */
.mm-edit__view-switch { .mm-edit__view-switch {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 3px;
border: 1px solid var(--fms-border);
border-radius: var(--fms-control-radius);
background: var(--fms-secondary);
}
.mm-edit__view-btn {
height: 26px;
padding: 0 12px;
border: none;
border-radius: 4px;
background: transparent;
color: var(--fms-text-secondary);
font-size: 12px; font-size: 12px;
cursor: pointer;
&.is-active {
background: var(--fms-card);
color: var(--fms-text);
font-weight: 600;
box-shadow: 0 1px 3px rgba(30, 45, 64, 0.12);
}
}
/* ---- 快捷键帮助(右上角 ? 图标,hover 展示) ---- */
.mm-edit__help {
position: relative;
display: inline-flex;
align-items: center;
align-self: center;
&:hover .mm-edit__help-pop,
&:focus-within .mm-edit__help-pop {
display: block;
}
} }
/* ---- 快捷键帮助(右上角 ? 图标,ui Popover hover 展示) ---- */
.mm-edit__help-icon { .mm-edit__help-icon {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@@ -2351,20 +2253,6 @@ onBeforeUnmount(() => {
} }
} }
.mm-edit__help-pop {
display: none;
position: absolute;
top: calc(100% + 8px);
right: 0;
z-index: 50;
width: 230px;
padding: 10px 12px;
border: 1px solid var(--fms-border);
border-radius: 8px;
background: var(--fms-card);
box-shadow: 0 6px 20px rgba(30, 45, 64, 0.14);
}
.mm-edit__help-title { .mm-edit__help-title {
margin-bottom: 6px; margin-bottom: 6px;
color: var(--fms-text); color: var(--fms-text);
@@ -2469,20 +2357,20 @@ onBeforeUnmount(() => {
overflow: hidden; overflow: hidden;
} }
/* 折叠后的展开按钮:占满折叠列,图标置于顶部 */ /* 展开属性面板(覆盖 ui Button 默认尺寸) */
.mm-fdesign__panel-expand { .mm-fdesign__panel-expand.button {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
min-height: 0;
padding-top: 10px; padding-top: 10px;
border: none;
background: transparent; background: transparent;
color: color-mix(in srgb, var(--fms-text-secondary) 70%, var(--fms-text)); color: color-mix(in srgb, var(--fms-text-secondary) 70%, var(--fms-text));
cursor: pointer;
&:hover { &:hover:not(:disabled) {
background: transparent;
color: var(--fms-primary); color: var(--fms-primary);
} }
} }
@@ -2522,49 +2410,33 @@ onBeforeUnmount(() => {
line-height: 16px; line-height: 16px;
} }
/* 面板头部折叠按钮 */ /* 折叠属性面板(覆盖 ui Button 默认尺寸) */
.mm-fdesign__collapse { .mm-fdesign__collapse.button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 20px; width: 20px;
height: 20px; height: 20px;
min-height: 0;
padding: 0; padding: 0;
border: none;
border-radius: 4px; border-radius: 4px;
background: transparent; background: transparent;
color: color-mix(in srgb, var(--fms-text-secondary) 70%, var(--fms-text)); color: color-mix(in srgb, var(--fms-text-secondary) 70%, var(--fms-text));
cursor: pointer; transform: none;
transition:
background 0.15s,
color 0.15s;
&:hover { &:hover:not(:disabled) {
background: var(--fms-secondary); background: var(--fms-secondary);
color: var(--fms-text); color: var(--fms-text);
} }
} }
.mm-fdesign__lib-search { /* 搜索框:压缩 ui Input 高度(覆盖默认 --fms-control-height) */
width: 100%; .mm-fdesign__lib-search.input-wrapper {
height: 26px; height: 26px;
min-height: 0;
padding: 0 8px; padding: 0 8px;
border: 1px solid var(--fms-border);
border-radius: 4px;
color: var(--fms-text);
background: var(--fms-card);
font-size: 11px; font-size: 11px;
margin-bottom: 10px; margin-bottom: 10px;
outline: none;
&::placeholder {
color: var(--fms-text-placeholder, #9ca3af);
}
&:focus {
border-color: var(--fms-primary);
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--fms-primary) 25%, transparent);
}
} }
.mm-fdesign__lib-group { .mm-fdesign__lib-group {
@@ -2709,18 +2581,17 @@ onBeforeUnmount(() => {
/* 分组名编辑输入框 + 确认/取消:宽度自适应(填满标题栏剩余空间), /* 分组名编辑输入框 + 确认/取消:宽度自适应(填满标题栏剩余空间),
* 短标题(如"基础")不会撑出大片空白,长标题自动延伸 */ * 短标题(如"基础")不会撑出大片空白,长标题自动延伸 */
.mm-fdesign__section-edit { .mm-fdesign__section-edit.input-wrapper {
flex: 1; flex: 1;
min-width: 80px; min-width: 80px;
height: 24px; height: 24px;
min-height: 0;
padding: 0 6px; padding: 0 6px;
border: 1px solid var(--fms-primary); border: 1px solid var(--fms-primary);
border-radius: 4px; border-radius: 4px;
background: var(--fms-card); background: var(--fms-card);
color: var(--fms-text); color: var(--fms-text);
font-size: 12px; font-size: 12px;
font-family: inherit;
outline: none;
box-shadow: 0 0 0 2px color-mix(in srgb, var(--fms-primary) 12%, transparent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--fms-primary) 12%, transparent);
} }
@@ -2731,25 +2602,25 @@ onBeforeUnmount(() => {
flex: none; flex: none;
} }
.mm-fdesign__section-edit-btn { .mm-fdesign__section-edit-btn.button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 22px; width: 22px;
height: 22px; height: 22px;
min-height: 0;
padding: 0; padding: 0;
border: 1px solid var(--fms-border); border: 1px solid var(--fms-border);
border-radius: 4px; border-radius: 4px;
background: var(--fms-card); background: var(--fms-card);
color: var(--fms-text-secondary); color: var(--fms-text-secondary);
cursor: pointer;
&:hover { &:hover:not(:disabled) {
border-color: var(--fms-primary); border-color: var(--fms-primary);
color: var(--fms-primary); color: var(--fms-primary);
} }
&:last-child:hover { &:last-child:hover:not(:disabled) {
border-color: #d95757; border-color: #d95757;
color: #d95757; color: #d95757;
} }
@@ -2981,30 +2852,30 @@ textarea.mm-fdesign__ctrl {
pointer-events: none; /* 纯预览,点击穿透到卡片 */ pointer-events: none; /* 纯预览,点击穿透到卡片 */
} }
/* 字段删除按钮:与必填/显示图标同款行内小图标,推至最右 */ /* 字段删除按钮:与必填/显示图标同款行内小图标,推至最右(覆盖 ui Button 默认尺寸) */
.mm-fdesign__tool-btn { .mm-fdesign__tool-btn.button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 18px; width: 18px;
height: 18px; height: 18px;
min-height: 0;
margin-left: auto; margin-left: auto;
padding: 0; padding: 0;
border: none; border: none;
border-radius: 4px; border-radius: 4px;
background: color-mix(in srgb, var(--fms-primary) 5%, transparent); background: color-mix(in srgb, var(--fms-primary) 5%, transparent);
color: var(--fms-text-disabled, #9ca3af); color: var(--fms-text-disabled, #9ca3af);
cursor: pointer;
transition: transition:
background 0.15s, background 0.15s,
color 0.15s; color 0.15s;
&:hover { &:hover:not(:disabled) {
background: color-mix(in srgb, var(--fms-primary) 16%, transparent); background: color-mix(in srgb, var(--fms-primary) 16%, transparent);
color: var(--fms-text); color: var(--fms-text);
} }
&.is-danger:hover { &.is-danger:hover:not(:disabled) {
color: #d95757; color: #d95757;
background: color-mix(in srgb, #d95757 12%, transparent); background: color-mix(in srgb, #d95757 12%, transparent);
} }
@@ -3113,37 +2984,32 @@ textarea.mm-fdesign__ctrl {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
} }
}
input[type='number'] { /* 数字输入:压缩 ui Input 高度(覆盖默认 --fms-control-height) */
flex: none; .mm-fdesign__span-input.input-wrapper {
width: 48px; flex: none;
height: 26px; width: 48px;
padding: 0 4px; height: 26px;
border: 1px solid var(--fms-border); min-height: 0;
border-radius: 4px; padding: 0 4px;
background: var(--fms-card); font-size: 11px;
color: var(--fms-text);
font-size: 11px; :deep(.input) {
text-align: center; text-align: center;
outline: none;
&:focus {
border-color: var(--fms-primary);
}
&:disabled {
opacity: 0.5;
}
} }
} }
/* 栅格宽度:去掉下拉后数字输入框即主控件,填充剩余宽度(列宽控件仍用下拉,不受影响) */ /* 栅格宽度:无下拉时数字输入框即主控件,填充剩余宽度(文本域高度仍用下拉,不受影响) */
.mm-fdesign__span-control input#mm-fdesign-colspan { .mm-fdesign__span-control > .mm-fdesign__span-input.input-wrapper {
flex: 1; flex: 1;
width: auto; width: auto;
min-width: 0; min-width: 0;
padding: 0 8px; padding: 0 8px;
text-align: left;
:deep(.input) {
text-align: left;
}
} }
.mm-fdesign__prop-static { .mm-fdesign__prop-static {
@@ -3158,25 +3024,12 @@ textarea.mm-fdesign__ctrl {
font-size: 11px; font-size: 11px;
} }
.mm-fdesign__prop-input { /* 属性面板常规输入:压缩 ui Input 高度 */
width: 100%; .mm-fdesign__prop-input.input-wrapper {
height: 26px; height: 26px;
min-height: 0;
padding: 0 8px; padding: 0 8px;
border: 1px solid var(--fms-border);
border-radius: 4px;
background: var(--fms-card);
color: var(--fms-text);
font-size: 11px; font-size: 11px;
outline: none;
&:focus {
border-color: var(--fms-primary);
box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--fms-primary) 20%, transparent);
}
&:disabled {
opacity: 0.5;
}
} }
.mm-fdesign__toggles { .mm-fdesign__toggles {
@@ -3192,40 +3045,6 @@ textarea.mm-fdesign__ctrl {
font-size: 11px; font-size: 11px;
} }
.mm-fdesign__toggle {
width: 30px;
height: 16px;
padding: 2px;
border: none;
border-radius: 999px;
background: #bdc7d2;
cursor: pointer;
transition: background-color 0.16s ease;
&::after {
content: '';
display: block;
width: 12px;
height: 12px;
border-radius: 50%;
background: #fff;
transition: transform 0.16s ease;
}
&.is-on {
background: var(--fms-primary);
&::after {
transform: translateX(14px);
}
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.mm-fdesign__delete { .mm-fdesign__delete {
margin-top: 10px; margin-top: 10px;
width: 100%; width: 100%;
@@ -3496,25 +3315,25 @@ textarea.mm-fdesign__ctrl {
-webkit-user-select: none; -webkit-user-select: none;
} }
/* ---- 分组设置按钮(齿轮):打开分组设置弹窗 ---- */ /* ---- 分组设置按钮(齿轮):打开分组设置弹窗(覆盖 ui Button 默认尺寸) ---- */
.mm-fdesign__section-btn { .mm-fdesign__section-btn.button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 20px; width: 20px;
height: 20px; height: 20px;
min-height: 0;
padding: 0; padding: 0;
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 4px; border-radius: 4px;
background: transparent; background: transparent;
color: var(--fms-text-placeholder, #9ca3af); color: var(--fms-text-placeholder, #9ca3af);
cursor: pointer;
transition: transition:
background 0.15s, background 0.15s,
color 0.15s, color 0.15s,
border-color 0.15s; border-color 0.15s;
&:hover { &:hover:not(:disabled) {
background: var(--fms-secondary-hover, #f1f5f9); background: var(--fms-secondary-hover, #f1f5f9);
color: var(--fms-text); color: var(--fms-text);
border-color: var(--fms-border); border-color: var(--fms-border);