@@ -0,0 +1,50 @@
|
||||
# 生产环境配置
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
context-path: /sftp-manager
|
||||
tomcat:
|
||||
max-threads: 200
|
||||
accept-count: 100
|
||||
|
||||
spring:
|
||||
datasource:
|
||||
url: jdbc:h2:file:./data/sftp-manager
|
||||
username: ${DB_USERNAME:sa}
|
||||
password: ${DB_PASSWORD:}
|
||||
hikari:
|
||||
maximum-pool-size: 10
|
||||
minimum-idle: 5
|
||||
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
show-sql: false
|
||||
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 500MB
|
||||
max-request-size: 2GB
|
||||
|
||||
app:
|
||||
sftp:
|
||||
session-timeout: 60000
|
||||
connection-timeout: 30000
|
||||
max-retries: 5
|
||||
|
||||
# Actuator 生产环境暴露健康与指标
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info,metrics
|
||||
endpoint:
|
||||
health:
|
||||
show-details: always
|
||||
|
||||
logging:
|
||||
file:
|
||||
name: ./logs/sftp-manager.log
|
||||
level:
|
||||
root: INFO
|
||||
com.sftp.manager: INFO
|
||||
@@ -0,0 +1,56 @@
|
||||
server:
|
||||
port: 8080 # 服务端口
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: sftp-manager
|
||||
|
||||
# H2数据库配置
|
||||
h2:
|
||||
console:
|
||||
enabled: true # 启用H2控制台
|
||||
path: /h2-console # 控制台访问路径
|
||||
datasource:
|
||||
url: jdbc:h2:file:./data/sftp-manager # 数据库文件路径
|
||||
driver-class-name: org.h2.Driver
|
||||
username: sa
|
||||
password:
|
||||
|
||||
# JPA配置
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update # 自动更新表结构
|
||||
show-sql: true # 显示SQL语句
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: true # 格式化SQL输出
|
||||
|
||||
# 文件上传配置
|
||||
servlet:
|
||||
multipart:
|
||||
enabled: true
|
||||
max-file-size: 100MB # 单文件最大100MB
|
||||
max-request-size: 500MB # 总请求最大500MB
|
||||
|
||||
# 自定义配置
|
||||
app:
|
||||
sftp:
|
||||
session-timeout: 30000 # SFTP会话超时时间(ms)
|
||||
connection-timeout: 10000 # 连接超时时间(ms)
|
||||
max-retries: 3 # 连接失败重试次数
|
||||
|
||||
# Actuator 监控端点(开发环境仅暴露 health、info)
|
||||
management:
|
||||
endpoints:
|
||||
web:
|
||||
exposure:
|
||||
include: health,info
|
||||
endpoint:
|
||||
health:
|
||||
show-details: when-authorized
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.sftp.manager: DEBUG
|
||||
org.hibernate.SQL: DEBUG
|
||||
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
|
||||
@@ -0,0 +1,373 @@
|
||||
/* SFTP Manager 自定义样式 */
|
||||
/* 全局样式 */
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
background-color: #f5f5f5;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 应用容器 */
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100vh;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 导航栏 */
|
||||
.navbar {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 16px;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* 工具栏 */
|
||||
.toolbar {
|
||||
flex-shrink: 0;
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
/* 上传进度条 */
|
||||
.upload-progress {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.upload-progress .progress {
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.upload-progress .progress-bar {
|
||||
transition: width 0.3s ease;
|
||||
font-size: 11px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
background-color: #0d6efd;
|
||||
}
|
||||
|
||||
/* 双面板容器 */
|
||||
.panels-container {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 面板 */
|
||||
.panel {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-right: 1px solid #dee2e6;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.panel:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* 拖拽上传效果 */
|
||||
.panel.drag-over {
|
||||
background-color: #e7f3ff;
|
||||
border: 2px dashed #0d6efd;
|
||||
}
|
||||
|
||||
/* 面板头部 */
|
||||
.panel-header {
|
||||
flex-shrink: 0;
|
||||
padding: 8px;
|
||||
background-color: #e9ecef;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.panel-mode {
|
||||
flex: 1;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.connection-select {
|
||||
flex: 2;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
/* 连接状态指示器 */
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.status-dot[data-status="connected"] {
|
||||
background-color: #198754;
|
||||
}
|
||||
|
||||
.status-dot[data-status="disconnected"] {
|
||||
background-color: #dc3545;
|
||||
}
|
||||
|
||||
.status-dot[data-status="connecting"] {
|
||||
background-color: #ffc107;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
.connection-status .status-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.connection-status.connected .status-text {
|
||||
color: #198754;
|
||||
}
|
||||
|
||||
.connection-status.disconnected .status-text {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.connection-status.connecting .status-text {
|
||||
color: #ffc107;
|
||||
}
|
||||
|
||||
/* 路径栏 */
|
||||
.path-bar {
|
||||
flex-shrink: 0;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.path-input {
|
||||
flex: 1;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 文件列表 */
|
||||
.file-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
/* 文件列表拖拽悬停效果 */
|
||||
.file-list.drag-over {
|
||||
background-color: #e7f3ff;
|
||||
outline: 2px dashed #0d6efd;
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
/* 文件项拖拽中 */
|
||||
.file-item.dragging {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* 文件项 */
|
||||
.file-item {
|
||||
padding: 8px 12px;
|
||||
min-height: 44px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
transition: background-color 0.15s;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.file-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.file-item.selected {
|
||||
background-color: #0d6efd;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.file-icon {
|
||||
margin-right: 10px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
margin-left: 10px;
|
||||
min-width: 80px;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.file-date {
|
||||
margin-left: 10px;
|
||||
min-width: 140px;
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 选中状态下的文件大小和日期 */
|
||||
.file-item.selected .file-size,
|
||||
.file-item.selected .file-date {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
/* 状态栏 */
|
||||
.status-bar {
|
||||
flex-shrink: 0;
|
||||
padding: 4px 16px;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 上下文菜单 */
|
||||
.context-menu {
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
z-index: 1000;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
padding: 8px 12px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.menu-item:hover {
|
||||
background-color: #0d6efd;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 连接列表 */
|
||||
.connection-item {
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.connection-item:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.connection-name {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.connection-info {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.connection-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.connection-actions button {
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 新建文件夹项(内联编辑) */
|
||||
.new-folder {
|
||||
background-color: #e7f3ff;
|
||||
}
|
||||
|
||||
.new-folder-input {
|
||||
width: 100%;
|
||||
padding: 2px 4px;
|
||||
border: 1px solid #0d6efd;
|
||||
outline: none;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.panels-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.panel {
|
||||
height: 50%;
|
||||
border-right: none;
|
||||
border-bottom: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.file-size,
|
||||
.file-date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 576px) {
|
||||
.toolbar button {
|
||||
padding: 2px 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.file-item {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SFTP文件管理器</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<nav class="navbar navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand mb-0 h1">SFTP文件管理器</span>
|
||||
<div>
|
||||
<button class="btn btn-primary btn-sm" onclick="showConnectionDialog()">连接管理</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="toolbar bg-light border-bottom">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="uploadFiles()">上传</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="downloadFiles()">下载</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="transferFiles()">传输到右侧</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteFiles()">删除</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="showRenameDialog()">重命名</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="showMkdirDialog()">新建文件夹</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="btn-show-hidden" onclick="toggleShowHidden()" title="切换是否显示隐藏文件">显示隐藏文件</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="refreshPanels()">刷新</button>
|
||||
</div>
|
||||
<!-- 文件上传输入框(隐藏) -->
|
||||
<input type="file" id="file-input" multiple style="display:none">
|
||||
<!-- 上传进度条 -->
|
||||
<div class="upload-progress" id="upload-progress" style="display:none;">
|
||||
<div class="progress" style="height: 20px; margin-left: 10px; width: 200px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%">0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 双面板区域 -->
|
||||
<div class="panels-container">
|
||||
<!-- 左面板 -->
|
||||
<div class="panel" id="left-panel">
|
||||
<div class="panel-header">
|
||||
<select class="form-select form-select-sm panel-mode" id="left-mode" onchange="onModeChange('left')">
|
||||
<option value="local">本地文件</option>
|
||||
<option value="sftp">SFTP服务器</option>
|
||||
</select>
|
||||
<div class="connection-status" id="left-status" style="display:none;">
|
||||
<span class="status-dot" data-status="disconnected"></span>
|
||||
<span class="status-text">未连接</span>
|
||||
</div>
|
||||
<select class="form-select form-select-sm connection-select" id="left-connection" style="display:none;" onchange="onConnectionChange('left')">
|
||||
<option value="">选择连接</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="path-bar">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="goUp('left')">↑</button>
|
||||
<input type="text" class="form-control form-control-sm path-input" id="left-path" readonly>
|
||||
</div>
|
||||
<div class="file-list" id="left-file-list">
|
||||
<div class="text-center text-muted p-3">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右面板 -->
|
||||
<div class="panel" id="right-panel">
|
||||
<div class="panel-header">
|
||||
<select class="form-select form-select-sm panel-mode" id="right-mode" onchange="onModeChange('right')">
|
||||
<option value="local">本地文件</option>
|
||||
<option value="sftp">SFTP服务器</option>
|
||||
</select>
|
||||
<div class="connection-status" id="right-status" style="display:none;">
|
||||
<span class="status-dot" data-status="disconnected"></span>
|
||||
<span class="status-text">未连接</span>
|
||||
</div>
|
||||
<select class="form-select form-select-sm connection-select" id="right-connection" style="display:none;" onchange="onConnectionChange('right')">
|
||||
<option value="">选择连接</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="path-bar">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="goUp('right')">↑</button>
|
||||
<input type="text" class="form-control form-control-sm path-input" id="right-path" readonly>
|
||||
</div>
|
||||
<div class="file-list" id="right-file-list">
|
||||
<div class="text-center text-muted p-3">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar bg-light border-top">
|
||||
<span id="status-text">就绪</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 连接管理对话框 -->
|
||||
<div class="modal fade" id="connectionModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">连接管理</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-primary" onclick="showAddConnectionDialog()">添加连接</button>
|
||||
</div>
|
||||
<div class="connection-list" id="connection-list">
|
||||
<!-- 连接列表动态生成 -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加连接对话框 -->
|
||||
<div class="modal fade" id="addConnectionModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">添加SFTP连接</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="connection-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">连接名称</label>
|
||||
<input type="text" class="form-control" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">主机地址</label>
|
||||
<input type="text" class="form-control" name="host" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">端口</label>
|
||||
<input type="number" class="form-control" name="port" value="22" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">用户名</label>
|
||||
<input type="text" class="form-control" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">密码</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">私钥路径(可选)</label>
|
||||
<input type="text" class="form-control" name="privateKeyPath">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">私钥密码(可选)</label>
|
||||
<input type="password" class="form-control" name="passPhrase">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveConnection()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,164 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SFTP文件管理器</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<nav class="navbar navbar-dark bg-dark">
|
||||
<div class="container-fluid">
|
||||
<span class="navbar-brand mb-0 h1">SFTP文件管理器</span>
|
||||
<div>
|
||||
<button class="btn btn-primary btn-sm" onclick="showConnectionDialog()">连接管理</button>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="toolbar bg-light border-bottom">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="uploadFiles()">上传</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="downloadFiles()">下载</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary" onclick="transferFiles()">传输到右侧</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" onclick="deleteFiles()">删除</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="showRenameDialog()">重命名</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="showMkdirDialog()">新建文件夹</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" id="btn-show-hidden" onclick="toggleShowHidden()" title="切换是否显示隐藏文件">显示隐藏文件</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="refreshPanels()">刷新</button>
|
||||
</div>
|
||||
<input type="file" id="file-input" multiple style="display:none">
|
||||
<div class="upload-progress" id="upload-progress" style="display:none;">
|
||||
<div class="progress" style="height: 20px; margin-left: 10px; width: 200px;">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%">0%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 双面板区域 -->
|
||||
<div class="panels-container">
|
||||
<!-- 左面板 -->
|
||||
<div class="panel" id="left-panel">
|
||||
<div class="panel-header">
|
||||
<select class="form-select form-select-sm panel-mode" id="left-mode" onchange="onModeChange('left')">
|
||||
<option value="local">本地文件</option>
|
||||
<option value="sftp">SFTP服务器</option>
|
||||
</select>
|
||||
<select class="form-select form-select-sm connection-select" id="left-connection" style="display:none;" onchange="onConnectionChange('left')">
|
||||
<option value="">选择连接</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="path-bar">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="goUp('left')">↑</button>
|
||||
<input type="text" class="form-control form-control-sm path-input" id="left-path" readonly>
|
||||
</div>
|
||||
<div class="file-list" id="left-file-list">
|
||||
<div class="text-center text-muted p-3">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右面板 -->
|
||||
<div class="panel" id="right-panel">
|
||||
<div class="panel-header">
|
||||
<select class="form-select form-select-sm panel-mode" id="right-mode" onchange="onModeChange('right')">
|
||||
<option value="local">本地文件</option>
|
||||
<option value="sftp">SFTP服务器</option>
|
||||
</select>
|
||||
<select class="form-select form-select-sm connection-select" id="right-connection" style="display:none;" onchange="onConnectionChange('right')">
|
||||
<option value="">选择连接</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="path-bar">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="goUp('right')">↑</button>
|
||||
<input type="text" class="form-control form-control-sm path-input" id="right-path" readonly>
|
||||
</div>
|
||||
<div class="file-list" id="right-file-list">
|
||||
<div class="text-center text-muted p-3">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 状态栏 -->
|
||||
<div class="status-bar bg-light border-top">
|
||||
<span id="status-text">就绪</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 连接管理对话框 -->
|
||||
<div class="modal fade" id="connectionModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">连接管理</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<button class="btn btn-primary" onclick="showAddConnectionDialog()">添加连接</button>
|
||||
</div>
|
||||
<div class="connection-list" id="connection-list"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 添加连接对话框 -->
|
||||
<div class="modal fade" id="addConnectionModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">添加SFTP连接</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="connection-form">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">连接名称</label>
|
||||
<input type="text" class="form-control" name="name" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">主机地址</label>
|
||||
<input type="text" class="form-control" name="host" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">端口</label>
|
||||
<input type="number" class="form-control" name="port" value="22" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">用户名</label>
|
||||
<input type="text" class="form-control" name="username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">密码</label>
|
||||
<input type="password" class="form-control" name="password">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">私钥路径(可选)</label>
|
||||
<input type="text" class="form-control" name="privateKeyPath">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">私钥密码(可选)</label>
|
||||
<input type="password" class="form-control" name="passPhrase">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary" onclick="saveConnection()">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user