@@ -274,9 +358,17 @@ const renameParams = ref({
case_sensitive: true,
format: '%Y%m%d',
position: 'suffix',
+ position: 'suffix',
case_type: 'lower'
})
+// 配置相关状态
+const showConfigModal = ref(false)
+const configBasePath = ref('')
+const configExtensions = ref({})
+const newCategoryName = ref('')
+const isConfigLoading = ref(false)
+
// 策略定义
const strategies = ref([
{ name: 'add_prefix', title: '添加前缀', description: '在文件名前添加字符' },
@@ -426,9 +518,13 @@ onMounted(() => {
websocketService.on('onRenameStrategies', handleRenameStrategies)
websocketService.on('onRenamePreview', handleRenamePreview)
websocketService.on('onRenameResult', handleRenameResult)
+ websocketService.on('onFileConfigUpdate', handleFileConfigUpdate)
// 初始获取
refreshFileList()
+
+ // 获取初始配置
+ websocketService.getFileConfig()
websocketService.getRenameStrategies()
})
@@ -439,6 +535,7 @@ onUnmounted(() => {
websocketService.off('onRenameStrategies', handleRenameStrategies)
websocketService.off('onRenamePreview', handleRenamePreview)
websocketService.off('onRenameResult', handleRenameResult)
+ websocketService.off('onFileConfigUpdate', handleFileConfigUpdate)
})
// 获取文件图标
@@ -525,6 +622,122 @@ const applyRename = () => {
)
}
+// 处理配置更新
+const handleFileConfigUpdate = (data) => {
+ isConfigLoading.value = false
+ if (data.base_path) {
+ configBasePath.value = data.base_path
+ // 如果是设置成功后的回传,更新当前路径
+ if (showConfigModal.value === false) {
+ currentPath.value = data.base_path
+ }
+ }
+ if (data.file_extensions) {
+ configExtensions.value = JSON.parse(JSON.stringify(data.file_extensions))
+ }
+}
+
+// 配置模态框方法
+const openConfigModal = () => {
+ isConfigLoading.value = true
+ showConfigModal.value = true
+
+ // 尝试发送请求
+ const sent = websocketService.getFileConfig()
+
+ if (!sent) {
+ // 发送失败(未连接),直接结束加载状态
+ isConfigLoading.value = false
+ // 但我们仍然显示弹窗,允许用户看(虽然可能是空的)或者手动重试?
+ // 更好的是提示用户
+ // 这里简单处理:让它保持打开,但 loading 结束
+ } else {
+ // 设置超时保护 (3秒后如果还没响应,就停止loading)
+ setTimeout(() => {
+ if (isConfigLoading.value) {
+ isConfigLoading.value = false
+ }
+ }, 3000)
+ }
+}
+
+const closeConfigModal = () => {
+ showConfigModal.value = false
+ isConfigLoading.value = false
+}
+
+const removeExtension = (category, index) => {
+ if (configExtensions.value[category]) {
+ configExtensions.value[category].splice(index, 1)
+ }
+}
+
+const removeCategory = (category) => {
+ if (confirm(`确定要删除 "${category}" 分类及其所有后缀吗?`)) {
+ delete configExtensions.value[category]
+ }
+}
+
+const addNewCategory = () => {
+ const name = newCategoryName.value.trim()
+ if (!name) return
+
+ if (configExtensions.value[name]) {
+ alert('该分类已存在')
+ return
+ }
+
+ // Use standard reactivity assignment for new property
+ configExtensions.value = {
+ ...configExtensions.value,
+ [name]: []
+ }
+ newCategoryName.value = ''
+}
+
+const addExtension = (category, event) => {
+ const val = event.target.value.trim()
+ if (!val) return
+
+ // Ensure starts with .
+ const ext = val.startsWith('.') ? val : `.${val}`
+
+ if (!configExtensions.value[category]) {
+ configExtensions.value[category] = []
+ }
+
+ if (!configExtensions.value[category].includes(ext)) {
+ configExtensions.value[category].push(ext)
+ }
+
+ event.target.value = '' // clear input
+}
+
+const saveConfig = () => {
+ // 验证: 检查是否有分类但没有后缀的情况
+ for (const [category, exts] of Object.entries(configExtensions.value)) {
+ if (!exts || exts.length === 0) {
+ alert(`分类 "${category}" 下没有添加任何扩展名 (如 .md, .txt),将无法扫描到文件。请先添加扩展名。`)
+ return
+ }
+ }
+
+ // 保存路径
+ if (configBasePath.value) {
+ websocketService.setBasePath(configBasePath.value)
+ }
+
+ // 保存扩展名
+ websocketService.setFileExtensions(configExtensions.value)
+
+ closeConfigModal()
+
+ // 延迟刷新列表 (给后端一点时间保存和重新扫描)
+ setTimeout(() => {
+ refreshFileList()
+ }, 500)
+}
+
diff --git a/src/services/websocketService.js b/src/services/websocketService.js
index 1996181..5021797 100644
--- a/src/services/websocketService.js
+++ b/src/services/websocketService.js
@@ -34,7 +34,8 @@ class WebSocketService {
onDownloadUrl: [],
onRenameStrategies: [],
onRenamePreview: [],
- onRenameResult: []
+ onRenameResult: [],
+ onFileConfigUpdate: []
}
}
@@ -214,6 +215,11 @@ class WebSocketService {
if (message.data.results) {
this.emit('onRenameResult', message.data)
}
+
+ // 文件配置相关消息 (使用 in 运算符检查属性存在性,避免空字符串/空对象判定为假)
+ if ('base_path' in message.data || 'file_extensions' in message.data) {
+ this.emit('onFileConfigUpdate', message.data)
+ }
}
}
@@ -401,6 +407,29 @@ class WebSocketService {
})
}
+ // 设置基础扫描路径
+ setBasePath(path) {
+ return this.send({
+ type: 'set_base_path',
+ base_path: path
+ })
+ }
+
+ // 设置文件扩展名配置
+ setFileExtensions(extensions) {
+ return this.send({
+ type: 'set_file_extensions',
+ file_extensions: extensions
+ })
+ }
+
+ // 获取文件配置
+ getFileConfig() {
+ return this.send({
+ type: 'get_file_config'
+ })
+ }
+
// 心跳检测
startHeartbeat() {
this.heartbeatTimer = setInterval(() => {