714
docs/10-模式切换功能.md
Normal file
714
docs/10-模式切换功能.md
Normal file
@@ -0,0 +1,714 @@
|
||||
# 模块10:模式切换功能
|
||||
|
||||
---
|
||||
|
||||
## 🎨 UI设计系统概览
|
||||
|
||||
> **完整设计系统文档请参考:** `UI设计系统.md`
|
||||
|
||||
### 核心设计原则
|
||||
- **现代简约**:界面清晰,层次分明
|
||||
- **专业高效**:减少操作步骤,提升工作效率
|
||||
- **一致性**:统一的视觉语言和交互模式
|
||||
- **可访问性**:符合WCAG 2.1 AA标准
|
||||
|
||||
### 关键设计令牌
|
||||
|
||||
**颜色系统:**
|
||||
- 主色:`#0d6efd`(操作按钮、选中状态)
|
||||
- 成功:`#198754`(连接成功状态)
|
||||
- 危险:`#dc3545`(删除操作、错误提示)
|
||||
- 深灰:`#212529`(导航栏背景)
|
||||
- 浅灰:`#e9ecef`(工具栏背景)
|
||||
|
||||
**字体系统:**
|
||||
- 字体族:系统字体栈(-apple-system, Segoe UI, Roboto等)
|
||||
- 正文:14px,行高1.5
|
||||
- 标题:20-32px,行高1.2-1.4
|
||||
- 小号文字:12px(文件大小、日期等)
|
||||
|
||||
**间距系统:**
|
||||
- 基础单位:8px
|
||||
- 标准间距:16px(1rem)
|
||||
- 组件内边距:8px-16px
|
||||
|
||||
**组件规范:**
|
||||
- 导航栏:高度48px,深色背景
|
||||
- 工具栏:浅灰背景,按钮间距8px
|
||||
- 文件项:最小高度44px,悬停效果150ms
|
||||
- 按钮:圆角4px,过渡150ms
|
||||
|
||||
**交互规范:**
|
||||
- 悬停效果:150ms过渡
|
||||
- 触摸目标:最小44x44px
|
||||
- 键盘导航:Tab、Enter、Delete、F2、F5、Esc
|
||||
- 焦点状态:2px蓝色轮廓
|
||||
|
||||
**响应式断点:**
|
||||
- 移动端:< 768px(双面板垂直排列)
|
||||
- 平板:768px - 1024px
|
||||
- 桌面:> 1024px(标准布局)
|
||||
|
||||
---
|
||||
|
||||
## 10.1 功能概述
|
||||
实现左侧和右侧面板在"本地文件"和"SFTP服务器"模式之间切换,支持同时连接多个SFTP服务器。
|
||||
|
||||
## 10.2 模式状态管理
|
||||
|
||||
### 10.2.1 JavaScript状态管理
|
||||
|
||||
```javascript
|
||||
// 面板状态管理
|
||||
const panelState = {
|
||||
left: {
|
||||
mode: 'local', // 'local' 或 'sftp'
|
||||
sessionId: 'local', // 'local' 或 SFTP会话ID
|
||||
currentPath: '', // 当前路径
|
||||
selectedFiles: [] // 选中的文件
|
||||
},
|
||||
right: {
|
||||
mode: 'local',
|
||||
sessionId: 'local',
|
||||
currentPath: '',
|
||||
selectedFiles: []
|
||||
}
|
||||
};
|
||||
|
||||
// 活跃连接映射
|
||||
const activeConnections = {};
|
||||
|
||||
// 已保存的连接列表
|
||||
let savedConnections = [];
|
||||
```
|
||||
|
||||
### 10.2.2 模式切换逻辑
|
||||
|
||||
```javascript
|
||||
// 模式切换
|
||||
function onModeChange(panelId) {
|
||||
const mode = $(`#${panelId}-mode`).val();
|
||||
panelState[panelId].mode = mode;
|
||||
|
||||
if (mode === 'local') {
|
||||
switchToLocalMode(panelId);
|
||||
} else {
|
||||
switchToSftpMode(panelId);
|
||||
}
|
||||
}
|
||||
|
||||
// 切换到本地模式
|
||||
function switchToLocalMode(panelId) {
|
||||
updateStatus(`正在切换到本地模式...`);
|
||||
|
||||
// 隐藏SFTP连接选择器
|
||||
$(`#${panelId}-connection`).hide();
|
||||
|
||||
// 更新会话ID
|
||||
panelState[panelId].sessionId = 'local';
|
||||
|
||||
// 设置默认路径
|
||||
panelState[panelId].currentPath = getDefaultLocalPath();
|
||||
|
||||
// 加载本地文件列表
|
||||
loadFiles(panelId);
|
||||
|
||||
updateStatus('已切换到本地模式');
|
||||
}
|
||||
|
||||
// 切换到SFTP模式
|
||||
function switchToSftpMode(panelId) {
|
||||
updateStatus(`正在切换到SFTP模式...`);
|
||||
|
||||
// 显示SFTP连接选择器
|
||||
$(`#${panelId}-connection`).show();
|
||||
|
||||
// 加载已保存的连接列表
|
||||
loadSavedConnections(panelId);
|
||||
|
||||
// 检查是否有活跃的SFTP连接
|
||||
const activeSessionId = findActiveSftpSession(panelId);
|
||||
if (activeSessionId) {
|
||||
// 使用已有连接
|
||||
panelState[panelId].sessionId = activeSessionId;
|
||||
$(`#${panelId}-connection`).val(activeSessionId);
|
||||
loadSftpCurrentPath(panelId, activeSessionId);
|
||||
} else {
|
||||
// 提示用户选择或创建连接
|
||||
alert('请选择一个SFTP连接或创建新连接');
|
||||
}
|
||||
|
||||
updateStatus('已切换到SFTP模式');
|
||||
}
|
||||
|
||||
// 获取默认本地路径
|
||||
function getDefaultLocalPath() {
|
||||
return System.getProperty('user.home');
|
||||
}
|
||||
|
||||
// 查找活跃的SFTP会话
|
||||
function findActiveSftpSession(panelId) {
|
||||
const connectionSelect = $(`#${panelId}-connection`);
|
||||
const sessionId = connectionSelect.val();
|
||||
if (sessionId && sessionId !== 'local') {
|
||||
return sessionId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 加载SFTP当前路径
|
||||
function loadSftpCurrentPath(panelId, sessionId) {
|
||||
$.ajax({
|
||||
url: '/api/files/path',
|
||||
method: 'GET',
|
||||
data: {sessionId: sessionId},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
panelState[panelId].currentPath = response.data.path;
|
||||
loadFiles(panelId);
|
||||
} else {
|
||||
alert('获取路径失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 10.3 连接管理UI
|
||||
|
||||
### 10.3.1 连接列表加载
|
||||
|
||||
```javascript
|
||||
// 加载已保存的连接列表
|
||||
function loadSavedConnections(panelId) {
|
||||
$.ajax({
|
||||
url: '/api/connection/list',
|
||||
method: 'GET',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
savedConnections = response.data;
|
||||
updateConnectionSelect(panelId, savedConnections);
|
||||
} else {
|
||||
alert('加载连接列表失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
|
||||
// 更新连接选择器
|
||||
function updateConnectionSelect(panelId, connections) {
|
||||
const select = $(`#${panelId}-connection`);
|
||||
select.empty();
|
||||
|
||||
// 添加选项
|
||||
if (connections.length === 0) {
|
||||
select.append('<option value="">请选择连接</option>');
|
||||
} else {
|
||||
connections.forEach(conn => {
|
||||
const option = $('<option>');
|
||||
option.val(conn.id);
|
||||
option.text(`${conn.name} (${conn.username}@${conn.host})`);
|
||||
select.append(option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 加载活跃连接列表
|
||||
function loadActiveConnections() {
|
||||
$.ajax({
|
||||
url: '/api/connection/active',
|
||||
method: 'GET',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
activeConnections = response.data;
|
||||
updateConnectionPanels();
|
||||
} else {
|
||||
console.error('加载活跃连接失败:', response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
|
||||
// 更新连接面板
|
||||
function updateConnectionPanels() {
|
||||
Object.keys(panelState).forEach(panelId => {
|
||||
if (panelState[panelId].mode === 'sftp') {
|
||||
updateConnectionSelect(panelId, savedConnections);
|
||||
// 选中当前活跃的连接
|
||||
const currentSessionId = panelState[panelId].sessionId;
|
||||
if (currentSessionId !== 'local') {
|
||||
// 找到对应的连接ID并选中
|
||||
Object.entries(activeConnections).forEach(([sessionId, conn]) => {
|
||||
if (sessionId === currentSessionId) {
|
||||
$(`#${panelId}-connection`).val(conn.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 10.3.2 连接管理对话框
|
||||
|
||||
```javascript
|
||||
// 显示连接管理对话框
|
||||
function showConnectionDialog() {
|
||||
$('#connectionModal').modal('show');
|
||||
loadConnectionList();
|
||||
}
|
||||
|
||||
// 加载连接列表
|
||||
function loadConnectionList() {
|
||||
const connectionList = $('#connection-list');
|
||||
connectionList.empty();
|
||||
|
||||
if (savedConnections.length === 0) {
|
||||
connectionList.html('<p class="text-muted text-center">暂无保存的连接</p>');
|
||||
return;
|
||||
}
|
||||
|
||||
savedConnections.forEach(conn => {
|
||||
const item = $(`
|
||||
<div class="connection-item" data-id="${conn.id}">
|
||||
<div>
|
||||
<div class="connection-name">${conn.name}</div>
|
||||
<div class="connection-info">${conn.username}@${conn.host}:${conn.port}</div>
|
||||
</div>
|
||||
<div class="connection-actions">
|
||||
<button class="btn btn-sm btn-primary" onclick="connectToSftp(${conn.id})">连接</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteConnection(${conn.id})">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
connectionList.append(item);
|
||||
});
|
||||
}
|
||||
|
||||
// 显示添加连接对话框
|
||||
function showAddConnectionDialog() {
|
||||
$('#connectionModal').modal('hide');
|
||||
$('#addConnectionModal').modal('show');
|
||||
$('#connection-form')[0].reset();
|
||||
}
|
||||
|
||||
// 保存连接
|
||||
function saveConnection() {
|
||||
const formData = $('#connection-form').serializeObject();
|
||||
|
||||
$.ajax({
|
||||
url: '/api/connection/save',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(formData),
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert('连接保存成功');
|
||||
$('#addConnectionModal').modal('hide');
|
||||
$('#connectionModal').modal('show');
|
||||
loadSavedConnections('left');
|
||||
loadSavedConnections('right');
|
||||
} else {
|
||||
alert('保存失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
|
||||
// 删除连接
|
||||
function deleteConnection(id) {
|
||||
if (confirm('确定要删除此连接吗?')) {
|
||||
$.ajax({
|
||||
url: '/api/connection/' + id,
|
||||
method: 'DELETE',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert('删除成功');
|
||||
loadConnectionList();
|
||||
loadSavedConnections('left');
|
||||
loadSavedConnections('right');
|
||||
} else {
|
||||
alert('删除失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 序列化表单为对象
|
||||
$.fn.serializeObject = function() {
|
||||
const o = {};
|
||||
const a = this.serializeArray();
|
||||
$.each(a, function() {
|
||||
if (o[this.name] !== undefined) {
|
||||
if (!o[this.name].push) {
|
||||
o[this.name] = [o[this.name]];
|
||||
}
|
||||
o[this.name].push(this.value || '');
|
||||
} else {
|
||||
o[this.name] = this.value || '';
|
||||
}
|
||||
});
|
||||
return o;
|
||||
};
|
||||
```
|
||||
|
||||
### 10.3.3 SFTP连接
|
||||
|
||||
```javascript
|
||||
// 连接到SFTP服务器
|
||||
function connectToSftp(connectionId) {
|
||||
// 查找连接配置
|
||||
const connection = savedConnections.find(c => c.id === connectionId);
|
||||
if (!connection) {
|
||||
alert('连接不存在');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否已连接
|
||||
const existingSession = findSessionByConnectionId(connectionId);
|
||||
if (existingSession) {
|
||||
alert('该连接已在使用中');
|
||||
return;
|
||||
}
|
||||
|
||||
updateStatus(`正在连接到 ${connection.name}...`);
|
||||
|
||||
$.ajax({
|
||||
url: '/api/connection/connect',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(connection),
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
const sessionId = response.data;
|
||||
|
||||
// 更新活跃连接列表
|
||||
activeConnections[sessionId] = connection;
|
||||
|
||||
// 更新选择器
|
||||
$(`#left-connection`).val(connectionId);
|
||||
$(`#right-connection`).val(connectionId);
|
||||
|
||||
// 更新面板状态
|
||||
updatePanelStateWithConnection(sessionId, connection);
|
||||
|
||||
// 加载活跃连接到选择器
|
||||
updateActiveConnectionOptions();
|
||||
|
||||
alert('连接成功');
|
||||
updateStatus('已连接到 ' + connection.name);
|
||||
} else {
|
||||
alert('连接失败: ' + response.message);
|
||||
updateStatus('连接失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
alert('连接失败: ' + error);
|
||||
updateStatus('连接失败: ' + error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 查找会话
|
||||
function findSessionByConnectionId(connectionId) {
|
||||
return Object.entries(activeConnections).find(([sessionId, conn]) => conn.id === connectionId);
|
||||
}
|
||||
|
||||
// 更新面板状态
|
||||
function updatePanelStateWithConnection(sessionId, connection) {
|
||||
// 更新左侧面板(如果是SFTP模式)
|
||||
if (panelState.left.mode === 'sftp') {
|
||||
panelState.left.sessionId = sessionId;
|
||||
$(`#left-connection`).val(connection.id);
|
||||
loadSftpCurrentPath('left', sessionId);
|
||||
}
|
||||
|
||||
// 更新右侧面板(如果是SFTP模式)
|
||||
if (panelState.right.mode === 'sftp') {
|
||||
panelState.right.sessionId = sessionId;
|
||||
$(`#right-connection`).val(connection.id);
|
||||
loadSftpCurrentPath('right', sessionId);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新活跃连接选项
|
||||
function updateActiveConnectionOptions() {
|
||||
Object.keys(panelState).forEach(panelId => {
|
||||
if (panelState[panelId].mode === 'sftp') {
|
||||
const select = $(`#${panelId}-connection`);
|
||||
select.empty();
|
||||
|
||||
// 添加选项
|
||||
if (Object.keys(activeConnections).length === 0) {
|
||||
select.append('<option value="">请先连接</option>');
|
||||
} else {
|
||||
Object.entries(activeConnections).forEach(([sessionId, conn]) => {
|
||||
const option = $('<option>');
|
||||
option.val(sessionId);
|
||||
option.text(`${conn.name} (${conn.username}@${conn.host})`);
|
||||
select.append(option);
|
||||
});
|
||||
}
|
||||
|
||||
// 选中的是当前会话
|
||||
if (panelState[panelId].sessionId !== 'local') {
|
||||
select.val(panelState[panelId].sessionId);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 连接切换
|
||||
function onConnectionChange(panelId) {
|
||||
const sessionId = $(`#${panelId}-connection`).val();
|
||||
if (!sessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
panelState[panelId].sessionId = sessionId;
|
||||
loadSftpCurrentPath(panelId, sessionId);
|
||||
}
|
||||
```
|
||||
|
||||
## 10.4 连接状态显示
|
||||
|
||||
### 10.4.1 连接状态指示器
|
||||
|
||||
```html
|
||||
<!-- 在面板头部添加状态指示器 -->
|
||||
<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="connected"></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')">
|
||||
</select>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 10.4.2 状态样式
|
||||
|
||||
```css
|
||||
/* 连接状态 */
|
||||
.connection-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.status-dot[data-status="connected"] {
|
||||
background-color: #28a745;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.connection-status.connected .status-text {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.connection-status.disconnected .status-text {
|
||||
color: #dc3545;
|
||||
}
|
||||
|
||||
.connection-status.connecting .status-text {
|
||||
color: #ffc107;
|
||||
}
|
||||
```
|
||||
|
||||
### 10.4.3 状态更新逻辑
|
||||
|
||||
```javascript
|
||||
// 更新连接状态显示
|
||||
function updateConnectionStatus(panelId, status, text) {
|
||||
const statusDiv = $(`#${panelId}-status`);
|
||||
if (statusDiv.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const statusDot = statusDiv.find('.status-dot');
|
||||
const statusText = statusDiv.find('.status-text');
|
||||
|
||||
statusDiv.removeClass('connected disconnected connecting');
|
||||
statusDiv.addClass(status);
|
||||
|
||||
statusDot.attr('data-status', status);
|
||||
statusText.text(text);
|
||||
}
|
||||
|
||||
// 显示连接状态
|
||||
function showConnectionStatus(panelId, sessionId) {
|
||||
const statusDiv = $(`#${panelId}-status`);
|
||||
if (statusDiv.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sessionId === 'local') {
|
||||
statusDiv.hide();
|
||||
} else {
|
||||
statusDiv.show();
|
||||
const connection = activeConnections[sessionId];
|
||||
if (connection) {
|
||||
updateConnectionStatus(panelId, 'connected', `已连接: ${connection.name}`);
|
||||
} else {
|
||||
updateConnectionStatus(panelId, 'disconnected', '未连接');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新模式切换时的状态
|
||||
function onModeChange(panelId) {
|
||||
const mode = $(`#${panelId}-mode`).val();
|
||||
panelState[panelId].mode = mode;
|
||||
|
||||
if (mode === 'local') {
|
||||
switchToLocalMode(panelId);
|
||||
showConnectionStatus(panelId, 'local');
|
||||
} else {
|
||||
switchToSftpMode(panelId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 10.5 断开连接
|
||||
|
||||
```javascript
|
||||
// 断开SFTP连接
|
||||
function disconnectFromSftp(sessionId) {
|
||||
updateStatus('正在断开连接...');
|
||||
|
||||
$.ajax({
|
||||
url: '/api/connection/disconnect',
|
||||
method: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({sessionId: sessionId}),
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
// 从活跃连接中移除
|
||||
delete activeConnections[sessionId];
|
||||
|
||||
// 更新面板状态
|
||||
updatePanelsAfterDisconnect(sessionId);
|
||||
|
||||
// 更新连接选项
|
||||
updateActiveConnectionOptions();
|
||||
|
||||
alert('已断开连接');
|
||||
updateStatus('连接已断开');
|
||||
} else {
|
||||
alert('断开连接失败: ' + response.message);
|
||||
}
|
||||
},
|
||||
error: handleError
|
||||
});
|
||||
}
|
||||
|
||||
// 更新断开连接后的面板
|
||||
function updatePanelsAfterDisconnect(sessionId) {
|
||||
Object.keys(panelState).forEach(panelId => {
|
||||
if (panelState[panelId].sessionId === sessionId) {
|
||||
panelState[panelId].sessionId = 'local';
|
||||
panelState[panelId].mode = 'local';
|
||||
$(`#${panelId}-mode`).val('local');
|
||||
onModeChange(panelId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 在连接项中添加断开按钮
|
||||
function loadConnectionList() {
|
||||
const connectionList = $('#connection-list');
|
||||
connectionList.empty();
|
||||
|
||||
if (savedConnections.length === 0) {
|
||||
connectionList.html('<p class="text-muted text-center">暂无保存的连接</p>');
|
||||
return;
|
||||
}
|
||||
|
||||
savedConnections.forEach(conn => {
|
||||
// 查找是否有活跃会话
|
||||
const activeSession = findSessionByConnectionId(conn.id);
|
||||
|
||||
const item = $(`
|
||||
<div class="connection-item" data-id="${conn.id}">
|
||||
<div>
|
||||
<div class="connection-name">${conn.name}</div>
|
||||
<div class="connection-info">${conn.username}@${conn.host}:${conn.port}</div>
|
||||
</div>
|
||||
<div class="connection-actions">
|
||||
${activeSession ?
|
||||
'<button class="btn btn-sm btn-warning" onclick="disconnectFromSftp(\'' +
|
||||
activeSession[0] + '\')">断开</button>' :
|
||||
'<button class="btn btn-sm btn-primary" onclick="connectToSftp(' +
|
||||
conn.id + ')">连接</button>'
|
||||
}
|
||||
<button class="btn btn-sm btn-danger" onclick="deleteConnection(${conn.id})">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
connectionList.append(item);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. **更新app.js**:添加模式切换逻辑
|
||||
|
||||
2. **更新index.html**:添加连接管理对话框和状态指示器
|
||||
|
||||
3. **测试功能**:
|
||||
- 测试本地/SFTP模式切换
|
||||
- 测试连接管理功能
|
||||
- 测试多连接管理
|
||||
- 测试连接状态显示
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **状态同步**:确保前后端状态同步
|
||||
2. **错误处理**:连接失败时的友好提示
|
||||
3. **会话管理**:正确管理多个SFTP会话
|
||||
4. **性能优化**:避免频繁刷新连接列表
|
||||
5. **用户体验**:提供清晰的状态反馈
|
||||
|
||||
## 下一步
|
||||
|
||||
完成模块10后,继续模块11:API接口设计规范
|
||||
Reference in New Issue
Block a user