|
|
@@ -252,40 +252,6 @@
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
- <!-- 自动检测目录树弹窗 -->
|
|
|
- <el-dialog
|
|
|
- v-model="scanTreeVisible"
|
|
|
- title="自动检测到的目录(可多选)"
|
|
|
- width="640px"
|
|
|
- :before-close="closeScanTree"
|
|
|
- >
|
|
|
- <el-tree
|
|
|
- v-if="scanTreeData.length"
|
|
|
- ref="scanTreeRef"
|
|
|
- :data="scanTreeData"
|
|
|
- show-checkbox
|
|
|
- node-key="localMount"
|
|
|
- default-expand-all
|
|
|
- :props="{ label: 'name', children: 'children' }"
|
|
|
- empty-text="该 SMB 共享根目录下没有可保护的子目录"
|
|
|
- >
|
|
|
- <template #default="{ node, data }">
|
|
|
- <el-tooltip
|
|
|
- :content="`SMB: ${data.smbPath}\n本地挂载点: ${data.localMount}`"
|
|
|
- placement="top"
|
|
|
- >
|
|
|
- <span class="directory-text">{{ data.name }}</span>
|
|
|
- </el-tooltip>
|
|
|
- </template>
|
|
|
- </el-tree>
|
|
|
- <div v-else class="scan-empty">该 SMB 共享根目录下没有可保护的子目录</div>
|
|
|
- <template #footer>
|
|
|
- <div class="dialog-footer">
|
|
|
- <el-button v-preReClick @click="closeScanTree">取消</el-button>
|
|
|
- <el-button v-preReClick type="primary" @click="confirmScanTree">确 定</el-button>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </el-dialog>
|
|
|
|
|
|
<!-- 服务器本地目录懒加载树弹窗(从根目录 / 开始,只列目录) -->
|
|
|
<el-dialog
|
|
|
@@ -330,7 +296,6 @@ import {
|
|
|
getAllDirectories,
|
|
|
createDirectory,
|
|
|
deleteDirectory,
|
|
|
- scanDirectories,
|
|
|
brushService,
|
|
|
getDirChildren
|
|
|
} from '@/api/ude'
|
|
|
@@ -474,67 +439,6 @@ const form = ref({
|
|
|
const ipv4Regex =
|
|
|
/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/
|
|
|
|
|
|
-// ---------- SMB 自动检测 ----------
|
|
|
-const scanLoading = ref(false)
|
|
|
-const scanTreeVisible = ref(false)
|
|
|
-const scanTreeData = ref([]) // DirectoryNode[]
|
|
|
-const scanTreeRef = ref(null)
|
|
|
-let scanTimer = null
|
|
|
-
|
|
|
-// 防抖触发:用户输入 IP / Port / Share 都可能触发,任一变化都重置定时器
|
|
|
-const triggerScan = async (force = false) => {
|
|
|
- const ip = (form.value.ip || '').trim()
|
|
|
- const port = (form.value.port || '').trim()
|
|
|
- if (!ipv4Regex.test(ip) || !/^\d{1,5}$/.test(port)) return
|
|
|
- if (force) {
|
|
|
- if (scanTimer) { clearTimeout(scanTimer); scanTimer = null }
|
|
|
- } else {
|
|
|
- if (scanTimer) clearTimeout(scanTimer)
|
|
|
- }
|
|
|
- return new Promise(resolve => {
|
|
|
- scanTimer = setTimeout(async () => {
|
|
|
- scanTimer = null
|
|
|
- scanLoading.value = true
|
|
|
- try {
|
|
|
- const res = await scanDirectories({
|
|
|
- ip,
|
|
|
- port
|
|
|
- })
|
|
|
- scanTreeData.value = res?.roots || []
|
|
|
- if (scanTreeData.value.length === 0) {
|
|
|
- ElMessage({ type: 'info', message: '未发现任何子目录,请检查 SMB 共享或手动添加' })
|
|
|
- } else {
|
|
|
- scanTreeVisible.value = true
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- // 拦截器已弹错
|
|
|
- } finally {
|
|
|
- scanLoading.value = false
|
|
|
- resolve()
|
|
|
- }
|
|
|
- }, 500)
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const confirmScanTree = () => {
|
|
|
- const tree = scanTreeRef.value
|
|
|
- if (!tree) return
|
|
|
- const nodes = tree.getCheckedNodes(false, true) // leafOnly=false, onlyChecked=true
|
|
|
- if (!nodes.length) {
|
|
|
- ElMessage({ type: 'warning', message: '请至少勾选一个目录' })
|
|
|
- return
|
|
|
- }
|
|
|
- // 回填到 form.directories: 本地挂载路径(udeServer 真去 mount 了,可直接用作 t_directory.directory)
|
|
|
- const paths = nodes.map(n => n.localMount)
|
|
|
- form.value.directories = paths.map(p => ({ directory: p }))
|
|
|
- ElMessage({ type: 'success', message: `已回填 ${paths.length} 个保护目录(本地挂载路径)` })
|
|
|
- closeScanTree()
|
|
|
-}
|
|
|
-
|
|
|
-const closeScanTree = () => {
|
|
|
- scanTreeVisible.value = false
|
|
|
-}
|
|
|
-
|
|
|
// ---------- 服务器本地目录懒加载树(从根目录 / 开始,只列目录) ----------
|
|
|
const localTreeVisible = ref(false)
|
|
|
const localTreeRef = ref(null)
|
|
|
@@ -583,25 +487,6 @@ const confirmLocalTree = () => {
|
|
|
closeLocalTree()
|
|
|
}
|
|
|
|
|
|
-// 打开 / 切换到新增/编辑弹窗时,如果 IP+port 已合法,自动触发检测
|
|
|
-// 注意:这两段 watch 必须放在 dialogFormVisible / form / scanTreeVisible /
|
|
|
-// scanTimer / triggerScan 全部声明之后,Vue 注册 watch 时会同步跑一次
|
|
|
-// source getter 取基线值,提前声明会触发 TDZ。
|
|
|
-watch(
|
|
|
- () => dialogFormVisible.value,
|
|
|
- val => {
|
|
|
- if (val) {
|
|
|
- // 等弹窗挂载完再触发,确保 form.value 已就位
|
|
|
- setTimeout(() => triggerScan(true), 200)
|
|
|
- }
|
|
|
- }
|
|
|
-)
|
|
|
-// IP 或 Port 变化也触发自动检测
|
|
|
-watch(
|
|
|
- [() => form.value.ip, () => form.value.port],
|
|
|
- () => triggerScan(false)
|
|
|
-)
|
|
|
-
|
|
|
// 服务名称:只允许中文/英文/数字/空格/中划线/下划线/点
|
|
|
const serviceNameRegex = /^[\u4e00-\u9fa5a-zA-Z0-9 _.-]+$/
|
|
|
const validateServiceNameFormat = (rule, value, callback) => {
|