在线编辑文件.

This commit is contained in:
lijiahang
2024-02-20 13:42:19 +08:00
parent f7ca8f0bf1
commit 8acb8730bd
6 changed files with 245 additions and 16 deletions

View File

@@ -93,6 +93,18 @@
emits('editor-mounted', editor);
};
// 获取值
const getValue = () => {
return editor?.getValue();
};
// 设置值
const setValue = (value: string) => {
editor?.setValue(value);
};
defineExpose({ getValue, setValue });
// 监听主题变更
watch(() => appStore.theme, (v) => {
if (editor && props.theme === true) {

View File

@@ -50,8 +50,8 @@
import useVisible from '@/hooks/visible';
import { nextTick, ref } from 'vue';
import { useTerminalStore } from '@/store';
import SftpSession from '../../handler/sftp-session';
import { permission10toString } from '@/utils/file';
import SftpSession from '../../handler/sftp-session';
const { visible, setVisible } = useVisible();
const { sessionManager } = useTerminalStore();

View File

@@ -0,0 +1,122 @@
<template>
<!-- 表头 -->
<div class="sftp-editor-header">
<!-- 左侧操作 -->
<div class="sftp-editor-header-left">
<div class="sftp-path-container">
<!-- 当前路径 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="path">
<span>{{ name }}</span>
</a-tooltip>
</div>
</div>
<!-- 右侧操作 -->
<a-space class="sftp-editor-header-right">
<!-- 保存 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="保存">
<span class="click-icon-wrapper header-action-icon"
@click="emits('save')">
<icon-save />
</span>
</a-tooltip>
<!-- 关闭 -->
<a-tooltip position="top"
:mini="true"
:overlay-inverse="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="关闭">
<span class="click-icon-wrapper header-action-icon"
@click="emits('close')">
<icon-close />
</span>
</a-tooltip>
</a-space>
</div>
</template>
<script lang="ts">
export default {
name: 'sftpEditorHeader'
};
</script>
<script lang="ts" setup>
import type { ISftpSession } from '../../types/terminal.type';
const props = defineProps<{
name: string;
path: string;
session: ISftpSession | undefined,
}>();
const emits = defineEmits(['save', 'close']);
</script>
<style lang="less" scoped>
@action-num: 2;
@action-gap: 8px;
@action-size: 26px;
@actions-width: @action-num * (@action-size + @action-gap);
.sftp-editor-header {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
&-left, &-right {
display: flex;
align-items: center;
height: 100%;
}
&-left {
width: calc(100% - @actions-width);
}
&-right {
width: @actions-width;
justify-content: flex-end;
}
}
.sftp-path-container {
width: 100%;
height: @action-size;
background: var(--color-fill-2);
border-radius: 2px;
overflow: hidden;
display: flex;
align-items: center;
padding: 0 8px;
span {
font-size: 14px;
line-height: 1.2;
text-overflow: ellipsis;
overflow: hidden;
}
}
.header-action-icon {
font-size: 16px;
padding: 4px;
width: @action-size;
height: @action-size;
}
</style>

View File

@@ -0,0 +1,38 @@
<template>
<editor ref="editorRef"
language="txt"
:auto-focus="true"
:theme="preference.theme.dark ? 'vs-dark' : 'vs'" />
</template>
<script lang="ts">
export default {
name: 'sftpFileEditor'
};
</script>
<script lang="ts" setup>
import { ref } from 'vue';
import { useTerminalStore } from '@/store';
const { preference } = useTerminalStore();
const editorRef = ref();
// 获取值
const getValue = () => {
return editorRef.value?.getValue();
};
// 设置值
const setValue = (value: string) => {
editorRef.value?.setValue(value);
};
defineExpose({ getValue, setValue });
</script>
<style lang="less" scoped>
</style>

View File

@@ -68,7 +68,7 @@
</span>
</a-tooltip>
<!-- 编辑内容 -->
<a-tooltip v-if="canEditable(record.attr)"
<a-tooltip v-if="canEditable(record.sizeByte, record.attr)"
position="top"
:mini="true"
:overlay-inverse="true"
@@ -159,7 +159,7 @@
selectedFiles: Array<string>;
}>();
const emits = defineEmits(['update:selectedFiles', 'loadFile']);
const emits = defineEmits(['update:selectedFiles', 'loadFile', 'editFile']);
const openSftpMoveModal = inject(openSftpMoveModalKey) as (sessionId: string, path: string) => void;
const openSftpChmodModal = inject(openSftpChmodModalKey) as (sessionId: string, path: string, permission: number) => void;
@@ -202,11 +202,12 @@
};
// 是否可编辑
const canEditable = (attr: string) => {
const canEditable = (sizeByte: number, attr: string) => {
const typeValue = formatFileType(attr).value;
// 非文件夹和链接文件可以编辑
// 非文件夹和链接文件 并且文件大小小于 2MB 可以编辑
return FILE_TYPE.DIRECTORY.value !== typeValue
&& FILE_TYPE.LINK_FILE.value !== typeValue;
&& FILE_TYPE.LINK_FILE.value !== typeValue
&& sizeByte <= 2 * 1024 * 1024;
};
// 点击文件名称
@@ -221,7 +222,8 @@
// 编辑文件
const editFile = (record: TableData) => {
// TODO
emits('editFile', record.name, record.path);
props.session?.getContent(record.path);
};
// 删除文件

View File

@@ -3,7 +3,7 @@
<a-split class="split-view"
v-model:size="splitSize"
:min="0.3"
:disabled="!editView">
:disabled="!editorView">
<!-- 左侧面板表格 -->
<template #first>
<a-spin class="sftp-table-container"
@@ -21,11 +21,24 @@
:session="session"
:list="fileList"
:loading="tableLoading"
@load-file="loadFiles" />
@load-file="loadFiles"
@edit-file="editFile" />
</a-spin>
</template>
<template #second v-if="editView">
<div>editor</div>
<template #second v-if="editorView">
<a-spin class="sftp-editor-container"
:loading="editorLoading">
<!-- 表头 -->
<sftp-editor-header class="sftp-editor-header"
:name="editorFileName"
:path="editorFilePath"
:session="session"
@save="editorSave"
@close="closeEditor" />
<!-- 编辑器 -->
<sftp-editor class="sftp-editor-wrapper"
ref="editorRef" />
</a-spin>
</template>
</a-split>
<!-- 创建文件模态框 -->
@@ -50,8 +63,10 @@
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
import { openSftpCreateModalKey, openSftpMoveModalKey, openSftpChmodModalKey } from '../../types/terminal.const';
import SftpTable from './sftp-table.vue';
import SftpTableHeader from './sftp-table-header.vue';
import SftpTable from './sftp-table.vue';
import SftpEditorHeader from './sftp-editor-header.vue';
import SftpEditor from './sftp-editor.vue';
import SftpCreateModal from './sftp-create-modal.vue';
import SftpMoveModal from './sftp-move-modal.vue';
import SftpChmodModal from './sftp-chmod-modal.vue';
@@ -62,13 +77,17 @@
const { preference, sessionManager } = useTerminalStore();
const { loading: tableLoading, setLoading: setTableLoading } = useLoading(true);
const { loading: editorLoading, setLoading: setEditorLoading } = useLoading();
const session = ref<ISftpSession>();
const currentPath = ref<string>('');
const fileList = ref<Array<SftpFile>>([]);
const selectFiles = ref<Array<string>>([]);
const splitSize = ref(1);
const editView = ref(true);
const editorView = ref(false);
const editorRef = ref();
const editorFileName = ref('');
const editorFilePath = ref('');
const createModal = ref();
const moveModal = ref();
const chmodModal = ref();
@@ -88,6 +107,30 @@
chmodModal.value?.open(sessionId, path, permission);
});
// 编辑文件
const editFile = (name: string, path: string) => {
setEditorLoading(true);
splitSize.value = 0.6;
editorView.value = true;
editorFileName.value = name;
editorFilePath.value = path;
};
// 编辑器保存
const editorSave = () => {
setEditorLoading(true);
const value = editorRef.value?.getValue() || '';
session.value?.setContent(editorFilePath.value, value);
};
// 关闭编辑器
const closeEditor = () => {
splitSize.value = 1;
editorView.value = false;
editorFileName.value = '';
editorFilePath.value = '';
};
// 连接成功回调
const connectCallback = () => {
loadFiles(undefined);
@@ -133,10 +176,22 @@
// 接收获取文件内容响应
const resolveSftpGetContent = (path: string, result: string, content: string) => {
setEditorLoading(false);
// 检查结果
if (!checkResult(result, '加载失败')) {
return;
}
editorRef.value?.setValue(content);
};
// 接收修改文件内容响应
const resolveSftpSetContent = (result: string, msg: string) => {
setEditorLoading(false);
// 检查结果
if (!checkResult(result, msg)) {
return;
}
Message.success('保存成功');
};
// 初始化会话
@@ -176,18 +231,18 @@
}
}
.sftp-table-container {
.sftp-table-container, .sftp-editor-container {
padding: 8px;
width: 100%;
height: 100%;
.sftp-table-header {
.sftp-table-header, .sftp-editor-header {
width: 100%;
height: @sftp-table-header-height;
padding-bottom: 8px;
}
.sftp-table-wrapper {
.sftp-table-wrapper, .sftp-editor-wrapper {
height: calc(100% - @sftp-table-header-height);
}
}