🔨 修改 sftp 样式.

This commit is contained in:
lijiahangmax
2025-11-26 10:25:59 +08:00
parent ad42be8fe8
commit 21e7d29077
5 changed files with 127 additions and 140 deletions

View File

@@ -6,7 +6,7 @@
:unmount-on-close="true"
:ok-button-props="{ disabled: loading }"
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
:on-before-ok="handleOk"
@cancel="handleClose">
<a-spin class="full form-container" :loading="loading">
<a-form :model="formModel"
@@ -14,6 +14,13 @@
label-align="right"
:auto-label-width="true"
:rules="bookmarkFormRules">
<!-- 类型 -->
<a-form-item field="type" label="类型" hide-asterisk>
<a-radio-group v-model="formModel.type"
type="button"
class="full-radio-group usn"
:options="toRadioOptions(pathBookmarkTypeKey)" />
</a-form-item>
<!-- 名称 -->
<a-form-item field="name" label="名称">
<a-input v-model="formModel.name"
@@ -24,13 +31,6 @@
<a-form-item field="groupId" label="分组">
<path-bookmark-group-selector v-model="formModel.groupId" />
</a-form-item>
<!-- 类型 -->
<a-form-item field="type" label="类型">
<a-select v-model="formModel.type"
:options="toOptions(pathBookmarkTypeKey)"
placeholder="请选择类型"
allow-clear />
</a-form-item>
<!-- 文件路径 -->
<a-form-item field="path" label="路径">
<a-textarea v-model="formModel.path"
@@ -51,22 +51,24 @@
<script lang="ts" setup>
import type { PathBookmarkUpdateRequest } from '@/api/terminal/path-bookmark';
import type { FormHandle } from '@/types/form';
import { ref } from 'vue';
import useLoading from '@/hooks/loading';
import useVisible from '@/hooks/visible';
import { assignOmitRecord } from '@/utils';
import { createPathBookmark, updatePathBookmark } from '@/api/terminal/path-bookmark';
import { bookmarkFormRules } from '../../types/form.rules';
import { pathBookmarkTypeKey, PathBookmarkType } from '../../types/const';
import { useDictStore } from '@/store';
import { Message } from '@arco-design/web-vue';
import { pathBookmarkTypeKey, PathBookmarkType } from '../../types/const';
import { bookmarkFormRules } from '../../types/form.rules';
import PathBookmarkGroupSelector from '@/components/terminal/bookmark-path/group/selector/index.vue';
const { visible, setVisible } = useVisible();
const { loading, setLoading } = useLoading();
const { toOptions } = useDictStore();
const { toRadioOptions } = useDictStore();
const title = ref<string>();
const isAddHandle = ref<boolean>(true);
const formHandle = ref<FormHandle>('add');
const defaultForm = (): PathBookmarkUpdateRequest => {
return {
@@ -86,28 +88,23 @@
// 打开新增
const openAdd = () => {
title.value = '添加路径书签';
isAddHandle.value = true;
renderForm({ ...defaultForm() });
formHandle.value = 'add';
formModel.value = assignOmitRecord({ ...defaultForm() });
setVisible(true);
};
// 打开修改
const openUpdate = (record: any) => {
title.value = '修改路径书签';
isAddHandle.value = false;
renderForm({ ...defaultForm(), ...record });
formHandle.value = 'update';
formModel.value = assignOmitRecord({ ...defaultForm(), ...record });
setVisible(true);
};
// 渲染表单
const renderForm = (record: any) => {
formModel.value = Object.assign({}, record);
};
defineExpose({ openAdd, openUpdate });
// 确定
const handlerOk = async () => {
const handleOk = async () => {
setLoading(true);
try {
// 验证参数
@@ -115,7 +112,7 @@
if (error) {
return false;
}
if (isAddHandle.value) {
if (formHandle.value === 'add') {
// 新增
const { data: id } = await createPathBookmark(formModel.value);
formModel.value.id = id;
@@ -127,8 +124,8 @@
Message.success('修改成功');
emits('updated', formModel.value);
}
// 清空
handlerClear();
handleClose();
return true;
} catch (e) {
return false;
} finally {
@@ -138,11 +135,12 @@
// 关闭
const handleClose = () => {
handlerClear();
handleClear();
setVisible(false);
};
// 清空
const handlerClear = () => {
const handleClear = () => {
setLoading(false);
};

View File

@@ -15,8 +15,9 @@
<a-form-item field="path"
disabled
label="文件路径">
<a-input v-model="formModel.path"
placeholder="原始路径" />
<a-textarea v-model="formModel.path"
placeholder="原始路径"
:auto-size="{ minRows: 3, maxRows: 3 }" />
</a-form-item>
<!-- 文件权限 -->
<a-form-item field="mod"
@@ -56,7 +57,6 @@
const { visible, setVisible } = useVisible();
const sessionKey = ref();
const modRef = ref();
const formRef = ref();
const formModel = ref({

View File

@@ -15,9 +15,10 @@
<a-form-item field="path"
:label="`${touch ? '文件' : '文件夹'}路径`"
:rules="[{ required: true, message: `请输入${touch ? '文件' : '文件夹'}路径` }]">
<a-input ref="pathRef"
v-model="formModel.path"
:placeholder="`请输入${touch ? '文件' : '文件夹'}路径`" />
<a-textarea ref="pathRef"
v-model="formModel.path"
:placeholder="`请输入${touch ? '文件' : '文件夹'}路径`"
:auto-size="{ minRows: 3, maxRows: 3 }" />
</a-form-item>
</a-form>
</a-modal>

View File

@@ -15,17 +15,19 @@
<a-form-item field="path"
disabled
label="原始路径">
<a-input v-model="formModel.path"
placeholder="原始路径" />
<a-textarea v-model="formModel.path"
placeholder="原始路径"
:auto-size="{ minRows: 3, maxRows: 3 }" />
</a-form-item>
<!-- 目标路径 -->
<a-form-item field="target"
label="目标路径"
extra="目标路径可以是绝对路径/相对路径/名称 (可以包含 ./ ../)"
:rules="[{ required: true, message: '请输入目标路径' }]">
<a-input ref="targetRef"
v-model="formModel.target"
placeholder="请输入目标路径" />
<a-textarea ref="targetRef"
v-model="formModel.target"
placeholder="请输入目标路径"
:auto-size="{ minRows: 3, maxRows: 3 }" />
</a-form-item>
</a-form>
</a-modal>

View File

@@ -8,67 +8,73 @@
:align-center="false"
:mask-closable="false"
:unmount-on-close="true"
:on-before-ok="handlerOk"
:on-before-ok="handleOk"
@cancel="handleClose">
<div class="upload-container">
<a-form :model="formModel"
ref="formRef"
label-align="right"
:auto-label-width="true">
<!-- 上传目录 -->
<div class="item-wrapper">
<div class="form-item">
<span class="item-label">上传至文件夹</span>
<a-input class="item-input"
v-model="parentPath"
placeholder="上传目录" />
<a-form-item field="parentPath"
label="上传目录"
:rules="[{ required: true, message: '请输入文件上传目录' }]">
<a-textarea ref="pathRef"
v-model="formModel.parentPath"
placeholder="上传目录"
:auto-size="{ minRows: 3, maxRows: 3 }" />
</a-form-item>
<!-- 选择文件 -->
<a-form-item class="mb0" hide-asterisk>
<div class="button-container">
<!-- 选择文件 -->
<a-upload v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="false"
:multiple="true">
<template #upload-button>
<a-button type="primary" long>选择文件</a-button>
</template>
</a-upload>
<!-- 选择文件夹 -->
<a-upload v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="false"
:directory="true">
<template #upload-button>
<a-button type="primary" long>选择文件夹</a-button>
</template>
</a-upload>
</div>
</div>
<a-space>
<!-- 选择文件 -->
<a-upload v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="false"
:multiple="true">
<template #upload-button>
<a-button type="primary">选择文件</a-button>
</template>
</a-upload>
<!-- 选择文件夹 -->
<a-upload v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="false"
:directory="true">
<template #upload-button>
<a-button type="primary">选择文件夹</a-button>
</template>
</a-upload>
</a-space>
<!-- 文件列表 -->
<a-upload v-if="fileList.length"
class="file-list-uploader"
v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="true">
<template #upload-button />
<template #file-name="{ fileItem }">
<div class="file-name-wrapper">
</a-form-item>
</a-form>
<!-- 文件列表 -->
<a-upload v-if="fileList.length"
class="file-list-uploader"
v-model:file-list="fileList"
:auto-upload="false"
:show-file-list="true">
<template #upload-button />
<template #file-name="{ fileItem }">
<div class="file-name-wrapper">
<!-- 文件名称 -->
<a-tooltip position="left"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="fileItem.file.webkitRelativePath || fileItem.file.name">
<!-- 文件名称 -->
<a-tooltip position="left"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="fileItem.file.webkitRelativePath || fileItem.file.name">
<!-- 文件名称 -->
<span class="file-name text-ellipsis">
{{ fileItem.file.webkitRelativePath || fileItem.file.name }}
</span>
</a-tooltip>
<!-- 文件大小 -->
<span class="file-size span-blue">
{{ getFileSize(fileItem.file.size) }}
<span class="file-name text-ellipsis">
{{ fileItem.file.webkitRelativePath || fileItem.file.name }}
</span>
</div>
</template>
</a-upload>
</div>
</a-tooltip>
<!-- 文件大小 -->
<span class="file-size span-blue">
{{ getFileSize(fileItem.file.size) }}
</span>
</div>
</template>
</a-upload>
</a-modal>
</template>
@@ -81,12 +87,11 @@
<script lang="ts" setup>
import type { FileItem } from '@arco-design/web-vue';
import type { ITerminalSession } from '@/views/terminal/interfaces';
import { ref } from 'vue';
import { ref, nextTick } from 'vue';
import { useTerminalStore } from '@/store';
import { Message } from '@arco-design/web-vue';
import { getFileSize } from '@/utils/file';
import useVisible from '@/hooks/visible';
import useLoading from '@/hooks/loading';
const props = defineProps<{
session?: ITerminalSession;
@@ -94,24 +99,31 @@
const emits = defineEmits(['closed']);
const { visible, setVisible } = useVisible();
const { loading, setLoading } = useLoading();
const { transferManager } = useTerminalStore();
const parentPath = ref('');
const pathRef = ref();
const formRef = ref();
const formModel = ref({
parentPath: ''
});
const fileList = ref<FileItem[]>([]);
// 打开
const open = (parent: string) => {
parentPath.value = parent;
formModel.value.parentPath = parent;
setVisible(true);
nextTick(() => {
pathRef.value?.focus();
});
};
defineExpose({ open });
// 确定
const handlerOk = async () => {
if (!parentPath.value) {
Message.error('请输入上传目录');
const handleOk = async () => {
// 验证参数
const error = await formRef.value.validate();
if (error) {
return false;
}
if (!fileList.value.length) {
@@ -120,20 +132,19 @@
}
// 获取上传的文件
const files = fileList.value.map(s => s.file as File);
// 普通上传
await transferManager.sftp.addUpload(props.session as ITerminalSession, parentPath.value, files);
// 清空
handlerClear();
await transferManager.sftp.addUpload(props.session as ITerminalSession, formModel.value.parentPath, files);
handleClose();
return true;
};
// 关闭
const handleClose = () => {
handlerClear();
handleClear();
setVisible(false);
};
// 清空
const handlerClear = () => {
const handleClear = () => {
fileList.value = [];
emits('closed');
};
@@ -142,49 +153,24 @@
<style lang="less" scoped>
@file-size-width: 82px;
@item-label: 104px;
.upload-container {
width: 100%;
padding: 20px;
}
.item-wrapper {
margin-bottom: 24px;
.button-container {
display: flex;
flex-direction: column;
width: 100%;
gap: 12px;
.form-item {
display: flex;
align-items: center;
}
.item-label {
width: @item-label;
padding-right: 8px;
display: flex;
justify-content: flex-end;
user-select: none;
&:after {
content: ':';
margin-left: 2px;
}
}
.item-input {
width: 376px;
}
.form-help {
margin: 4px 0 0 @item-label;
font-size: 12px;
color: var(--color-text-2);
:deep(.arco-upload) {
flex: 1;
}
}
.file-list-uploader {
margin-top: 24px;
margin-top: 16px;
:deep(.arco-upload) {
display: none;
@@ -192,7 +178,7 @@
:deep(.arco-upload-list) {
padding: 0 12px 0 0;
max-height: calc(100vh - 496px);
max-height: calc(100vh - 536px);
overflow-x: hidden;
overflow-y: auto;
}