|
|
@@ -247,28 +247,19 @@
|
|
|
</el-form-item>
|
|
|
<el-form-item label="保护目录" required>
|
|
|
<div class="directory-list">
|
|
|
+ <!-- 单选模式:固定一行,只展示 form.directories[0];接口仍是数组,固定只传一个元素(后端零改动) -->
|
|
|
<el-form-item
|
|
|
- v-for="(item, index) in form.directories"
|
|
|
- :key="index"
|
|
|
- :prop="`directories.${index}.directory`"
|
|
|
+ prop="directories.0.directory"
|
|
|
:rules="{ required: true, message: '请点击下方「选择目录」从服务器选取', trigger: 'blur' }"
|
|
|
>
|
|
|
<div class="directory-row">
|
|
|
<!-- 只读:保护目录仅能通过「选择目录」树选择回填,不允许手动输入 -->
|
|
|
<el-input
|
|
|
- v-model="item.directory"
|
|
|
+ v-model="form.directories[0].directory"
|
|
|
readonly
|
|
|
placeholder="请点击下方「选择目录」从服务器选取"
|
|
|
class="directory-input"
|
|
|
/>
|
|
|
- <el-button
|
|
|
- v-preReClick
|
|
|
- icon="delete"
|
|
|
- link
|
|
|
- type="danger"
|
|
|
- @click="removeDirectory(index)"
|
|
|
- >删除
|
|
|
- </el-button>
|
|
|
</div>
|
|
|
</el-form-item>
|
|
|
<el-button
|
|
|
@@ -294,28 +285,30 @@
|
|
|
<!-- 服务器本地目录懒加载树弹窗(从根目录 / 开始,只列目录) -->
|
|
|
<el-dialog
|
|
|
v-model="localTreeVisible"
|
|
|
- title="选择保护目录(服务器根目录层级,可多选)"
|
|
|
+ title="选择保护目录(服务器根目录层级)"
|
|
|
width="560px"
|
|
|
:before-close="closeLocalTree"
|
|
|
>
|
|
|
- <!-- 刷新:换 key 销毁重建树,从根目录重新懒加载(服务器目录有变更时使用),勾选状态一并重置 -->
|
|
|
+ <!-- 刷新:换 key 销毁重建树,从根目录重新懒加载(服务器目录有变更时使用),选中状态一并重置 -->
|
|
|
<div class="tree-toolbar">
|
|
|
<el-button v-preReClick icon="refresh" size="small" @click="refreshLocalTree"
|
|
|
>刷新整个目录</el-button
|
|
|
>
|
|
|
</div>
|
|
|
<!-- v-if: 关闭弹窗即销毁树,重开时按当前表单 IP/port 重新懒加载,避免 lazy 缓存串机器 -->
|
|
|
+ <!-- node-click:点选目录节点即回填并关闭弹窗,省掉「确定」按钮一步(单选模式的即点即选交互) -->
|
|
|
<el-tree
|
|
|
v-if="localTreeVisible"
|
|
|
:key="localTreeKey"
|
|
|
ref="localTreeRef"
|
|
|
lazy
|
|
|
- show-checkbox
|
|
|
+ highlight-current
|
|
|
node-key="path"
|
|
|
:load="loadLocalDirNode"
|
|
|
:props="{ label: 'name', isLeaf: 'leaf' }"
|
|
|
empty-text="根目录下没有可选目录"
|
|
|
style="max-height: 420px; overflow-y: auto"
|
|
|
+ @node-click="handleDirNodeClick"
|
|
|
>
|
|
|
<template #default="{ data }">
|
|
|
<el-tooltip :content="data.path" placement="top">
|
|
|
@@ -325,8 +318,7 @@
|
|
|
</el-tree>
|
|
|
<template #footer>
|
|
|
<div class="dialog-footer">
|
|
|
- <el-button v-preReClick @click="closeLocalTree">取消</el-button>
|
|
|
- <el-button v-preReClick type="primary" @click="confirmLocalTree">确 定</el-button>
|
|
|
+ <el-button v-preReClick @click="closeLocalTree">取 消</el-button>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
@@ -614,52 +606,16 @@ const loadLocalDirNode = (node, resolve) => {
|
|
|
.catch(() => resolve([])) // 失败降级为空,不卡树
|
|
|
}
|
|
|
|
|
|
-// 确认勾选:取所有「完全勾选」的节点,父子同时勾选时只保留最上层(被父级
|
|
|
-// 级联带勾的后代丢弃,父目录已覆盖子目录),与已有行合并去重。
|
|
|
-// 注意不能用旧写法 getCheckedNodes(true)(只取叶子):懒加载树里勾选一个还没
|
|
|
-// 展开的非叶目录(如 /home)时它不算叶子,会回填为空或只回填它已加载的子孙。
|
|
|
-const confirmLocalTree = () => {
|
|
|
- const tree = localTreeRef.value
|
|
|
- if (!tree) return
|
|
|
- // getCheckedNodes(false, false):返回所有完全勾选的节点(含父节点,不含半选)
|
|
|
- const checked = tree.getCheckedNodes(false, false)
|
|
|
- if (!checked.length) {
|
|
|
- ElMessage({ type: 'warning', message: '请至少勾选一个目录' })
|
|
|
- return
|
|
|
- }
|
|
|
- // 1. normalize(解决尾斜杠/多斜杠)
|
|
|
- const norm = p => p.replace(/\/+/g, '/').replace(/\/$/, '') || '/'
|
|
|
- // 父路径推导:'/a/b' → '/a','/a' → '/'(根)
|
|
|
- const seen = new Set()
|
|
|
- const list = []
|
|
|
- for (const n of checked) {
|
|
|
- if (!n || typeof n.path !== 'string') continue
|
|
|
- const p = norm(n.path)
|
|
|
- if (seen.has(p)) continue
|
|
|
- seen.add(p)
|
|
|
- list.push({ ...n, path: p })
|
|
|
- }
|
|
|
- // 3. 叶子过滤
|
|
|
- const nodes = list.filter(n =>
|
|
|
- !list.some(m =>
|
|
|
- m.path !== n.path &&
|
|
|
- m.path.startsWith(n.path === '/' ? '/' : n.path + '/')
|
|
|
- )
|
|
|
- )
|
|
|
-
|
|
|
- const existing = new Set(
|
|
|
- form.value.directories.map(d => (d.directory || '').trim()).filter(Boolean)
|
|
|
- )
|
|
|
- // 保留已填写的非空行,勾选结果去重后追加
|
|
|
- const merged = form.value.directories.filter(d => (d.directory || '').trim())
|
|
|
- for (const n of nodes) {
|
|
|
- if (!existing.has(n.path)) {
|
|
|
- merged.push({ directory: n.path })
|
|
|
- existing.add(n.path)
|
|
|
- }
|
|
|
- }
|
|
|
- form.value.directories = merged.length ? merged : [{ directory: '' }]
|
|
|
- ElMessage({ type: 'success', message: `已回填 ${nodes.length} 个保护目录` })
|
|
|
+// 点选目录节点即回填并关闭弹窗(单选模式,无「确定」按钮)。
|
|
|
+// node-click 回调的第一个参数就是节点 data({name, path, leaf...}),懒加载树同样适用。
|
|
|
+// 后端接口仍是 directories 数组,前端固定只传一个元素,后端零改动天然兼容。
|
|
|
+const handleDirNodeClick = data => {
|
|
|
+ if (!data || typeof data.path !== 'string') return
|
|
|
+ // normalize(解决尾斜杠/多斜杠):'/a//b/' → '/a/b','/' 根目录保留
|
|
|
+ const p = data.path.replace(/\/+/g, '/').replace(/\/$/, '') || '/'
|
|
|
+ // 固定回填第一行(表单只有这一行)
|
|
|
+ form.value.directories = [{ directory: p }]
|
|
|
+ ElMessage({ type: 'success', message: `已选择保护目录 ${p}` })
|
|
|
closeLocalTree()
|
|
|
}
|
|
|
|
|
|
@@ -762,13 +718,6 @@ const rules = ref({
|
|
|
iden: [{ required: true, message: '请选择接入标识', trigger: 'change' }]
|
|
|
})
|
|
|
|
|
|
-const addDirectory = () => {
|
|
|
- form.value.directories.push({ directory: '' })
|
|
|
-}
|
|
|
-const removeDirectory = index => {
|
|
|
- form.value.directories.splice(index, 1)
|
|
|
-}
|
|
|
-
|
|
|
const openDialog = () => {
|
|
|
type.value = 'create'
|
|
|
form.value = {
|
|
|
@@ -803,10 +752,8 @@ const updateServiceInfo = row => {
|
|
|
brush: row.brush || 0,
|
|
|
// A 方案:记录挂载状态,模板用它置灰密钥下拉框(挂载中禁换密钥)
|
|
|
mountStatus: row.mountStatus,
|
|
|
- directories:
|
|
|
- row.directories && row.directories.length
|
|
|
- ? row.directories.map(d => ({ id: d.id, directory: d.directory }))
|
|
|
- : [{ directory: '' }]
|
|
|
+ // 单选模式:只回显第一个目录(历史多目录数据编辑保存后自然收敛为单个)
|
|
|
+ directories: [{ directory: row.directories?.[0]?.directory || '' }]
|
|
|
}
|
|
|
dialogFormVisible.value = true
|
|
|
// 同 openDialog:清掉上一次弹窗残留的校验红框(编辑已挂载服务时 iden 是禁用回显,更不该带红框)
|
|
|
@@ -825,7 +772,9 @@ const closeDialog = () => {
|
|
|
keyAlgo: 'SM4-CTR',
|
|
|
status: '启用',
|
|
|
brush: 0,
|
|
|
- directories: []
|
|
|
+ // 必须重置为「含一个空行」的数组:模板固定绑定 form.directories[0].directory,
|
|
|
+ // 且 el-dialog 关闭不销毁内容,重置成空数组会让下一次渲染读 undefined.directory 直接报错
|
|
|
+ directories: [{ directory: '' }]
|
|
|
}
|
|
|
}
|
|
|
|