新增录制轨迹文件记录
This commit is contained in:
parent
bd13a5aeb2
commit
dae78fffc3
@ -8,3 +8,130 @@
|
|||||||
background-color: #2196f3;
|
background-color: #2196f3;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 轨迹管理区域样式 */
|
||||||
|
.path-management {
|
||||||
|
margin-top: 30px;
|
||||||
|
padding: 20px;
|
||||||
|
background: linear-gradient(145deg, #e6e6e6, #ffffff);
|
||||||
|
border-radius: 15px;
|
||||||
|
box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.1), -10px -10px 20px rgba(255, 255, 255, 0.7);
|
||||||
|
width: 100%;
|
||||||
|
max-width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-management h3 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-input {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-input input {
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
box-shadow: inset 5px 5px 10px rgba(0, 0, 0, 0.1), inset -5px -5px 10px rgba(255, 255, 255, 0.7);
|
||||||
|
width: 200px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
background: linear-gradient(145deg, #4CAF50, #45a049);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 10px 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1), -5px -5px 10px rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 7px 7px 14px rgba(0, 0, 0, 0.15), -7px -7px 14px rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.1), -3px -3px 6px rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-list h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
color: #555;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
max-height: 200px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList li {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 5px 0;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.1), -3px -3px 6px rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList li button {
|
||||||
|
background: linear-gradient(145deg, #f44336, #da190b);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList li button:hover {
|
||||||
|
background: linear-gradient(145deg, #e53935, #c62828);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList li button.load-btn {
|
||||||
|
background: linear-gradient(145deg, #2196F3, #1976D2);
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pathList li button.load-btn:hover {
|
||||||
|
background: linear-gradient(145deg, #1E88E5, #1565C0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 响应式设计 - 轨迹管理 */
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.path-input {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-input input {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path-management {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -13,11 +13,152 @@ window.addEventListener('DOMContentLoaded', function() {
|
|||||||
const playbackBtn = document.getElementById('playbackBtn');
|
const playbackBtn = document.getElementById('playbackBtn');
|
||||||
const status = document.getElementById('status');
|
const status = document.getElementById('status');
|
||||||
|
|
||||||
|
// 获取轨迹管理相关元素
|
||||||
|
const pathNameInput = document.getElementById('pathName');
|
||||||
|
const savePathBtn = document.getElementById('savePathBtn');
|
||||||
|
const pathList = document.getElementById('pathList');
|
||||||
|
|
||||||
// 调试信息
|
// 调试信息
|
||||||
console.log('Record.js loaded');
|
console.log('Record.js loaded');
|
||||||
console.log('recordBtn:', recordBtn);
|
console.log('recordBtn:', recordBtn);
|
||||||
console.log('playbackBtn:', playbackBtn);
|
console.log('playbackBtn:', playbackBtn);
|
||||||
console.log('status:', status);
|
console.log('status:', status);
|
||||||
|
console.log('pathNameInput:', pathNameInput);
|
||||||
|
console.log('savePathBtn:', savePathBtn);
|
||||||
|
console.log('pathList:', pathList);
|
||||||
|
|
||||||
|
// 列出已保存的轨迹
|
||||||
|
function listPaths() {
|
||||||
|
fetch('/list_paths')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
// 清空路径列表
|
||||||
|
pathList.innerHTML = '';
|
||||||
|
|
||||||
|
// 添加路径到列表
|
||||||
|
data.paths.forEach(path => {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
li.innerHTML = `
|
||||||
|
<span>${path}</span>
|
||||||
|
<div>
|
||||||
|
<button class="load-btn" data-path="${path}">加载</button>
|
||||||
|
<button class="delete-btn" data-path="${path}">删除</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
pathList.appendChild(li);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 添加加载和删除按钮的事件监听器
|
||||||
|
document.querySelectorAll('.load-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const pathName = this.getAttribute('data-path');
|
||||||
|
loadPath(pathName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.querySelectorAll('.delete-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', function() {
|
||||||
|
const pathName = this.getAttribute('data-path');
|
||||||
|
deletePath(pathName);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
status.innerHTML = `<p>错误: ${data.message}</p>`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerHTML = `<p>通信错误: ${error.message}</p>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存轨迹
|
||||||
|
function savePath() {
|
||||||
|
const pathName = pathNameInput.value.trim();
|
||||||
|
if (!pathName) {
|
||||||
|
status.innerHTML = '<p>请输入轨迹名称</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window.recordedActions.length === 0) {
|
||||||
|
status.innerHTML = '<p>没有可保存的轨迹</p>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch('/save_path', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ name: pathName, actions: window.recordedActions })
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
status.innerHTML = `<p>${data.message}</p>`;
|
||||||
|
// 清空输入框
|
||||||
|
pathNameInput.value = '';
|
||||||
|
// 更新轨迹列表
|
||||||
|
listPaths();
|
||||||
|
} else {
|
||||||
|
status.innerHTML = `<p>错误: ${data.message}</p>`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerHTML = `<p>通信错误: ${error.message}</p>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载轨迹
|
||||||
|
function loadPath(pathName) {
|
||||||
|
fetch(`/load_path?name=${pathName}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
window.recordedActions = data.data.actions;
|
||||||
|
status.innerHTML = `<p>轨迹 ${pathName} 加载成功,共 ${window.recordedActions.length} 个操作</p>`;
|
||||||
|
} else {
|
||||||
|
status.innerHTML = `<p>错误: ${data.message}</p>`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerHTML = `<p>通信错误: ${error.message}</p>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除轨迹
|
||||||
|
function deletePath(pathName) {
|
||||||
|
if (confirm(`确定要删除轨迹 ${pathName} 吗?`)) {
|
||||||
|
fetch('/delete_path', {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ name: pathName })
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (data.status === 'success') {
|
||||||
|
status.innerHTML = `<p>${data.message}</p>`;
|
||||||
|
// 更新轨迹列表
|
||||||
|
listPaths();
|
||||||
|
} else {
|
||||||
|
status.innerHTML = `<p>错误: ${data.message}</p>`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
status.innerHTML = `<p>通信错误: ${error.message}</p>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存轨迹按钮点击事件
|
||||||
|
if (savePathBtn) {
|
||||||
|
savePathBtn.addEventListener('click', savePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面加载时列出已保存的轨迹
|
||||||
|
listPaths();
|
||||||
|
|
||||||
// 录制按钮点击事件 - 支持鼠标和触摸事件
|
// 录制按钮点击事件 - 支持鼠标和触摸事件
|
||||||
function toggleRecording() {
|
function toggleRecording() {
|
||||||
|
|||||||
@ -47,6 +47,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 轨迹管理区域 -->
|
||||||
|
<div class="path-management">
|
||||||
|
<h3>轨迹管理</h3>
|
||||||
|
<div class="path-input">
|
||||||
|
<input type="text" id="pathName" placeholder="输入轨迹名称(如:test1)">
|
||||||
|
<button class="btn btn-save" id="savePathBtn">保存轨迹</button>
|
||||||
|
</div>
|
||||||
|
<div class="path-list">
|
||||||
|
<h4>已保存轨迹</h4>
|
||||||
|
<ul id="pathList"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 状态显示区域 -->
|
<!-- 状态显示区域 -->
|
||||||
<div class="status" id="status">
|
<div class="status" id="status">
|
||||||
<p>就绪</p>
|
<p>就绪</p>
|
||||||
|
|||||||
@ -2,6 +2,7 @@ from flask import Flask, send_file, request, jsonify, send_from_directory
|
|||||||
import motor
|
import motor
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
@ -87,5 +88,85 @@ def control():
|
|||||||
print(f"控制出错: {e}")
|
print(f"控制出错: {e}")
|
||||||
return jsonify({'status': 'error', 'message': f'控制出错: {e}'})
|
return jsonify({'status': 'error', 'message': f'控制出错: {e}'})
|
||||||
|
|
||||||
|
# 保存轨迹路由
|
||||||
|
@app.route('/save_path', methods=['POST'])
|
||||||
|
def save_path():
|
||||||
|
data = request.get_json()
|
||||||
|
path_name = data.get('name')
|
||||||
|
recorded_actions = data.get('actions')
|
||||||
|
|
||||||
|
if not path_name or not recorded_actions:
|
||||||
|
return jsonify({'status': 'error', 'message': '路径名称和轨迹数据不能为空'})
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 确保Path目录存在
|
||||||
|
os.makedirs('Path', exist_ok=True)
|
||||||
|
|
||||||
|
# 保存为JSON文件
|
||||||
|
file_path = os.path.join('Path', f'{path_name}.json')
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump({'name': path_name, 'actions': recorded_actions}, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
return jsonify({'status': 'success', 'message': '轨迹保存成功'})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"保存轨迹出错: {e}")
|
||||||
|
return jsonify({'status': 'error', 'message': f'保存轨迹出错: {e}'})
|
||||||
|
|
||||||
|
# 列出轨迹路由
|
||||||
|
@app.route('/list_paths', methods=['GET'])
|
||||||
|
def list_paths():
|
||||||
|
try:
|
||||||
|
# 确保Path目录存在
|
||||||
|
os.makedirs('Path', exist_ok=True)
|
||||||
|
|
||||||
|
# 列出所有轨迹文件
|
||||||
|
path_files = [f.replace('.json', '') for f in os.listdir('Path') if f.endswith('.json')]
|
||||||
|
|
||||||
|
return jsonify({'status': 'success', 'paths': path_files})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"列出轨迹出错: {e}")
|
||||||
|
return jsonify({'status': 'error', 'message': f'列出轨迹出错: {e}'})
|
||||||
|
|
||||||
|
# 加载轨迹路由
|
||||||
|
@app.route('/load_path', methods=['GET'])
|
||||||
|
def load_path():
|
||||||
|
path_name = request.args.get('name')
|
||||||
|
|
||||||
|
if not path_name:
|
||||||
|
return jsonify({'status': 'error', 'message': '路径名称不能为空'})
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_path = os.path.join('Path', f'{path_name}.json')
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return jsonify({'status': 'error', 'message': '轨迹文件不存在'})
|
||||||
|
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
data = json.load(f)
|
||||||
|
|
||||||
|
return jsonify({'status': 'success', 'data': data})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"加载轨迹出错: {e}")
|
||||||
|
return jsonify({'status': 'error', 'message': f'加载轨迹出错: {e}'})
|
||||||
|
|
||||||
|
# 删除轨迹路由
|
||||||
|
@app.route('/delete_path', methods=['DELETE'])
|
||||||
|
def delete_path():
|
||||||
|
data = request.get_json()
|
||||||
|
path_name = data.get('name')
|
||||||
|
|
||||||
|
if not path_name:
|
||||||
|
return jsonify({'status': 'error', 'message': '路径名称不能为空'})
|
||||||
|
|
||||||
|
try:
|
||||||
|
file_path = os.path.join('Path', f'{path_name}.json')
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
return jsonify({'status': 'error', 'message': '轨迹文件不存在'})
|
||||||
|
|
||||||
|
os.remove(file_path)
|
||||||
|
return jsonify({'status': 'success', 'message': '轨迹删除成功'})
|
||||||
|
except Exception as e:
|
||||||
|
print(f"删除轨迹出错: {e}")
|
||||||
|
return jsonify({'status': 'error', 'message': f'删除轨迹出错: {e}'})
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user