✨ 移动 & 提权.
This commit is contained in:
@@ -104,6 +104,9 @@ export function downloadFile(res: any, fileName: string) {
|
||||
* 10进制权限 转 字符串权限
|
||||
*/
|
||||
export function permission10toString(permission: number) {
|
||||
if (permission === undefined) {
|
||||
return '---';
|
||||
}
|
||||
const ps = (permission + '');
|
||||
let res = '';
|
||||
for (let i = 0; i < ps.length; i++) {
|
||||
@@ -124,6 +127,11 @@ export function permission10toString(permission: number) {
|
||||
res += 'x';
|
||||
}
|
||||
}
|
||||
if (res.length <= 9) {
|
||||
res = res.padEnd(9, '-');
|
||||
} else {
|
||||
res = res.substring(0, 9);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,43 @@
|
||||
<template>
|
||||
<div></div>
|
||||
<a-modal v-model:visible="visible"
|
||||
body-class="modal-form"
|
||||
title-align="start"
|
||||
title="修改权限"
|
||||
:align-center="false"
|
||||
:mask-closable="false"
|
||||
:unmount-on-close="true"
|
||||
:on-before-ok="handlerOk">
|
||||
<a-form :model="formModel"
|
||||
ref="formRef"
|
||||
label-align="right"
|
||||
:style="{ width: '460px' }"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }">
|
||||
<!-- 文件路径 -->
|
||||
<a-form-item field="path"
|
||||
disabled
|
||||
label="文件路径">
|
||||
<a-input v-model="formModel.path"
|
||||
placeholder="原始路径" />
|
||||
</a-form-item>
|
||||
<!-- 文件权限 -->
|
||||
<a-form-item field="mod"
|
||||
label="文件权限"
|
||||
:rules="[{ required: true, message: '请输入文件权限' }]">
|
||||
<div class="mod-wrapper">
|
||||
<!-- 权限输入框 -->
|
||||
<a-input-number ref="modRef"
|
||||
class="mod-input"
|
||||
v-model="formModel.mod"
|
||||
placeholder="请输入文件权限"
|
||||
hide-button
|
||||
@input="updatePreview" />
|
||||
<!-- 权限预览 -->
|
||||
<span class="mod-preview">{{ formModel.permission }}</span>
|
||||
</div>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -9,9 +47,79 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
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';
|
||||
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { sessionManager } = useTerminalStore();
|
||||
|
||||
const sessionId = ref();
|
||||
const modRef = ref();
|
||||
const formRef = ref();
|
||||
const formModel = ref({
|
||||
path: '',
|
||||
mod: 0,
|
||||
permission: ''
|
||||
});
|
||||
|
||||
// 修改预览
|
||||
const updatePreview = (v: number) => {
|
||||
formModel.value.permission = permission10toString(v);
|
||||
};
|
||||
|
||||
// 打开新增
|
||||
const open = (session: string, path: string, permission: number) => {
|
||||
sessionId.value = session;
|
||||
formModel.value.path = path;
|
||||
formModel.value.mod = permission;
|
||||
formModel.value.permission = permission10toString(permission);
|
||||
setVisible(true);
|
||||
// 自动聚焦
|
||||
nextTick(() => {
|
||||
modRef.value?.focus();
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
try {
|
||||
// 验证参数
|
||||
const error = await formRef.value.validate();
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
// 获取会话
|
||||
const session = sessionManager.getSession(sessionId.value);
|
||||
if (session instanceof SftpSession) {
|
||||
session.chmod(formModel.value.path, formModel.value.mod);
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.mod-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.mod-input {
|
||||
width: 65%;
|
||||
}
|
||||
|
||||
.mod-preview {
|
||||
width: 30%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
:align-center="false"
|
||||
:mask-closable="false"
|
||||
:unmount-on-close="true"
|
||||
:on-before-ok="handlerOk"
|
||||
@close="handleClose">
|
||||
:on-before-ok="handlerOk">
|
||||
<a-form :model="formModel"
|
||||
ref="formRef"
|
||||
label-align="right"
|
||||
layout="horizontal"
|
||||
:style="{ width: '460px' }"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }">
|
||||
@@ -35,13 +33,11 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useVisible from '@/hooks/visible';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { nextTick, ref } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import SftpSession from '../../handler/sftp-session';
|
||||
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { loading, setLoading } = useLoading();
|
||||
const { sessionManager } = useTerminalStore();
|
||||
|
||||
const sessionId = ref();
|
||||
@@ -68,7 +64,6 @@
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// 验证参数
|
||||
const error = await formRef.value.validate();
|
||||
@@ -86,25 +81,11 @@
|
||||
session.mkdir(formModel.value.path);
|
||||
}
|
||||
}
|
||||
// 清空
|
||||
handlerClear();
|
||||
} catch (e) {
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
handlerClear();
|
||||
};
|
||||
|
||||
// 清空
|
||||
const handlerClear = () => {
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
@@ -1,5 +1,36 @@
|
||||
<template>
|
||||
<div></div>
|
||||
<a-modal v-model:visible="visible"
|
||||
body-class="modal-form"
|
||||
title-align="start"
|
||||
title="移动文件"
|
||||
:align-center="false"
|
||||
:mask-closable="false"
|
||||
:unmount-on-close="true"
|
||||
:on-before-ok="handlerOk">
|
||||
<a-form :model="formModel"
|
||||
ref="formRef"
|
||||
label-align="right"
|
||||
:style="{ width: '460px' }"
|
||||
:label-col-props="{ span: 6 }"
|
||||
:wrapper-col-props="{ span: 18 }">
|
||||
<!-- 原始路径 -->
|
||||
<a-form-item field="path"
|
||||
disabled
|
||||
label="原始路径">
|
||||
<a-input v-model="formModel.path"
|
||||
placeholder="原始路径" />
|
||||
</a-form-item>
|
||||
<!-- 目标路径 -->
|
||||
<a-form-item field="target"
|
||||
label="目标路径"
|
||||
extra="目标路径可以是绝对路径/相对路径/名称 (可以包含 ./ ../)"
|
||||
:rules="[{ required: true, message: '请输入目标路径' }]">
|
||||
<a-input ref="targetRef"
|
||||
v-model="formModel.target"
|
||||
placeholder="请输入目标路径" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
@@ -9,6 +40,53 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { nextTick, ref } from 'vue';
|
||||
import { useTerminalStore } from '@/store';
|
||||
import SftpSession from '../../handler/sftp-session';
|
||||
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { sessionManager } = useTerminalStore();
|
||||
|
||||
const sessionId = ref();
|
||||
const targetRef = ref();
|
||||
const formRef = ref();
|
||||
const formModel = ref({
|
||||
path: '',
|
||||
target: ''
|
||||
});
|
||||
|
||||
// 打开新增
|
||||
const open = (session: string, path: string) => {
|
||||
sessionId.value = session;
|
||||
formModel.value.path = path;
|
||||
formModel.value.target = path;
|
||||
setVisible(true);
|
||||
// 自动聚焦
|
||||
nextTick(() => {
|
||||
targetRef.value?.focus();
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
try {
|
||||
// 验证参数
|
||||
const error = await formRef.value.validate();
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
// 获取会话
|
||||
const session = sessionManager.getSession(sessionId.value);
|
||||
if (session instanceof SftpSession) {
|
||||
session.move(formModel.value.path, formModel.value.target);
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
arrow-class="terminal-tooltip-content"
|
||||
content="提权">
|
||||
<span class="click-icon-wrapper row-action-icon"
|
||||
@click="chmodFile(record.path, record.attr)">
|
||||
@click="chmodFile(record.path, record.permission)">
|
||||
<icon-user-group />
|
||||
</span>
|
||||
</a-tooltip>
|
||||
@@ -144,13 +144,13 @@
|
||||
import type { TableData } from '@arco-design/web-vue/es/table/interface';
|
||||
import type { SftpFile, ISftpSession } from '../../types/terminal.type';
|
||||
import type { VNodeRef } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { ref, computed, watch, inject } from 'vue';
|
||||
import { useRowSelection } from '@/types/table';
|
||||
import { dateFormat } from '@/utils';
|
||||
import { setAutoFocus } from '@/utils/dom';
|
||||
import useCopy from '@/hooks/copy';
|
||||
import columns from './types/table.columns';
|
||||
import { FILE_TYPE } from '../../types/terminal.const';
|
||||
import { setAutoFocus } from '@/utils/dom';
|
||||
import { FILE_TYPE, openSftpChmodModalKey, openSftpMoveModalKey } from '../../types/terminal.const';
|
||||
|
||||
const props = defineProps<{
|
||||
session: ISftpSession | undefined;
|
||||
@@ -161,6 +161,9 @@
|
||||
|
||||
const emits = defineEmits(['update:selectedFiles', 'loadFile']);
|
||||
|
||||
const openSftpMoveModal = inject(openSftpMoveModalKey) as (sessionId: string, path: string) => void;
|
||||
const openSftpChmodModal = inject(openSftpChmodModalKey) as (sessionId: string, path: string, permission: number) => void;
|
||||
|
||||
const rowSelection = useRowSelection({ width: 40 });
|
||||
const { copy } = useCopy();
|
||||
|
||||
@@ -211,6 +214,8 @@
|
||||
if (FILE_TYPE.DIRECTORY.value === formatFileType(record.attr).value) {
|
||||
// 进入文件夹
|
||||
emits('loadFile', record.path);
|
||||
} else {
|
||||
copy(record.name, '名称已复制');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -232,15 +237,12 @@
|
||||
|
||||
// 移动文件
|
||||
const moveFile = (path: string) => {
|
||||
// TODO openModal('path')
|
||||
console.log(path);
|
||||
openSftpMoveModal(props.session?.sessionId as string, path);
|
||||
};
|
||||
|
||||
// 文件提权
|
||||
const chmodFile = (path: string, attr: string) => {
|
||||
// TODO openModal('path','mod')
|
||||
console.log(path, attr);
|
||||
|
||||
const chmodFile = (path: string, permission: number) => {
|
||||
openSftpChmodModal(props.session?.sessionId as string, path, permission);
|
||||
};
|
||||
|
||||
// 格式化文件类型
|
||||
|
||||
@@ -30,6 +30,10 @@
|
||||
</a-split>
|
||||
<!-- 创建文件模态框 -->
|
||||
<sftp-create-modal ref="createModal" />
|
||||
<!-- 移动文件模态框 -->
|
||||
<sftp-move-modal ref="moveModal" />
|
||||
<!-- 文件提权模态框 -->
|
||||
<sftp-chmod-modal ref="chmodModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,10 +49,12 @@
|
||||
import { useTerminalStore } from '@/store';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import { openSftpCreateModalKey } from '../../types/terminal.const';
|
||||
import { openSftpCreateModalKey, openSftpMoveModalKey, openSftpChmodModalKey } from '../../types/terminal.const';
|
||||
import SftpTable from './sftp-table.vue';
|
||||
import SftpTableHeader from './sftp-table-header.vue';
|
||||
import SftpCreateModal from './sftp-create-modal.vue';
|
||||
import SftpMoveModal from './sftp-move-modal.vue';
|
||||
import SftpChmodModal from './sftp-chmod-modal.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
tab: TerminalTabItem
|
||||
@@ -58,18 +64,30 @@
|
||||
const { loading: tableLoading, setLoading: setTableLoading } = useLoading(true);
|
||||
|
||||
const session = ref<ISftpSession>();
|
||||
const createModal = ref();
|
||||
const currentPath = ref<string>('');
|
||||
const fileList = ref<Array<SftpFile>>([]);
|
||||
const selectFiles = ref<Array<string>>([]);
|
||||
const splitSize = ref(1);
|
||||
const editView = ref(true);
|
||||
const createModal = ref();
|
||||
const moveModal = ref();
|
||||
const chmodModal = ref();
|
||||
|
||||
// 暴露打开创建方法
|
||||
// 暴露打开创建模态框
|
||||
provide(openSftpCreateModalKey, (sessionId: string, path: string, isTouch: boolean) => {
|
||||
createModal.value?.open(sessionId, path, isTouch);
|
||||
});
|
||||
|
||||
// 暴露打开移动模态框
|
||||
provide(openSftpMoveModalKey, (sessionId: string, path: string) => {
|
||||
moveModal.value?.open(sessionId, path);
|
||||
});
|
||||
|
||||
// 暴露打开提权模态框
|
||||
provide(openSftpChmodModalKey, (sessionId: string, path: string, permission: number) => {
|
||||
chmodModal.value?.open(sessionId, path, permission);
|
||||
});
|
||||
|
||||
// 连接成功回调
|
||||
const connectCallback = () => {
|
||||
loadFiles(undefined);
|
||||
|
||||
@@ -287,6 +287,12 @@ export const openSshSettingModalKey = Symbol();
|
||||
// 打开 sftpCreateModal key
|
||||
export const openSftpCreateModalKey = Symbol();
|
||||
|
||||
// 打开 sftpMoveModal key
|
||||
export const openSftpMoveModalKey = Symbol();
|
||||
|
||||
// 打开 sftpChmodModal key
|
||||
export const openSftpChmodModalKey = Symbol();
|
||||
|
||||
// 字体后缀 兜底
|
||||
export const fontFamilySuffix = ',courier-new, courier, monospace';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user