From 60cacfa8fbb7d0066561a076316370061ae39ebe Mon Sep 17 00:00:00 2001 From: oneao Date: Wed, 26 Aug 2026 22:44:45 +0800 Subject: [PATCH] 20260826224445 --- code/fms/fms-vue/.gitignore | 1 + .../fms-vue/src/components/ui/modal/modal.vue | 11 +- .../fms-vue/src/components/ui/tree/index.scss | 25 +- .../components/FieldGroupManager.vue | 471 --- .../components/IconSelect.vue | 2 +- ...onfigPanel.vue => ModuleFormEditPanel.vue} | 1846 ++------- .../components/ModuleListConfigPanel.vue | 15 +- .../components/ModuleTableEditPanel.vue | 3325 +++++++++++++++++ .../views/system/module-management/index.vue | 78 +- 9 files changed, 3650 insertions(+), 2124 deletions(-) delete mode 100644 code/fms/fms-vue/src/views/system/module-management/components/FieldGroupManager.vue rename code/fms/fms-vue/src/views/system/module-management/components/{ModuleEditConfigPanel.vue => ModuleFormEditPanel.vue} (66%) create mode 100644 code/fms/fms-vue/src/views/system/module-management/components/ModuleTableEditPanel.vue diff --git a/code/fms/fms-vue/.gitignore b/code/fms/fms-vue/.gitignore index 945398ba..af57496b 100644 --- a/code/fms/fms-vue/.gitignore +++ b/code/fms/fms-vue/.gitignore @@ -13,6 +13,7 @@ dist-ssr dist-verify dist-check dist-check2 +dist-check3 *.local # Editor directories and files diff --git a/code/fms/fms-vue/src/components/ui/modal/modal.vue b/code/fms/fms-vue/src/components/ui/modal/modal.vue index d3e244bf..adfc44fc 100644 --- a/code/fms/fms-vue/src/components/ui/modal/modal.vue +++ b/code/fms/fms-vue/src/components/ui/modal/modal.vue @@ -108,9 +108,15 @@ function toggleFullscreen() { } // 遮罩点击关闭:wrap 铺满视口且层级高于 mask,事件实际落在 wrap 上; -// 只响应点击 wrap 自身(面板外空白/遮罩区域),点击面板内部不关闭 +// 只响应点击 wrap 自身(面板外空白/遮罩区域),点击面板内部不关闭。 +// 记录 mousedown 是否发生在面板内:若在面板内按下(如拖选输入框文本)后 +// 拖出到遮罩再松开,click.target 会回溯为共同祖先 wrap,此时不应误判为点击遮罩。 +let maskDownInPanel = false +function onWrapMouseDown(event) { + maskDownInPanel = !!panelRef.value?.contains(event.target) +} function onWrapClick(event) { - if (event.target === event.currentTarget && props.maskClosable) { + if (event.target === event.currentTarget && props.maskClosable && !maskDownInPanel) { requestClose() } } @@ -208,6 +214,7 @@ onBeforeUnmount(() => { v-if="isOpen" class="fms-modal-wrap" :class="{ 'fms-modal-centered': centered }" + @mousedown="onWrapMouseDown" @click="onWrapClick" >
-/** - * 字段分组管理弹窗:管理 s_field_group 树形分组。 - * 简化交互:顶部输入框回车即新增(选中节点则挂到其下,未选中为顶级), - * 树节点行内直接 启用 / 重命名 / 删除,无需右侧属性面板。 - * 独立保存到后端,保存后 emit("saved", groups, idMapping),父级用 idMapping - * 重映射列表/编辑配置中的 b_group_id(临时 ID → 雪花 ID)。 - */ -import { computed, nextTick, ref, watch } from 'vue' -import Message from '@/components/ui/message/message-manager' -import Modal from '@/components/ui/modal/modal.vue' -import Button from '@/components/ui/button/button.vue' -import Switch from '@/components/ui/switch/switch.vue' -import Tree from '@/components/ui/tree/tree.vue' -import { Plus, Pencil, Trash2, ArrowUp, ArrowDown } from '@lucide/vue' -import { buildTree } from '@/utils/tree' -import { createTempId } from '@/utils/tempId' -import { cloneData, diffRows, allocateTemporaryIds, tableChange, hasChanges } from '@/utils/dataChanges' -import { saveObjectApi } from '@/services/api' - -const props = defineProps({ - open: { type: Boolean, default: false }, - moduleId: { type: String, required: true }, - groups: { type: Array, default: () => [] }, - referencedGroupIds: { type: Array, default: () => [] }, -}) - -const emit = defineEmits(['update:open', 'saved']) - -const localGroups = ref([]) -const selectedGroupId = ref(null) -const saving = ref(false) - -/* 顶部输入即新增 */ -const newTitle = ref('') -const addInputRef = ref(null) - -/* 行内重命名 */ -const editingId = ref(null) -const renameValue = ref('') -const renameInputRef = ref(null) - -watch( - () => props.groups, - (val) => { - localGroups.value = cloneData(val || []) - }, - { immediate: true }, -) - -const treeData = computed(() => buildTree(localGroups.value)) -const selectedGroup = computed(() => - localGroups.value.find((g) => String(g.b_id) === String(selectedGroupId.value)), -) - -function onTreeSelect(keys) { - selectedGroupId.value = keys.length ? String(keys[0]) : null -} - -/* 新增:输入名称回车即添加;选中节点时挂到其下,否则为顶级。 - 新增后不自动选中新节点,便于连续新增到同一父级下。 */ -function handleAdd() { - const title = newTitle.value.trim() - if (!title) return - localGroups.value.push({ - b_id: createTempId(), - b_module_id: props.moduleId, - b_parent_id: selectedGroupId.value || null, - b_title: title, - b_xh: (localGroups.value.length + 1) * 10, - b_canuse: 1, - b_layout_direction: 'vertical', - }) - newTitle.value = '' - nextTick(() => addInputRef.value?.focus?.()) -} - -function onAddEnter(event) { - if (event.isComposing) return - handleAdd() -} - -/* 行内重命名 */ -function startRename(node) { - editingId.value = String(node.b_id) - renameValue.value = node.b_title || '' - nextTick(() => renameInputRef.value?.focus?.()) -} - -function commitRename(node) { - if (editingId.value !== String(node.b_id)) return - const title = renameValue.value.trim() - if (title) node.b_title = title - editingId.value = null -} - -function cancelRename() { - editingId.value = null -} - -function onRenameEnter(event, node) { - if (event.isComposing) return - commitRename(node) -} - -/* 行内启用切换 */ -function toggleEnable(node) { - node.b_canuse = Number(node.b_canuse) === 1 ? 0 : 1 -} - -function toggleLayout(node) { - node.b_layout_direction = node.b_layout_direction === 'horizontal' ? 'vertical' : 'horizontal' -} - -/* 同级排序:上移/下移(交换同级顺序并重新编号 b_xh,随保存提交) */ -function moveGroup(node, delta) { - if (!node) return - const parentId = node.b_parent_id == null ? null : String(node.b_parent_id) - const siblings = localGroups.value.filter( - (g) => (g.b_parent_id == null ? null : String(g.b_parent_id)) === parentId, - ) - siblings.sort((a, b) => (a.b_xh || 0) - (b.b_xh || 0)) - const idx = siblings.findIndex((g) => String(g.b_id) === String(node.b_id)) - const target = idx + delta - if (idx < 0 || target < 0 || target >= siblings.length) return - const [moved] = siblings.splice(idx, 1) - siblings.splice(target, 0, moved) - siblings.forEach((g, i) => { - g.b_xh = (i + 1) * 10 - }) -} - -/* 删除:有子分组 / 仍被引用时禁止 */ -function deleteGroup(node) { - if (!node) return - const id = String(node.b_id) - const hasChildren = localGroups.value.some( - (g) => String(g.b_parent_id) === id && String(g.b_id) !== id, - ) - if (hasChildren) { - Message.warning('该分组下还有子分组,请先删除子分组') - return - } - if (props.referencedGroupIds.some((gid) => String(gid) === id)) { - Message.warning('该分组仍被列表或编辑配置引用,请先清空引用') - return - } - localGroups.value = localGroups.value.filter((g) => String(g.b_id) !== id) - if (String(selectedGroupId.value) === id) selectedGroupId.value = null -} - -async function save() { - if (saving.value) return - const changes = diffRows(localGroups.value, cloneData(props.groups || [])) - const req = tableChange('s_field_group', changes) - if (!hasChanges(req)) { - Message.info('没有需要保存的变更') - emit('update:open', false) - emit('saved', localGroups.value, new Map()) - return - } - saving.value = true - try { - const mapping = await allocateTemporaryIds([req.inserts || [], req.updates || []]) - await saveObjectApi([req]) - Message.success('分组已保存') - emit('update:open', false) - emit('saved', localGroups.value, mapping) - } catch (err) { - Message.error('保存失败:' + (err?.message || err)) - } finally { - saving.value = false - } -} - - - - - diff --git a/code/fms/fms-vue/src/views/system/module-management/components/IconSelect.vue b/code/fms/fms-vue/src/views/system/module-management/components/IconSelect.vue index 9b0e130f..e0c089da 100644 --- a/code/fms/fms-vue/src/views/system/module-management/components/IconSelect.vue +++ b/code/fms/fms-vue/src/views/system/module-management/components/IconSelect.vue @@ -23,7 +23,7 @@ const ICON_NAMES = [ 'CalendarDays', 'CalendarClock', 'Clock', 'Timer', 'History', 'AlarmClock', 'Search', 'Filter', 'Eye', 'EyeOff', 'Lock', 'Unlock', 'Key', 'KeyRound', 'Plus', 'Minus', 'Pencil', 'Trash2', 'Copy', 'Save', 'Upload', 'Download', - 'RefreshCw', 'RotateCw', 'Undo2', 'Redo2', 'ExternalLink', 'Link', 'Share2', + 'RefreshCw', 'RotateCw', 'ExternalLink', 'Link', 'Share2', 'Printer', 'Mail', 'Phone', 'MapPin', 'Globe', 'Globe2', 'Languages', 'Translate', 'BookOpen', 'BookMarked', 'GraduationCap', 'Award', 'Star', 'Heart', 'Flag', 'Check', 'CheckCircle2', 'XCircle', 'AlertCircle', 'AlertTriangle', 'Info', diff --git a/code/fms/fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue b/code/fms/fms-vue/src/views/system/module-management/components/ModuleFormEditPanel.vue similarity index 66% rename from code/fms/fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue rename to code/fms/fms-vue/src/views/system/module-management/components/ModuleFormEditPanel.vue index 66c9b448..200e24ec 100644 --- a/code/fms/fms-vue/src/views/system/module-management/components/ModuleEditConfigPanel.vue +++ b/code/fms/fms-vue/src/views/system/module-management/components/ModuleFormEditPanel.vue @@ -1,6 +1,6 @@ @@ -1728,46 +1399,43 @@ onBeforeUnmount(() => { placeholder="搜索字段名 / 编码" />
- + +
无匹配字段
@@ -1779,7 +1447,7 @@ onBeforeUnmount(() => {
- - - - 已移除「{{ fieldName(lastDeleted.row) }}」 - - - -
@@ -1859,8 +1500,6 @@ onBeforeUnmount(() => {
  • Ctrl+C 复制选中字段属性
  • Ctrl+X 剪切(复制并删除当前字段)
  • Ctrl+V 粘贴属性到选中字段
  • -
  • Ctrl+Z 撤销
  • -
  • Ctrl+Shift+Z / Ctrl+Y 重做
  • Delete 删除选中字段
  • @@ -1868,344 +1507,41 @@ onBeforeUnmount(() => {
    - -
    -
    -
    - -
    - 从左侧字段拖入,或在分组内拖拽调整顺序 - -
    - -
    暂无内容
    -
    -
    - - -
    -
    - - - - -
    -
    -
    -
    - - -
    -
    暂无子表列
    -
    - -
    - # - - - {{ g.title }} - - - 操作 -
    - -
    - # - - - {{ fieldName(row) }} - * - {{ widthOf(row) }} - - - - 操作 -
    -
    - 1 - - - {{ sampleText(row) }} - - - - 编辑 - -
    -
    -
    -
    -
    - -
    +
    @@ -2879,7 +2060,7 @@ onBeforeUnmount(() => { border-bottom: 1px solid var(--fms-border); } -/* 视图切换不再 absolute 定位:左/右两翼 flex 伸缩挤出中间位 */ +/* 视图切换:左/右两翼 flex 伸缩挤出中间位,保证居中 */ .mm-edit__head-center { flex: none; display: inline-flex; @@ -2940,35 +2121,6 @@ onBeforeUnmount(() => { } } -/* 头部撤销 / 重做图标按钮 */ -.mm-edit__hist-btn { - display: inline-flex; - align-items: center; - justify-content: center; - width: 28px; - height: 28px; - padding: 0; - border: 1px solid var(--fms-border); - border-radius: var(--fms-control-radius); - background: var(--fms-card); - color: var(--fms-text-secondary); - cursor: pointer; - transition: - border-color 150ms ease, - background 150ms ease, - color 150ms ease; - - &:hover:not(:disabled) { - border-color: color-mix(in srgb, var(--fms-primary) 45%, transparent); - color: var(--fms-primary); - } - - &:disabled { - opacity: 0.4; - cursor: not-allowed; - } -} - .mm-edit__view-switch { display: inline-flex; align-items: center; @@ -3087,63 +2239,6 @@ onBeforeUnmount(() => { } } -/* ---- 撤销提示条(删除字段后临时出现,弱化为次级提示,避免抢眼) ---- */ -.mm-edit__undo-wrap { - position: relative; - display: inline-flex; - align-items: center; - gap: 6px; - padding: 3px 10px; - border-radius: 999px; - border: 1px dashed var(--fms-border); - background: var(--fms-card); - font-size: 11px; - overflow: hidden; /* 裁剪倒计时进度条 */ -} - -/* 底部倒计时进度条:与 8 秒自动消失同步收缩,提示撤销窗口剩余时间 */ -.mm-edit__undo-bar { - position: absolute; - left: 0; - bottom: 0; - width: 100%; - height: 2px; - background: var(--fms-primary); - opacity: 0.45; - transform-origin: left; - animation: mm-edit-undo-bar 8s linear forwards; -} - -@keyframes mm-edit-undo-bar { - from { - transform: scaleX(1); - } - to { - transform: scaleX(0); - } -} - -.mm-edit__undo-text { - color: var(--fms-text-secondary); -} - -.mm-edit__undo { - display: inline-flex; - align-items: center; - gap: 3px; - padding: 1px 8px; - border: 1px solid var(--fms-border); - border-radius: 999px; - background: var(--fms-card); - color: var(--fms-primary); - font-size: 11px; - cursor: pointer; - - &:hover { - background: color-mix(in srgb, var(--fms-primary) 6%, transparent); - } -} - /* ---- 设计视图:工作区模型(三栏统一灰底,白色表单纸面居中浮起) ---- */ .mm-fdesign { display: grid; @@ -3384,9 +2479,8 @@ onBeforeUnmount(() => { min-height: 120px; } -/* ---- 分组卡片(主表 / 子表统一,参考 demo.html 分组样式) ---- */ -.mm-fdesign__section, -.mm-tdesign__section { +/* ---- 分组卡片(主表表单设计,参考 demo.html 分组样式) ---- */ +.mm-fdesign__section { margin-top: 12px; border: 1px solid var(--fms-border); border-radius: 8px; @@ -3413,21 +2507,8 @@ onBeforeUnmount(() => { } } -/* 分组停用标记 */ -.mm-fdesign__section-off { - padding: 0 6px; - border: 1px solid color-mix(in srgb, var(--fms-danger, #d95757) 30%, transparent); - border-radius: 999px; - background: color-mix(in srgb, var(--fms-danger, #d95757) 8%, var(--fms-card)); - color: var(--fms-danger, #d95757); - font-size: 10px; - font-style: normal; - line-height: 16px; -} - -/* 分组标题行(主表 / 子表统一):白底 header 条,与卡片圆角裁剪 */ -.mm-fdesign__section-title, -.mm-tdesign__section-title { +/* 分组标题行(主表表单设计):白底 header 条,与卡片圆角裁剪 */ +.mm-fdesign__section-title { display: flex; align-items: center; gap: 8px; @@ -3447,15 +2528,6 @@ onBeforeUnmount(() => { white-space: nowrap; } -/* 未分组伪分区名称 */ -.mm-tdesign__section-flag { - flex: 1; - min-width: 0; - font-style: normal; - color: var(--fms-text-secondary); - font-size: 11px; -} - /* 分组名内联编辑:悬停提示可点击重命名 */ .mm-fdesign__section-name.is-editable { cursor: text; @@ -3810,10 +2882,7 @@ textarea.mm-fdesign__ctrl { .mm-fdesign__field:hover .mm-fdesign__invisible-mark, .mm-fdesign__field.is-selected .mm-fdesign__invisible-mark, -.mm-fdesign__field.is-invisible .mm-fdesign__invisible-mark, -.mm-tdesign__col:hover .mm-fdesign__invisible-mark, -.mm-tdesign__col.is-selected .mm-fdesign__invisible-mark, -.mm-tdesign__col.is-invisible .mm-fdesign__invisible-mark { +.mm-fdesign__field.is-invisible .mm-fdesign__invisible-mark { opacity: 1; } @@ -4055,28 +3124,14 @@ textarea.mm-fdesign__ctrl { flex: 1; } -/* ---- 字段库:类型分组小标题 ---- */ -.mm-fdesign__lib-subtitle { - margin: 10px 0 4px; - color: var(--fms-text); - font-size: 12px; - font-weight: 700; - letter-spacing: 0.02em; - /* 前竖线:与 lib-title 统一左对齐 */ - border-left: 3px solid var(--fms-primary); - padding-left: 8px; - - &:first-child { - margin-top: 0; - } -} - /* ---- 分组标题行:右侧操作(字段/列计数 + 停用标记 + 删除),主表/子表统一 ---- */ .mm-edit__section-meta { display: inline-flex; align-items: center; gap: 6px; flex: none; + /* 无标题分组时标题名不渲染,meta 仍靠右 */ + margin-left: auto; margin-left: auto; } @@ -4087,7 +3142,7 @@ textarea.mm-fdesign__ctrl { font-variant-numeric: tabular-nums; } -/* 画布分组删除按钮(标题行右侧):默认隐藏,分组 hover 时浮现,降低视觉噪音 */ +/* 画布分组删除按钮(标题行右侧):图标常驻显示 */ .mm-fdesign__section-del { display: inline-flex; align-items: center; @@ -4100,17 +3155,11 @@ textarea.mm-fdesign__ctrl { background: transparent; color: var(--fms-text-placeholder, #9ca3af); cursor: pointer; - opacity: 0; transition: - opacity 0.15s, background 0.15s, color 0.15s, border-color 0.15s; - .mm-fdesign__section:hover & { - opacity: 1; - } - &:hover { background: color-mix(in srgb, var(--fms-danger, #d95757) 10%, var(--fms-card)); color: var(--fms-danger, #d95757); @@ -4118,6 +3167,70 @@ textarea.mm-fdesign__ctrl { } } +/* 分组标题行编辑按钮(✏ 修改标题):图标常驻显示 */ +.mm-fdesign__section-btn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + padding: 0; + border: 1px solid transparent; + border-radius: var(--fms-control-radius, 5px); + background: transparent; + color: var(--fms-text-placeholder, #9ca3af); + cursor: pointer; + transition: + background 0.15s, + color 0.15s, + border-color 0.15s; + + &:hover { + background: var(--fms-secondary-hover, #f1f5f9); + color: var(--fms-text); + border-color: var(--fms-border); + } +} + +/* 分组标题为空时的占位:灰色「空」,点击可设置标题 */ +.mm-fdesign__section-name.is-empty { + color: var(--fms-text-placeholder, #9ca3af); + cursor: text; +} + +/* 分组拖拽手柄(标题行左侧):拖动调整分组顺序 */ +.mm-fdesign__section-grip { + display: inline-flex; + align-items: center; + justify-content: center; + flex: none; + width: 22px; + height: 22px; + padding: 0; + border: 1px solid transparent; + border-radius: var(--fms-control-radius, 5px); + background: transparent; + color: var(--fms-text-placeholder, #9ca3af); + cursor: grab; + transition: + background 0.15s, + color 0.15s; + + &:hover { + background: var(--fms-secondary-hover, #f1f5f9); + color: var(--fms-text); + } + + &:active { + cursor: grabbing; + } +} + +/* 分组卡片拖拽占位 */ +.mm-fdesign__section-ghost { + opacity: 0.4; +} + /* 分组级左右布局:标题在左(竖排),字段画布在右;仅影响单个分组 */ .mm-fdesign__section.is-horizontal { display: flex; @@ -4166,9 +3279,7 @@ textarea.mm-fdesign__ctrl { } .mm-fdesign__field:hover .mm-fdesign__label-chips, -.mm-fdesign__field.is-selected .mm-fdesign__label-chips, -.mm-tdesign__col:hover .mm-fdesign__label-chips, -.mm-tdesign__col.is-selected .mm-fdesign__label-chips { +.mm-fdesign__field.is-selected .mm-fdesign__label-chips { opacity: 1; } @@ -4223,459 +3334,6 @@ textarea.mm-fdesign__ctrl { } } -/* ---- 表格(子表)设计:列画布(透明,白色分组卡片直接浮于灰底) ---- */ -.mm-tdesign__sheet { - display: flex; - flex-direction: column; - gap: 12px; -} - -/* WYSIWYG 表格:横向滚动 + 冻结序号/操作列 */ -.mm-tdesign__table { - overflow: auto; - max-height: 240px; - border: 1px solid var(--fms-border); - border-radius: 6px; - background: var(--fms-card); - - &.is-resizing { - user-select: none; - } -} - -.mm-tdesign__row { - display: flex; - align-items: center; - min-width: max-content; - border-bottom: 1px solid var(--fms-border); - - &:last-child { - border-bottom: none; - } -} - -.mm-tdesign__head-row { - background: var(--fms-secondary); -} - -/* 预览第一级表头:分组格(跨列合并 = 组内列宽之和) */ -.mm-tdesign__group-cell { - flex: none; - display: inline-flex; - align-items: center; - justify-content: center; - height: 30px; - padding: 0 8px; - border-right: 1px solid var(--fms-border); - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: var(--fms-text); - font-size: 12px; - font-weight: 600; - user-select: none; - - &.is-unnamed { - color: var(--fms-text-secondary); - font-weight: 400; - } -} - -.mm-tdesign__cols { - display: flex; - align-items: center; - min-width: max-content; -} - -/* 冻结列(横向滚动时保持固定) */ -.mm-tdesign__frozen { - flex: none; - position: sticky; - z-index: 6; - display: inline-flex; - align-items: center; - justify-content: center; - height: 100%; - font-size: 11px; - color: var(--fms-text-secondary); -} - -.mm-tdesign__head-row .mm-tdesign__frozen { - background: var(--fms-secondary); -} - -.mm-tdesign__row:not(.mm-tdesign__head-row) .mm-tdesign__frozen { - background: var(--fms-card); -} - -.mm-tdesign__frozen-left { - left: 0; - width: 44px; - min-width: 44px; - padding: 0 6px; - border-right: 1px solid var(--fms-border); -} - -.mm-tdesign__frozen-right { - right: 0; - min-width: 56px; - padding: 0 8px; - border-left: 1px solid var(--fms-border); -} - -/* 表头单元格 */ -.mm-tdesign__head-cell { - position: relative; - flex: none; - display: inline-flex; - align-items: center; - gap: 4px; - height: 34px; - padding: 0 6px; - border-right: 1px solid var(--fms-border); - font-size: 12px; - font-weight: 600; - color: var(--fms-text); - white-space: nowrap; - overflow: hidden; - cursor: pointer; - user-select: none; - transition: background 0.15s; - - &:hover { - background: color-mix(in srgb, var(--fms-primary) 6%, transparent); - } - - &.is-selected { - background: color-mix(in srgb, var(--fms-primary) 12%, transparent); - box-shadow: inset 0 -2px 0 var(--fms-primary); - } - - &.is-hidden { - opacity: 0.45; - } - - &.is-resizing-col { - background: color-mix(in srgb, var(--fms-primary) 10%, transparent); - } -} - -.mm-tdesign__head-name { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.mm-tdesign__head-width { - flex: none; - color: var(--fms-text-secondary); - font-size: 10px; - font-weight: 400; - font-variant-numeric: tabular-nums; - opacity: 0.9; -} - -/* 列宽拖拽手柄:悬停在列右缘,按下后左右拖拽实时调整 b_width */ -.mm-tdesign__resize-handle { - position: absolute; - top: 0; - right: -3px; - z-index: 3; - width: 9px; - height: 100%; - cursor: col-resize; - touch-action: none; -} - -.mm-tdesign__resize-handle::after { - content: ''; - position: absolute; - top: 25%; - right: 4px; - width: 1px; - height: 50%; - background: transparent; - transition: background 0.15s ease; -} - -.mm-tdesign__resize-handle:hover::after, -.mm-tdesign__resize-handle:focus-visible::after, -.mm-tdesign__head-cell.is-resizing-col .mm-tdesign__resize-handle::after { - background: var(--fms-primary); -} - -.mm-tdesign__resize-handle:focus-visible { - outline: 2px solid color-mix(in srgb, var(--fms-primary) 55%, transparent); - outline-offset: -2px; - border-radius: 4px; -} - -.mm-tdesign__row-op { - padding: 2px 10px; - border-radius: 4px; - background: color-mix(in srgb, var(--fms-primary) 10%, transparent); - color: var(--fms-primary); - font-size: 11px; - white-space: nowrap; -} - -/* 预览弹窗内容 */ -.mm-tdesign__preview-wrap { - padding: 8px 0; - min-height: 120px; - - .mm-tdesign__table { - max-height: 60vh; - } -} - -/* 预览表格:数据单元格与样例控件外观 */ -.mm-tdesign__cell { - flex: none; - display: inline-flex; - align-items: center; - height: 40px; - padding: 4px 10px; - border-right: 1px solid var(--fms-border); - overflow: hidden; - - &.is-hidden { - opacity: 0.4; - text-decoration: line-through; - } -} - -.mm-tdesign__sample { - display: inline-flex; - align-items: center; - width: 100%; - height: 24px; - padding: 0 8px; - border: 1px solid var(--fms-border); - border-radius: 4px; - background: var(--fms-secondary-hover); - color: var(--fms-text-secondary); - font-size: 12px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-variant-numeric: tabular-nums; - - &.is-select { - position: relative; - padding-right: 22px; - - &::after { - content: ''; - position: absolute; - right: 9px; - top: 50%; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--fms-text-secondary); - transform: translateY(-45%); - } - } - - &.is-money { - justify-content: flex-end; - font-weight: 600; - color: var(--fms-text); - } - - &.is-checkbox { - border: none; - background: transparent; - color: var(--fms-primary); - font-size: 13px; - } - - &.is-textarea { - height: 34px; - align-items: flex-start; - padding-top: 6px; - } - - &.is-desc { - border: 1px dashed var(--fms-border-strong, #c8d2dc); - background: transparent; - font-style: italic; - } -} - -.mm-tdesign__row-op { - padding: 2px 10px; - border-radius: 4px; - background: color-mix(in srgb, var(--fms-primary) 10%, transparent); - color: var(--fms-primary); - font-size: 11px; - white-space: nowrap; -} - -/* 列清单提示行 */ -.mm-tdesign__list-head { - display: flex; - align-items: center; - gap: 8px; - margin-top: 2px; - padding: 0 2px; -} - -.mm-tdesign__list-head-hint { - flex: 1; - min-width: 0; - color: var(--fms-text-placeholder, #9ca3af); - font-size: 11px; -} - -/* 子表预览入口:打开真实表格效果弹窗(弹窗内可拖拽列宽) */ -.mm-tdesign__preview-btn { - display: inline-flex; - align-items: center; - gap: 4px; - flex: none; - height: 24px; - padding: 0 10px; - border: 1px solid var(--fms-border); - border-radius: var(--fms-control-radius, 5px); - background: var(--fms-card); - color: var(--fms-text-secondary); - font-size: 12px; - cursor: pointer; - transition: - background 0.15s, - color 0.15s, - border-color 0.15s; - - &:hover:not(:disabled) { - border-color: var(--fms-primary); - color: var(--fms-primary); - } - - &:disabled { - opacity: 0.5; - cursor: not-allowed; - } -} - -.mm-tdesign__col { - display: flex; - align-items: center; - gap: 8px; - min-height: 38px; - padding: 4px 8px; - border: 1px solid transparent; /* 默认不显示边框线 */ - border-radius: 6px; - background: var(--fms-card); - cursor: grab; - user-select: none; - -webkit-user-select: none; - transition: - border-color 0.15s, - box-shadow 0.15s; - - &:hover { - border-color: color-mix(in srgb, var(--fms-primary) 35%, transparent); - } - - &.is-selected { - border-style: dashed; - border-color: var(--fms-primary); - box-shadow: none; - } - - &.is-invisible { - opacity: 0.55; - } - - .mm-fdesign__field-name { - flex: 0 1 auto; - } -} - -/* 拖拽手柄:默认隐藏,hover / 选中时浮现;整卡本身可拖拽(cursor 提示保留在卡片上) */ -.mm-tdesign__drag-handle { - flex: none; - display: inline-flex; - align-items: center; - justify-content: center; - width: 20px; - height: 20px; - color: var(--fms-text-secondary); - cursor: grab; - opacity: 0; - transition: opacity 0.15s; -} - -.mm-tdesign__col { - cursor: grab; -} - -.mm-tdesign__col:hover .mm-tdesign__drag-handle, -.mm-tdesign__col.is-selected .mm-tdesign__drag-handle { - opacity: 0.7; -} - -.mm-tdesign__col-meta { - display: inline-flex; - align-items: center; - gap: 6px; - margin-left: auto; - flex: none; -} - -.mm-tdesign__col-type { - padding: 0 6px; - border-radius: 4px; - background: var(--fms-secondary); - color: color-mix(in srgb, var(--fms-text-secondary) 65%, var(--fms-text)); - font-size: 10px; - line-height: 16px; -} - -.mm-tdesign__col-width { - color: color-mix(in srgb, var(--fms-text-secondary) 70%, var(--fms-text)); - font-size: 11px; - font-variant-numeric: tabular-nums; -} - -.mm-tdesign__col-del { - flex: none; - display: inline-flex; - align-items: center; - justify-content: center; - width: 24px; - height: 24px; - padding: 0; - border: none; - border-radius: 5px; - background: transparent; - color: var(--fms-text-disabled, #9ca3af); - cursor: pointer; - opacity: 0; - transition: opacity 0.15s; - - &:hover { - background: #fdecec; - color: #d95757; - } -} - -.mm-tdesign__col:hover .mm-tdesign__col-del, -.mm-tdesign__col.is-selected .mm-tdesign__col-del { - opacity: 1; -} - -.mm-tdesign__empty { - display: flex; - align-items: center; - justify-content: center; - min-height: 56px; - color: var(--fms-text-secondary); - font-size: 11px; -} +
    + + + +
    +
    +
    +
    + + +
    +
    +
    +
    + + +
    +
    +
    + +
    + +
    +
    快捷键
    +
      +
    • Ctrl+C 复制选中字段属性
    • +
    • Ctrl+X 剪切(复制并删除当前字段)
    • +
    • Ctrl+V 粘贴属性到选中字段
    • +
    • Delete 删除选中字段
    • +
    +
    +
    +
    +
    + + +
    +
    +
    + + +
    暂无内容
    + +