2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-08 17:44:37 +08:00

feat: 阶段提交

This commit is contained in:
2026-01-12 05:24:53 +08:00
parent c3054dcb91
commit fe90dd3dc8
10 changed files with 2166 additions and 19 deletions

View File

@@ -1,38 +1,70 @@
<script setup lang="ts">
import FileEditor from '@/components/common/FileEditor.vue'
import file from '@/api/panel/file'
import { FileEditorView } from '@/components/file-editor'
import { useEditorStore } from '@/store'
import { decodeBase64 } from '@/utils'
import { useGettext } from 'vue3-gettext'
const { $gettext } = useGettext()
const editorStore = useEditorStore()
const show = defineModel<boolean>('show', { type: Boolean, required: true })
const file = defineModel<string>('file', { type: String, required: true })
const editor = ref<any>(null)
const filePath = defineModel<string>('file', { type: String, required: true })
const handleRefresh = () => {
editor.value.get()
}
const editorRef = ref<InstanceType<typeof FileEditorView>>()
const handleSave = () => {
editor.value.save()
}
// 获取文件所在目录作为初始路径
const initialPath = computed(() => {
if (!filePath.value) return '/'
const parts = filePath.value.split('/')
parts.pop()
return parts.join('/') || '/'
})
// 打开时自动加载文件
watch(show, (newShow) => {
if (newShow && filePath.value) {
// 暂停文件管理的键盘快捷键
window.$bus.emit('file:keyboard-pause')
// 清空之前的标签页
editorStore.closeAllTabs()
// 设置根目录
editorStore.setRootPath(initialPath.value)
// 打开指定文件
editorStore.openFile(filePath.value, '', 'utf-8')
editorStore.setLoading(filePath.value, true)
useRequest(file.content(encodeURIComponent(filePath.value)))
.onSuccess(({ data }) => {
const content = decodeBase64(data.content)
editorStore.reloadFile(filePath.value, content)
})
.onError(() => {
window.$message.error($gettext('Failed to load file'))
editorStore.closeTab(filePath.value)
})
.onComplete(() => {
editorStore.setLoading(filePath.value, false)
})
} else if (!newShow) {
// 恢复文件管理的键盘快捷键
window.$bus.emit('file:keyboard-resume')
}
})
</script>
<template>
<n-modal
v-model:show="show"
preset="card"
:title="$gettext('Edit - %{ file }', { file })"
style="width: 60vw"
size="huge"
:title="$gettext('File Editor')"
style="width: 90vw; height: 85vh"
content-style="padding: 0; height: calc(85vh - 60px); display: flex; flex-direction: column;"
:bordered="false"
:segmented="false"
>
<template #header-extra>
<n-flex>
<n-button @click="handleRefresh"> {{ $gettext('Refresh') }} </n-button>
<n-button type="primary" @click="handleSave"> {{ $gettext('Save') }} </n-button>
</n-flex>
</template>
<file-editor ref="editor" :path="file" :read-only="false" />
<FileEditorView ref="editorRef" :initial-path="initialPath" />
</n-modal>
</template>

View File

@@ -906,8 +906,24 @@ const goToParentDir = () => {
path.value = parentPath
}
// 键盘快捷键暂停状态
const keyboardPaused = ref(false)
const pauseKeyboard = () => {
keyboardPaused.value = true
}
const resumeKeyboard = () => {
keyboardPaused.value = false
}
// 键盘快捷键处理
const handleKeyDown = (event: KeyboardEvent) => {
// 如果键盘监听被暂停(如编辑器打开时),不处理快捷键
if (keyboardPaused.value) {
return
}
// 如果焦点在输入框中,不处理快捷键
const target = event.target as HTMLElement
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable) {
@@ -1116,6 +1132,8 @@ onMounted(() => {
window.$bus.on('file:search', handleFileSearch)
window.$bus.on('file:refresh', refresh)
window.$bus.on('file:keyboard-pause', pauseKeyboard)
window.$bus.on('file:keyboard-resume', resumeKeyboard)
// 添加全局鼠标事件监听
document.addEventListener('mousemove', onSelectionMove)
@@ -1135,6 +1153,8 @@ onUnmounted(() => {
// 移除事件监听
window.$bus.off('file:search', handleFileSearch)
window.$bus.off('file:refresh', refresh)
window.$bus.off('file:keyboard-pause', pauseKeyboard)
window.$bus.off('file:keyboard-resume', resumeKeyboard)
document.removeEventListener('mousemove', onSelectionMove)
document.removeEventListener('mouseup', onSelectionEnd)
document.removeEventListener('keydown', handleKeyDown)