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
- }
-}
-
-
-
- emit('update:open', v)"
- @ok="save"
- >
-
-
-
分组结构
-
共 {{ localGroups.length }} 个分组
-
-
-
(newTitle = e.target.value)"
- @keydown.enter="onAddEnter"
- @keydown.esc="newTitle = ''"
- />
-
-
-
- {{ selectedGroup ? `将添加到「${selectedGroup.b_title || '未命名分组'}」下` : '将添加为顶级分组' }}
-
-
-
-
-
-
-
-
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="搜索字段名 / 编码"
/>
-
- {{ group.label }}
-
-
-
-
-
无匹配字段
+
+
+
+
无匹配字段
@@ -1779,7 +1447,7 @@ onBeforeUnmount(() => {
{
{
data-view="data"
@click="switchView('data')"
>
- 预览
+ 数据