| New file |
| | |
| | | <!DOCTYPE html> |
| | | <html lang="zh-CN"> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | | <style> |
| | | * { |
| | | margin: 0; |
| | | padding: 0; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | body { |
| | | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; |
| | | background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); |
| | | padding: 30px; |
| | | line-height: 1.8; |
| | | } |
| | | |
| | | .breadcrumb { |
| | | font-size: 14px; |
| | | color: #999; |
| | | margin-bottom: 25px; |
| | | padding: 12px 20px; |
| | | background: linear-gradient(145deg, #ffffff, #f5f5f5); |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .breadcrumb a { |
| | | color: #999; |
| | | text-decoration: none; |
| | | } |
| | | |
| | | .update-time { |
| | | float: right; |
| | | color: #ccc; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .intro { |
| | | line-height: 2; |
| | | margin-bottom: 40px; |
| | | color: #555; |
| | | font-size: 16px; |
| | | padding: 25px; |
| | | background: linear-gradient(145deg, #ffffff, #f8f9fa); |
| | | border-radius: 12px; |
| | | border-left: 4px solid #0066cc; |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | h1 { |
| | | font-size: 32px; |
| | | margin-bottom: 30px; |
| | | padding-bottom: 20px; |
| | | border-bottom: 3px solid transparent; |
| | | border-image: linear-gradient(90deg, #0066cc, #00c6ff); |
| | | border-image-slice: 1; |
| | | color: #1a1a2e; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | h2 { |
| | | font-size: 22px; |
| | | margin: 40px 0 25px; |
| | | color: #1a1a2e; |
| | | font-weight: 700; |
| | | } |
| | | |
| | | .content-text { |
| | | line-height: 1.8; |
| | | color: #666; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | ul.feature-list { |
| | | list-style: none; |
| | | padding-left: 20px; |
| | | } |
| | | |
| | | ul.feature-list li { |
| | | position: relative; |
| | | padding-left: 20px; |
| | | margin-bottom: 10px; |
| | | line-height: 1.8; |
| | | color: #666; |
| | | } |
| | | |
| | | ul.feature-list li:before { |
| | | content: "■"; |
| | | position: absolute; |
| | | left: 0; |
| | | color: #333; |
| | | } |
| | | |
| | | .feedback-section { |
| | | margin: 40px 0; |
| | | text-align: center; |
| | | } |
| | | |
| | | .stars { |
| | | margin: 20px 0; |
| | | } |
| | | |
| | | .stars span { |
| | | font-size: 30px; |
| | | margin: 0 10px; |
| | | color: #ddd; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .pagination { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-top: 60px; |
| | | padding-top: 30px; |
| | | border-top: 1px solid #e0e0e0; |
| | | } |
| | | |
| | | .pagination > div { |
| | | cursor: pointer; |
| | | max-width: 45%; |
| | | } |
| | | |
| | | .pagination > div:hover { |
| | | color: #0066cc; |
| | | } |
| | | |
| | | .api-section { |
| | | margin: 40px 0; |
| | | padding: 30px; |
| | | background: linear-gradient(145deg, #ffffff, #f0f0f0); |
| | | border-radius: 16px; |
| | | box-shadow: 0 8px 32px rgba(0, 102, 204, 0.1); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .api-section:hover { |
| | | box-shadow: 0 12px 48px rgba(0, 102, 204, 0.15); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .api-section h2 { |
| | | margin-top: 0; |
| | | background: linear-gradient(135deg, #0066cc, #00c6ff); |
| | | -webkit-background-clip: text; |
| | | -webkit-text-fill-color: transparent; |
| | | background-clip: text; |
| | | font-size: 24px; |
| | | font-weight: 700; |
| | | position: relative; |
| | | padding-left: 20px; |
| | | } |
| | | |
| | | .api-section h2::before { |
| | | content: ''; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 50%; |
| | | transform: translateY(-50%); |
| | | width: 6px; |
| | | height: 24px; |
| | | background: linear-gradient(135deg, #0066cc, #00c6ff); |
| | | border-radius: 3px; |
| | | } |
| | | |
| | | .api-info { |
| | | background-color: #fff; |
| | | padding: 25px; |
| | | margin: 20px 0; |
| | | border-radius: 12px; |
| | | border-left: 5px solid #0066cc; |
| | | box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .api-info:hover { |
| | | box-shadow: 0 6px 24px rgba(0, 0, 0, 0.08); |
| | | } |
| | | |
| | | .api-method { |
| | | display: inline-block; |
| | | padding: 6px 16px; |
| | | border-radius: 20px; |
| | | font-weight: 700; |
| | | margin-right: 12px; |
| | | font-size: 13px; |
| | | text-transform: uppercase; |
| | | letter-spacing: 0.5px; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .api-method:hover { |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); |
| | | } |
| | | |
| | | .method-post { |
| | | background: linear-gradient(135deg, #49cc90, #38b57d); |
| | | color: #fff; |
| | | } |
| | | |
| | | .method-get { |
| | | background: linear-gradient(135deg, #61affe, #4e98eb); |
| | | color: #fff; |
| | | } |
| | | |
| | | .method-put { |
| | | background: linear-gradient(135deg, #fca130, #e89020); |
| | | color: #fff; |
| | | } |
| | | |
| | | .method-delete { |
| | | background: linear-gradient(135deg, #f93e3e, #e62e2e); |
| | | color: #fff; |
| | | } |
| | | |
| | | .api-url { |
| | | font-family: 'Courier New', 'Consolas', monospace; |
| | | background: linear-gradient(135deg, #2d3748, #1a202c); |
| | | color: #48bb78; |
| | | padding: 14px 18px; |
| | | margin: 15px 0; |
| | | border-radius: 8px; |
| | | font-size: 14px; |
| | | word-break: break-all; |
| | | border: 1px solid #4a5568; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .api-url::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 4px; |
| | | height: 100%; |
| | | background: linear-gradient(180deg, #48bb78, #38a169); |
| | | } |
| | | |
| | | table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | margin: 15px 0; |
| | | background-color: #fff; |
| | | } |
| | | |
| | | table th, |
| | | table td { |
| | | padding: 12px; |
| | | text-align: left; |
| | | border: 1px solid #e0e0e0; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | table th { |
| | | background: linear-gradient(135deg, #667eea, #764ba2); |
| | | font-weight: 700; |
| | | color: #fff; |
| | | text-transform: uppercase; |
| | | font-size: 12px; |
| | | letter-spacing: 0.5px; |
| | | } |
| | | |
| | | table tr:hover { |
| | | background-color: #f8f9fa; |
| | | transition: background-color 0.2s ease; |
| | | } |
| | | |
| | | pre { |
| | | background: linear-gradient(135deg, #1e1e1e, #2d2d30); |
| | | color: #d4d4d4; |
| | | padding: 24px; |
| | | border-radius: 12px; |
| | | overflow-x: auto; |
| | | margin: 20px 0; |
| | | box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); |
| | | border: 1px solid #3e3e42; |
| | | position: relative; |
| | | } |
| | | |
| | | pre::before { |
| | | content: '{ }'; |
| | | position: absolute; |
| | | top: 10px; |
| | | right: 15px; |
| | | color: #858585; |
| | | font-size: 12px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | code { |
| | | font-family: 'Courier New', monospace; |
| | | font-size: 13px; |
| | | line-height: 1.6; |
| | | } |
| | | |
| | | .mock-container { |
| | | background: linear-gradient(145deg, #ffffff, #f8f9fa); |
| | | padding: 25px; |
| | | margin: 25px 0; |
| | | border-radius: 16px; |
| | | box-shadow: 0 8px 24px rgba(0, 102, 204, 0.12); |
| | | border: 2px solid #e3e8ef; |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .mock-container:hover { |
| | | box-shadow: 0 12px 32px rgba(0, 102, 204, 0.18); |
| | | border-color: #0066cc; |
| | | } |
| | | |
| | | .mock-btn { |
| | | background: linear-gradient(135deg, #0066cc, #0052a3); |
| | | color: #fff; |
| | | border: none; |
| | | padding: 12px 28px; |
| | | border-radius: 25px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | margin: 5px; |
| | | height: 44px; |
| | | line-height: 20px; |
| | | box-shadow: 0 4px 15px rgba(0, 102, 204, 0.3); |
| | | transition: all 0.3s ease; |
| | | position: relative; |
| | | overflow: hidden; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .mock-btn::before { |
| | | content: ''; |
| | | position: absolute; |
| | | top: 50%; |
| | | left: 50%; |
| | | width: 0; |
| | | height: 0; |
| | | border-radius: 50%; |
| | | background: rgba(255, 255, 255, 0.3); |
| | | transform: translate(-50%, -50%); |
| | | transition: width 0.6s, height 0.6s; |
| | | } |
| | | |
| | | .mock-btn:hover { |
| | | background: linear-gradient(135deg, #0052a3, #003d7a); |
| | | box-shadow: 0 6px 20px rgba(0, 102, 204, 0.4); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .mock-btn:hover::before { |
| | | width: 300px; |
| | | height: 300px; |
| | | } |
| | | |
| | | .mock-btn:active { |
| | | transform: translateY(0); |
| | | box-shadow: 0 2px 10px rgba(0, 102, 204, 0.3); |
| | | } |
| | | |
| | | .reset-btn { |
| | | background: linear-gradient(135deg, #f5f5f5, #e0e0e0); |
| | | color: #666; |
| | | border: 1px solid #d0d0d0; |
| | | padding: 12px 28px; |
| | | border-radius: 25px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | margin: 5px; |
| | | height: 44px; |
| | | line-height: 20px; |
| | | box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1); |
| | | transition: all 0.3s ease; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .reset-btn:hover { |
| | | background: linear-gradient(135deg, #e0e0e0, #d0d0d0); |
| | | box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15); |
| | | transform: translateY(-2px); |
| | | color: #444; |
| | | } |
| | | |
| | | .reset-btn:active { |
| | | transform: translateY(0); |
| | | box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .mode-switch { |
| | | display: flex; |
| | | gap: 10px; |
| | | margin-bottom: 20px; |
| | | padding: 5px; |
| | | background: #f0f2f5; |
| | | border-radius: 25px; |
| | | width: fit-content; |
| | | } |
| | | |
| | | .mode-switch button { |
| | | padding: 8px 20px; |
| | | border: none; |
| | | border-radius: 20px; |
| | | cursor: pointer; |
| | | font-size: 13px; |
| | | font-weight: 600; |
| | | transition: all 0.3s ease; |
| | | background: transparent; |
| | | color: #666; |
| | | } |
| | | |
| | | .mode-switch button.active { |
| | | background: linear-gradient(135deg, #0066cc, #0052a3); |
| | | color: #fff; |
| | | box-shadow: 0 2px 10px rgba(0, 102, 204, 0.3); |
| | | } |
| | | |
| | | .mode-switch button:hover:not(.active) { |
| | | background: #e0e0e0; |
| | | } |
| | | |
| | | .json-input-container { |
| | | display: none; |
| | | } |
| | | |
| | | .json-input-container.active { |
| | | display: block; |
| | | } |
| | | |
| | | .form-input-container { |
| | | display: block; |
| | | } |
| | | |
| | | .form-input-container.hidden { |
| | | display: none; |
| | | } |
| | | |
| | | .json-textarea { |
| | | width: 100%; |
| | | min-height: 200px; |
| | | padding: 15px; |
| | | border: 2px solid #e3e8ef; |
| | | border-radius: 12px; |
| | | font-family: 'Courier New', monospace; |
| | | font-size: 13px; |
| | | line-height: 1.6; |
| | | resize: vertical; |
| | | transition: all 0.3s ease; |
| | | background: #fafbfc; |
| | | } |
| | | |
| | | .json-textarea:focus { |
| | | outline: none; |
| | | border-color: #0066cc; |
| | | box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1); |
| | | background: #fff; |
| | | } |
| | | |
| | | .json-textarea.error { |
| | | border-color: #f93e3e; |
| | | background: #fff5f5; |
| | | } |
| | | |
| | | .mock-result { |
| | | background: linear-gradient(145deg, #f8f9fa, #e9ecef); |
| | | padding: 20px; |
| | | margin-top: 20px; |
| | | border-radius: 12px; |
| | | max-height: 500px; |
| | | overflow-y: auto; |
| | | display: none; |
| | | border: 2px solid #dee2e6; |
| | | box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | animation: slideDown 0.3s ease; |
| | | } |
| | | |
| | | .mock-result.show { |
| | | display: block; |
| | | } |
| | | |
| | | @keyframes slideDown { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(-10px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | .mock-form { |
| | | background: linear-gradient(145deg, #ffffff, #f8f9fa); |
| | | padding: 20px; |
| | | margin-top: 15px; |
| | | border-radius: 12px; |
| | | border: 1px solid #e3e8ef; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .mock-form h5 { |
| | | color: #333; |
| | | margin-bottom: 15px; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .form-group { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .form-group label { |
| | | display: block; |
| | | margin-bottom: 6px; |
| | | color: #555; |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .form-group label .required { |
| | | color: #f93e3e; |
| | | margin-left: 3px; |
| | | } |
| | | |
| | | .form-group input, |
| | | .form-group select { |
| | | width: 100%; |
| | | padding: 10px 12px; |
| | | border: 1px solid #d1d5db; |
| | | border-radius: 6px; |
| | | font-size: 13px; |
| | | color: #333; |
| | | background: #fff; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .form-group input:focus, |
| | | .form-group select:focus { |
| | | outline: none; |
| | | border-color: #0066cc; |
| | | box-shadow: 0 0 0 3px rgba(0, 102, 204, 0.1); |
| | | } |
| | | |
| | | .form-group input.error, |
| | | .form-group select.error { |
| | | border-color: #f93e3e; |
| | | background: #fff5f5; |
| | | } |
| | | |
| | | .form-group .error-msg { |
| | | color: #f93e3e; |
| | | font-size: 12px; |
| | | margin-top: 5px; |
| | | display: none; |
| | | } |
| | | |
| | | .form-group .error-msg.show { |
| | | display: block; |
| | | } |
| | | |
| | | .error-msg { |
| | | color: #f93e3e; |
| | | font-size: 12px; |
| | | margin-top: 5px; |
| | | display: none; |
| | | } |
| | | |
| | | .error-msg.show { |
| | | display: block; |
| | | } |
| | | |
| | | .error-message { |
| | | color: #f93e3e; |
| | | font-size: 12px; |
| | | margin-top: 5px; |
| | | display: none; |
| | | } |
| | | |
| | | .error-message.show { |
| | | display: block; |
| | | } |
| | | |
| | | .form-group .hint { |
| | | color: #999; |
| | | font-size: 12px; |
| | | margin-top: 4px; |
| | | } |
| | | |
| | | .mock-form-actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | margin-top: 20px; |
| | | } |
| | | |
| | | .mock-btn-secondary { |
| | | background: linear-gradient(135deg, #6c757d, #5a6268); |
| | | color: #fff; |
| | | border: none; |
| | | padding: 12px 28px; |
| | | border-radius: 25px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | box-shadow: 0 4px 15px rgba(108, 117, 125, 0.3); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .mock-btn-secondary:hover { |
| | | background: linear-gradient(135deg, #5a6268, #495057); |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .mock-btn-secondary:active { |
| | | transform: translateY(0); |
| | | } |
| | | |
| | | .tag { |
| | | display: inline-block; |
| | | padding: 5px 14px; |
| | | color: #0b0b0b; |
| | | border-radius: 12px; |
| | | font-size: 14px; |
| | | font-weight: 700; |
| | | margin-left: 10px; |
| | | text-transform: uppercase; |
| | | letter-spacing: 0.5px; |
| | | box-shadow: 0 3px 6px rgba(0, 0, 0, 0.3); |
| | | } |
| | | |
| | | .note { |
| | | background: linear-gradient(135deg, #fff9e6, #fff3cd); |
| | | border-left: 5px solid #ffc107; |
| | | padding: 20px; |
| | | margin: 20px 0; |
| | | border-radius: 12px; |
| | | box-shadow: 0 4px 12px rgba(255, 193, 7, 0.15); |
| | | position: relative; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .note::before { |
| | | content: '⚠'; |
| | | position: absolute; |
| | | top: 15px; |
| | | right: 15px; |
| | | font-size: 24px; |
| | | opacity: 0.2; |
| | | } |
| | | |
| | | .note-title { |
| | | font-weight: 700; |
| | | color: #856404; |
| | | margin-bottom: 10px; |
| | | font-size: 16px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .note-title::before { |
| | | content: '💡'; |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | h3 { |
| | | font-size: 18px; |
| | | color: #2c3e50; |
| | | margin: 20px 0 15px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | h4 { |
| | | font-size: 16px; |
| | | color: #34495e; |
| | | margin: 18px 0 12px; |
| | | font-weight: 600; |
| | | padding-left: 12px; |
| | | border-left: 3px solid #0066cc; |
| | | } |
| | | |
| | | /* 滚动条美化 */ |
| | | ::-webkit-scrollbar { |
| | | width: 8px; |
| | | height: 8px; |
| | | } |
| | | |
| | | ::-webkit-scrollbar-track { |
| | | background: #f1f1f1; |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | ::-webkit-scrollbar-thumb { |
| | | background: linear-gradient(135deg, #667eea, #764ba2); |
| | | border-radius: 4px; |
| | | } |
| | | |
| | | ::-webkit-scrollbar-thumb:hover { |
| | | background: linear-gradient(135deg, #764ba2, #667eea); |
| | | } |
| | | |
| | | /* Mock测试折叠功能 */ |
| | | .mock-container { |
| | | position: relative; |
| | | } |
| | | |
| | | .mock-container .mock-toggle-btn { |
| | | position: absolute; |
| | | top: 0; |
| | | right: 0; |
| | | background: linear-gradient(135deg, #f5f5f5, #e0e0e0); |
| | | border: 1px solid #d0d0d0; |
| | | border-radius: 6px; |
| | | padding: 6px 12px; |
| | | cursor: pointer; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | color: #666; |
| | | transition: all 0.3s ease; |
| | | z-index: 10; |
| | | } |
| | | |
| | | .mock-container .mock-toggle-btn:hover { |
| | | background: linear-gradient(135deg, #e0e0e0, #d0d0d0); |
| | | color: #444; |
| | | } |
| | | |
| | | .mock-container .mock-content { |
| | | transition: all 0.3s ease; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .mock-container .mock-content.collapsed { |
| | | max-height: 0; |
| | | opacity: 0; |
| | | margin-top: 0; |
| | | padding-top: 0; |
| | | padding-bottom: 0; |
| | | } |
| | | |
| | | .mock-container .mock-content.expanded { |
| | | max-height: 2000px; |
| | | opacity: 1; |
| | | } |
| | | |
| | | /* 加载动画 */ |
| | | @keyframes pulse { |
| | | 0%, 100% { |
| | | opacity: 1; |
| | | } |
| | | 50% { |
| | | opacity: 0.5; |
| | | } |
| | | } |
| | | |
| | | .loading { |
| | | animation: pulse 1.5s ease-in-out infinite; |
| | | } |
| | | |
| | | /* 渐入动画 */ |
| | | @keyframes fadeIn { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | .api-section { |
| | | animation: fadeIn 0.6s ease-out; |
| | | } |
| | | |
| | | /* 代码复制按钮 */ |
| | | .code-wrapper { |
| | | position: relative; |
| | | } |
| | | |
| | | .copy-btn { |
| | | position: absolute; |
| | | top: 10px; |
| | | right: 10px; |
| | | background: rgba(255, 255, 255, 0.1); |
| | | color: #d4d4d4; |
| | | border: 1px solid rgba(255, 255, 255, 0.2); |
| | | padding: 6px 12px; |
| | | border-radius: 6px; |
| | | cursor: pointer; |
| | | font-size: 12px; |
| | | transition: all 0.3s ease; |
| | | opacity: 0; |
| | | } |
| | | |
| | | .code-wrapper:hover .copy-btn { |
| | | opacity: 1; |
| | | } |
| | | |
| | | .copy-btn:hover { |
| | | background: rgba(255, 255, 255, 0.2); |
| | | border-color: rgba(255, 255, 255, 0.4); |
| | | } |
| | | |
| | | /* 成功提示 */ |
| | | .success-icon { |
| | | color: #49cc90; |
| | | font-weight: bold; |
| | | animation: scaleIn 0.3s ease; |
| | | } |
| | | |
| | | @keyframes scaleIn { |
| | | from { |
| | | transform: scale(0); |
| | | } |
| | | to { |
| | | transform: scale(1); |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <div class="breadcrumb"> |
| | | <a href="#">RCS接口文档</a> > 接口详情 |
| | | <span class="update-time">更新时间:2025-12-29 14:20:00</span> |
| | | </div> |
| | | |
| | | <h1>RCS接口文档</h1> |
| | | |
| | | <div class="intro"> |
| | | <p style="font-size: 16px; margin-bottom: 20px;">欢迎使用中扬RCS开放平台 |
| | | API。本文档提供了完整的接口说明,包含请求参数、返回结果以及示例代码。每个接口都提供了 Mock |
| | | 功能,方便您快速测试和集成。</p> |
| | | </div> |
| | | |
| | | <div class="note" style="margin-bottom: 30px;"> |
| | | <div class="note-title">📌 快速对接指南</div> |
| | | <p style="margin-bottom: 12px;"><strong>接口中标 * 的为常用接口</strong>,初步对接时,只需要调通以下接口:</p> |
| | | <ul style="list-style: none; padding-left: 0; margin-bottom: 15px;"> |
| | | <li style="padding: 6px 0; padding-left: 25px; position: relative;"> |
| | | <span style="position: absolute; left: 0; color: #0066cc; font-weight: bold;">1.</span>生成任务单 |
| | | </li> |
| | | <li style="padding: 6px 0; padding-left: 25px; position: relative;"> |
| | | <span style="position: absolute; left: 0; color: #0066cc; font-weight: bold;">2.</span>取消任务单 |
| | | </li> |
| | | </ul> |
| | | <p style="margin-bottom: 12px;"><strong>如果上层系统需要接收任务的执行状态</strong>,需要提供以下接口,供调度系统回调: |
| | | </p> |
| | | <ul style="list-style: none; padding-left: 0; margin-bottom: 15px;"> |
| | | <li style="padding: 6px 0; padding-left: 25px; position: relative;"> |
| | | <span style="position: absolute; left: 0; color: #0066cc; font-weight: bold;">•</span>任务执行通知接口 |
| | | </li> |
| | | </ul> |
| | | <p style="background: #fff3cd; padding: 10px 15px; border-radius: 6px; margin-top: 15px; border-left: 4px solid #ffc107;"> |
| | | ⚠️ <strong>超时设置:</strong>中扬调度系统调用上层系统的接口,获取连接超时时间默认为 <strong>30秒</strong>,数据返回超时时间默认为 |
| | | <strong>60秒</strong>,超时情况下,调度系统会返回连接失败。 |
| | | </p> |
| | | </div> |
| | | |
| | | <div class="api-info" style="margin-bottom: 30px;"> |
| | | <h3 style="color: #2c3e50; font-size: 18px; margin-bottom: 15px; padding-left: 0; border-left: none;">📋 |
| | | 对接约定</h3> |
| | | <ul style="list-style: none; padding-left: 0;"> |
| | | <li style="padding: 10px 15px; margin-bottom: 8px; background: #f8f9fa; border-radius: 6px; border-left: 3px solid #667eea;"> |
| | | <strong style="color: #667eea;">统一格式:</strong>为接口统一并兼容,所有的参数都为字符串格式。 |
| | | </li> |
| | | <li style="padding: 10px 15px; margin-bottom: 8px; background: #f8f9fa; border-radius: 6px; border-left: 3px solid #667eea;"> |
| | | <strong style="color: #667eea;">术语约定:</strong>文本涉及到的 AGV、robot、机器人术语、CTU为同一术语,不要混淆。 |
| | | </li> |
| | | <li style="padding: 10px 15px; margin-bottom: 8px; background: #f8f9fa; border-radius: 6px; border-left: 3px solid #667eea;"> |
| | | <strong style="color: #667eea;">版本兼容:</strong>为兼容以前版本,消息上报字段会比列出的字段要多,上层平台根据业务截取需要的字段。 |
| | | </li> |
| | | <li style="padding: 10px 15px; margin-bottom: 8px; background: #f8f9fa; border-radius: 6px; border-left: 3px solid #667eea;"> |
| | | <strong style="color: #667eea;">容器定义:</strong>应用于叉车、CTU等项目中,料箱、托盘、载具都可称为容器。 |
| | | </li> |
| | | </ul> |
| | | </div> |
| | | |
| | | <!-- 接口概览 --> |
| | | <section id="api-overview" class="api-section"> |
| | | <h2>接口概览</h2> |
| | | <div class="api-info"> |
| | | <h3>🔗 基础信息</h3> |
| | | <table style="margin-top: 15px;"> |
| | | <tbody> |
| | | <tr> |
| | | <td style="width: 30%; font-weight: bold; background: #f8f9fa;">基础 URL</td> |
| | | <td><code style="background: #282c34; color: #48bb78; padding: 4px 8px; border-radius: 4px;">http://IP:PORT</code> |
| | | </td> |
| | | </tr> |
| | | <tr> |
| | | <td style="font-weight: bold; background: #f8f9fa;">请求格式</td> |
| | | <td><code>application/json</code></td> |
| | | </tr> |
| | | <tr> |
| | | <td style="font-weight: bold; background: #f8f9fa;">返回格式</td> |
| | | <td><code>application/json</code></td> |
| | | </tr> |
| | | <tr> |
| | | <td style="font-weight: bold; background: #f8f9fa;">字符编码</td> |
| | | <td><code>UTF-8</code></td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | |
| | | <div class="api-info"> |
| | | <h3>📋 通用请求参数</h3> |
| | | <p style="margin-bottom: 15px; color: #666;">以下参数为所有接口的通用参数,每次调用时需要携带:</p> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">是否必填</th> |
| | | <th>描述</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>reqTime</code></td> |
| | | <td><span style="color: #999;">选填</span></td> |
| | | <td>请求时间戳,格式: <code>yyyy-MM-dd HH:mm:ss</code>。由上层系统设定。</td> |
| | | </tr> |
| | | <!-- <tr>--> |
| | | <!-- <td><code>clientCode</code></td>--> |
| | | <!-- <td><span style="color: #999;">选填</span></td>--> |
| | | <!-- <td>客户端编号,如 PDA、HCWMS 等。如果填写,需先在 RCS-2000 系统配置,上层系统调用时进行填写,当多系统调用时,调度系统可以进行调用方区分。</td>--> |
| | | <!-- </tr>--> |
| | | <tr> |
| | | <td><code>tokenCode</code></td> |
| | | <td><span style="color: #999;">选填</span></td> |
| | | <td>令牌号,由调度系统颁发。如果填写,需先在 RCS-2000 系统配置,上层系统调用时进行填写。</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | |
| | | <div class="api-info"> |
| | | <h3>📤 通用返回值定义</h3> |
| | | <p style="margin-bottom: 15px; color: #666;">所有接口的响应都遵循以下统一格式:</p> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">是否必填</th> |
| | | <th>描述</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>code</code></td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">必填</span></td> |
| | | <td>返回编号,<code>200</code> 表示成功,<code>1~N</code> 表示失败</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>message</code></td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">必填</span></td> |
| | | <td>返回消息,<code>请求成功</code> 表示成功,内容为详细的错误描述</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>data</code></td> |
| | | <td><span style="color: #999;">选填</span></td> |
| | | <td>返回的数据结构,具体内容根据接口而定</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | |
| | | </section> |
| | | |
| | | <!-- 生成任务单 --> |
| | | <section id="api-task-create" class="api-section"> |
| | | <h2>生成任务单* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>创建搬运任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/bus/submit</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>批次编号(上层系统生成,唯一标识)</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>tasks</code></td> |
| | | <td>array</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务数组,包含具体的任务详情</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>任务数组元素参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>taskNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务编号(上层系统生成,唯一标识)</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>oriSta</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>起点站点编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>destSta</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>终点站点编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>oriLoc</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>起点库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>destLoc</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>终点库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>priority</code></td> |
| | | <td>int</td> |
| | | <td><span style="color: #999;">否</span></td> |
| | | <td>优先级:1-300,默认为1</td> |
| | | </tr> |
| | | |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | |
| | | "batchNo": "122334", |
| | | "tasks": [ |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriLoc": "A100100101", |
| | | "destSta": "STA001", |
| | | "priority": 1 |
| | | }, |
| | | { |
| | | "taskNo": "TASK20231220001", |
| | | "oriSta": "STA002", |
| | | "destLoc": "B02-03-05", |
| | | "priority": 2 |
| | | } |
| | | ] |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "任务创建成功", |
| | | "data": { |
| | | "taskNo": "TASK20231220001", |
| | | "taskId": "T1234567890", |
| | | "status": "ASSIGN" |
| | | }, |
| | | "timestamp": 1671526800000 |
| | | }</code></pre> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-create', 'form')" id="task-create-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-create', 'json')" id="task-create-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-create-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>taskNo <span class="required">*</span></label> |
| | | <input type="text" id="task-create-taskNo" placeholder="TASK20231220001" |
| | | value="TASK20231220001"> |
| | | <div class="error-msg" id="task-create-taskNo-error">请输入任务编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>batchNo <span class="required">*</span></label> |
| | | <input type="text" id="task-create-batchNo" placeholder="122334" |
| | | value="122334"> |
| | | <div class="error-msg" id="task-create-batchNo-error">请输入批次编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>taskType <span class="required">*</span></label> |
| | | <select id="task-create-taskType"> |
| | | <option value="1" selected>1 - 出库(oriLoc和destSta必填)</option> |
| | | <option value="2">2 - 入库(oriSta和destLoc必填)</option> |
| | | <option value="3">3 - 库位间移库(oriLoc和destLoc必填)</option> |
| | | <option value="4">4 - 站点间搬运(oriSta和destSta必填)</option> |
| | | </select> |
| | | <div class="error-msg" id="task-create-taskType-error">请选择任务类型</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>oriSta</label> |
| | | <input type="text" id="task-create-oriSta" placeholder="STA001" value=""> |
| | | <div class="hint">起点站点编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>destSta</label> |
| | | <input type="text" id="task-create-destSta" placeholder="STA002" value="STA001"> |
| | | <div class="hint">终点站点编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>oriLoc</label> |
| | | <input type="text" id="task-create-oriLoc" placeholder="A100100101" value="A100100101"> |
| | | <div class="hint">起点库位编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>destLoc</label> |
| | | <input type="text" id="task-create-destLoc" placeholder="B02-03-05" value=""> |
| | | <div class="hint">终点库位编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>priority</label> |
| | | <input type="text" id="task-create-priority" placeholder="1" value="1"> |
| | | <div class="hint">优先级:1-300,默认为1</div> |
| | | </div> |
| | | |
| | | </div> |
| | | <div class="json-input-container" id="task-create-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-create-json">{ |
| | | "taskNo": "TASK20231220001", |
| | | "batchNo": "122334", |
| | | "tasks": [ |
| | | { |
| | | "oriLoc": "A100100101", |
| | | "destSta": "STA001", |
| | | "priority": 1 |
| | | |
| | | } |
| | | ] |
| | | }</textarea> |
| | | <div class="error-msg" id="task-create-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskCreate()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskCreateForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-create-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 取消任务 --> |
| | | <section id="api-task-cancel" class="api-section"> |
| | | <h2>取消任务单* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>取消已创建的任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/task/cancel</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>tasks</code></td> |
| | | <td>array</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>要取消的任务编号数组</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: RED;">是</span></td> |
| | | <td>任务批次编号</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | “batchNo”: “12345”, |
| | | “tasks”: [“123”, “456”] |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | code: 200, |
| | | msg: ‘…’, |
| | | data: [ |
| | | { |
| | | “taskNo”: “123”, |
| | | “success”: true, |
| | | “msg”: null |
| | | }, |
| | | { |
| | | “taskNo”: “456”, |
| | | “success”: false, |
| | | “msg”: “456 is not exist” |
| | | } |
| | | ] |
| | | }</code></pre> |
| | | |
| | | <div class="note"> |
| | | <div class="note-title">注意事项</div> |
| | | <p>• 已经在执行中的任务无法取消,会返回相应错误码</p> |
| | | <p>• 取消任务后,AGV会停止执行并返回待命状态</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-cancel', 'form')" id="task-cancel-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-cancel', 'json')" id="task-cancel-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-cancel-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>tasks <span class="required">*</span></label> |
| | | <input type="text" id="task-cancel-tasks" placeholder="TASK20231220001,TASK20231220002" |
| | | value="TASK20231220001,TASK20231220002"> |
| | | <div class="error-msg" id="task-cancel-tasks-error">请输入要取消的任务编号</div> |
| | | <div class="hint">多个任务编号请用逗号分隔</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>batchNo</label> |
| | | <input type="text" id="task-cancel-batchNo" placeholder="12345" |
| | | value="12345"> |
| | | <div class="hint">任务批次编号(选填)</div> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="task-cancel-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-cancel-json">{ |
| | | "batchNo": "12345", |
| | | "tasks": ["TASK20231220001", "TASK20231220002"] |
| | | }</textarea> |
| | | <div class="error-msg" id="task-cancel-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskCancel()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskCancelForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-cancel-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 任务执行通知 --> |
| | | <section id="api-task-notice" class="api-section"> |
| | | <h2>任务执行通知* <span class="tag">回调接口</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>RCS回调上层系统接口</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/task/report</div> |
| | | |
| | | <div class="note" style="background: linear-gradient(135deg, #e3f2fd, #bbdefb); border-left-color: #2196f3;"> |
| | | <div class="note-title" style="color: #1565c0;">📢 接口说明</div> |
| | | <p style="color: #1976d2;">此接口由<strong>上层系统提供</strong>,RCS系统在任务状态发生变化时主动回调。上层系统需要实现此接口并配置回调地址到RCS系统中。 |
| | | </p> |
| | | </div> |
| | | |
| | | <h4>请求参数(RCS推送)</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td><code>batchNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务批次</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>taskNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>任务编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>timestamp</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>时间戳</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>推送示例(RCS → 上层系统)</h4> |
| | | <pre><code>{ |
| | | "taskNo": "TASK20231220001", |
| | | "batchNo": "2345", |
| | | "timestamp": "2023-12-20 14:30:25" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例(上层系统需返回)</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "接收成功" |
| | | }</code></pre> |
| | | |
| | | |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试(模拟RCS推送)</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="form-group"> |
| | | <label>回调地址 <span class="required">*</span></label> |
| | | <input type="text" id="task-notice-callback-url" placeholder="http://localhost:8080/api/callback" value="http://localhost:8080/api/callback"> |
| | | <span class="error-message" id="task-notice-callback-url-error">请输入回调地址</span> |
| | | </div> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskNotice()">发送请求</button> |
| | | <button class="reset-btn" onclick="resetTaskNoticeForm()">重置</button> |
| | | </div> |
| | | <div id="mock-task-notice-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 申请入库任务 --> |
| | | <section id="api-task-priority" class="api-section"> |
| | | <h2>申请入库任务* <span class="tag">常用</span></h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>申请入库任务</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/location/allocate</div> |
| | | <div class="note" style="background: linear-gradient(135deg, #e3f2fd, #bbdefb); border-left-color: #2196f3;"> |
| | | <div class="note-title" style="color: #1565c0;">📢 接口说明</div> |
| | | <p style="color: #1976d2;">此接口由<strong>上层系统提供</strong>,RCS系统在任务状态发生变化时主动回调。上层系统需要实现此接口并配置回调地址到RCS系统中。 |
| | | </p> |
| | | </div> |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>barcode</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>料箱码</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>staNo</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>入库站点</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | "barcode": "8000001", |
| | | "staNo": "1005" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "success", |
| | | "data": { |
| | | "locNo": "A100100101" |
| | | } |
| | | }</code></pre> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button class="active" onclick="switchInputMode('task-priority', 'form')" id="task-priority-form-btn"> |
| | | 表单输入 |
| | | </button> |
| | | <button onclick="switchInputMode('task-priority', 'json')" id="task-priority-json-btn">JSON输入</button> |
| | | </div> |
| | | <div class="mock-form"> |
| | | <div class="form-input-container" id="task-priority-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>taskNo <span class="required">*</span></label> |
| | | <input type="text" id="task-priority-taskNo" placeholder="TASK20231220001" |
| | | value="TASK20231220001"> |
| | | <div class="error-msg" id="task-priority-taskNo-error">请输入任务编号</div> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>priority <span class="required">*</span></label> |
| | | <input type="text" id="task-priority-priority" placeholder="1-300" value="3"> |
| | | <div class="hint">优先级范围:1-300</div> |
| | | <div class="error-msg" id="task-priority-priority-error">请输入优先级(1-300)</div> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="task-priority-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="task-priority-json">{ |
| | | "taskNo": "TASK20231220001", |
| | | "priority": "3" |
| | | }</textarea> |
| | | <div class="error-msg" id="task-priority-json-error">请输入有效的JSON格式</div> |
| | | </div> |
| | | <div class="mock-form-actions"> |
| | | <button class="mock-btn" onclick="mockTaskPriority()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetTaskPriorityForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-task-priority-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> |
| | | |
| | | <!-- 库位状态修改 --> |
| | | <!-- <section id="api-loc-status" class="api-section"> |
| | | <h2>库位状态修改</h2> |
| | | <div class="api-info"> |
| | | <h3> |
| | | <span class="api-method method-post">POST</span> |
| | | <span>修改库位状态</span> |
| | | </h3> |
| | | <div class="api-url">/api/open/loc/status/update</div> |
| | | |
| | | <h4>请求参数</h4> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th style="width: 20%;">参数名</th> |
| | | <th style="width: 15%;">类型</th> |
| | | <th style="width: 15%;">必填</th> |
| | | <th>说明</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | |
| | | <tr> |
| | | <td><code>locCode</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>库位编号</td> |
| | | </tr> |
| | | <tr> |
| | | <td><code>status</code></td> |
| | | <td>string</td> |
| | | <td><span style="color: #f93e3e; font-weight: bold;">是</span></td> |
| | | <td>库位状态:0-禁用、1-启用、2-在库、3-空库位</td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | |
| | | <h4>请求示例</h4> |
| | | <pre><code>{ |
| | | "locCode": "A100100101", |
| | | "status": "0" |
| | | }</code></pre> |
| | | |
| | | <h4>返回示例</h4> |
| | | <pre><code>{ |
| | | "code": 200, |
| | | "message": "库位状态修改成功" |
| | | }</code></pre> |
| | | |
| | | <div class="note"> |
| | | <div class="note-title">使用场景</div> |
| | | <p>• 临时封闭某个库位(维护、检修等)</p> |
| | | <p>• 库位异常时禁用</p> |
| | | <p>• 维护完成后重新启用库位</p> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="mock-container"> |
| | | <h4>Mock 测试</h4> |
| | | <button class="mock-toggle-btn" onclick="toggleMockContent(this)">展开</button> |
| | | <div class="mock-content collapsed"> |
| | | <div class="mode-switch"> |
| | | <button id="loc-status-form-btn" class="mode-btn active" |
| | | onclick="switchInputMode('loc-status', 'form')">表单输入 |
| | | </button> |
| | | <button id="loc-status-json-btn" class="mode-btn" onclick="switchInputMode('loc-status', 'json')"> |
| | | JSON输入 |
| | | </button> |
| | | </div> |
| | | <div class="form-input-container" id="loc-status-form-container"> |
| | | <h5>请求参数</h5> |
| | | <div class="form-group"> |
| | | <label>库位编码 <span class="required">*</span></label> |
| | | <input type="text" id="loc-status-locCode" placeholder="A100100101" value="A100100101"> |
| | | <span class="error-message" id="loc-status-locCode-error">请输入库位编码</span> |
| | | </div> |
| | | <div class="form-group"> |
| | | <label>状态 <span class="required">*</span></label> |
| | | <select id="loc-status-status"> |
| | | <option value="">请选择状态</option> |
| | | <option value="0">0 - 禁用</option> |
| | | <option value="1" selected>1 - 启用</option> |
| | | <option value="2">2 - 在库</option> |
| | | <option value="3">3 - 空库位</option> |
| | | </select> |
| | | <span class="error-message" id="loc-status-status-error">请选择状态</span> |
| | | </div> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockLocStatus()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetLocStatusForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div class="json-input-container" id="loc-status-json-container"> |
| | | <h5>JSON输入</h5> |
| | | <textarea class="json-textarea" id="loc-status-json" rows="8">{ |
| | | "locCode": "A100100101", |
| | | "status": "1" |
| | | }</textarea> |
| | | <span class="error-message" id="loc-status-json-error">请输入有效的JSON参数</span> |
| | | <div class="form-actions"> |
| | | <button class="mock-btn" onclick="mockLocStatus()">执行 Mock 请求</button> |
| | | <button class="reset-btn" onclick="resetLocStatusForm()">重置</button> |
| | | </div> |
| | | </div> |
| | | <div id="mock-loc-status-result" class="mock-result"></div> |
| | | </div> |
| | | </div> |
| | | </section> --> |
| | | |
| | | |
| | | |
| | | <!-- 错误码说明 --> |
| | | <section id="error-codes" class="api-section"> |
| | | <h2>错误码说明</h2> |
| | | <div class="api-info"> |
| | | <h3>通用错误码</h3> |
| | | <table> |
| | | <thead> |
| | | <tr> |
| | | <th>错误码</th> |
| | | <th>说明</th> |
| | | <th>解决方案</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr> |
| | | <td>200</td> |
| | | <td>成功</td> |
| | | <td>-</td> |
| | | </tr> |
| | | <tr> |
| | | <td>500</td> |
| | | <td>参数错误</td> |
| | | <td>检查请求参数是否完整和正确</td> |
| | | </tr> |
| | | |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | </section> |
| | | |
| | | |
| | | <div class="feedback-section"> |
| | | <p style="color: #999;">以上内容对您有帮助吗?</p> |
| | | <div class="stars"> |
| | | <span>☆</span> |
| | | <span>☆</span> |
| | | <span>☆</span> |
| | | <span>☆</span> |
| | | <span>☆</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="pagination"> |
| | | <div class="prev-page"> |
| | | <div style="color: #999; font-size: 14px; margin-bottom: 10px;">上一篇</div> |
| | | <div style="color: #333; font-size: 16px;">平台规范</div> |
| | | </div> |
| | | <div class="next-page"> |
| | | <div style="color: #999; font-size: 14px; margin-bottom: 10px; text-align: right;">下一篇</div> |
| | | <div style="color: #333; font-size: 16px; text-align: right;">应用接入引导</div> |
| | | </div> |
| | | </div> |
| | | |
| | | <script> |
| | | // 验证任务创建参数 |
| | | function validateTaskCreate() { |
| | | let isValid = true; |
| | | |
| | | const taskNo = document.getElementById('task-create-taskNo'); |
| | | const taskType = document.getElementById('task-create-taskType'); |
| | | const oriSta = document.getElementById('task-create-oriSta'); |
| | | const destSta = document.getElementById('task-create-destSta'); |
| | | const oriLoc = document.getElementById('task-create-oriLoc'); |
| | | const destLoc = document.getElementById('task-create-destLoc'); |
| | | |
| | | const taskNoError = document.getElementById('task-create-taskNo-error'); |
| | | const taskTypeError = document.getElementById('task-create-taskType-error'); |
| | | |
| | | taskNo.classList.remove('error'); |
| | | taskType.classList.remove('error'); |
| | | oriSta.classList.remove('error'); |
| | | destSta.classList.remove('error'); |
| | | oriLoc.classList.remove('error'); |
| | | destLoc.classList.remove('error'); |
| | | |
| | | taskNoError.classList.remove('show'); |
| | | taskTypeError.classList.remove('show'); |
| | | |
| | | if (!taskNo.value.trim()) { |
| | | taskNo.classList.add('error'); |
| | | taskNoError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | if (!taskType.value) { |
| | | taskType.classList.add('error'); |
| | | taskTypeError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | const taskTypeValue = parseInt(taskType.value); |
| | | if (taskTypeValue === 1 || taskTypeValue === 3) { |
| | | if (!oriLoc.value.trim()) { |
| | | oriLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 2 || taskTypeValue === 4) { |
| | | if (!oriSta.value.trim()) { |
| | | oriSta.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 1 || taskTypeValue === 4) { |
| | | if (!destSta.value.trim()) { |
| | | destSta.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | if (taskTypeValue === 2 || taskTypeValue === 3) { |
| | | if (!destLoc.value.trim()) { |
| | | destLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | |
| | | if (oriLoc.value.trim() && destLoc.value.trim() && oriLoc.value.trim() === destLoc.value.trim()) { |
| | | oriLoc.classList.add('error'); |
| | | destLoc.classList.add('error'); |
| | | isValid = false; |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务创建表单 |
| | | function resetTaskCreateForm() { |
| | | document.getElementById('task-create-taskNo').value = 'TASK20231220001'; |
| | | document.getElementById('task-create-batchNo').value = '122334'; |
| | | document.getElementById('task-create-taskType').value = '1'; |
| | | document.getElementById('task-create-oriSta').value = ''; |
| | | document.getElementById('task-create-destSta').value = 'STA001'; |
| | | document.getElementById('task-create-oriLoc').value = 'A100100101'; |
| | | document.getElementById('task-create-destLoc').value = ''; |
| | | document.getElementById('task-create-priority').value = '1'; |
| | | |
| | | syncFormToJson('task-create'); |
| | | |
| | | const inputs = document.querySelectorAll('#task-create-taskNo, #task-create-batchNo, #task-create-taskType, #task-create-oriSta, #task-create-destSta, #task-create-oriLoc, #task-create-destLoc'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-create-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-create-taskNo-error') error.textContent = '请输入任务编号'; |
| | | if (error.id === 'task-create-taskType-error') error.textContent = '请选择任务类型'; |
| | | }); |
| | | |
| | | document.getElementById('mock-task-create-result').classList.remove('show'); |
| | | document.getElementById('mock-task-create-result').innerHTML = ''; |
| | | |
| | | const jsonError = document.getElementById('task-create-json-error'); |
| | | if (jsonError) jsonError.classList.remove('show'); |
| | | |
| | | |
| | | const resultDiv = document.getElementById('mock-task-create-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | |
| | | // 切换输入模式 |
| | | function switchInputMode(formId, mode) { |
| | | const formBtn = document.getElementById(`${formId}-form-btn`); |
| | | const jsonBtn = document.getElementById(`${formId}-json-btn`); |
| | | const formContainer = document.getElementById(`${formId}-form-container`); |
| | | const jsonContainer = document.getElementById(`${formId}-json-container`); |
| | | |
| | | if (mode === 'form') { |
| | | syncJsonToForm(formId); |
| | | formBtn.classList.add('active'); |
| | | jsonBtn.classList.remove('active'); |
| | | formContainer.classList.remove('hidden'); |
| | | jsonContainer.classList.remove('active'); |
| | | } else { |
| | | syncFormToJson(formId); |
| | | formBtn.classList.remove('active'); |
| | | jsonBtn.classList.add('active'); |
| | | formContainer.classList.add('hidden'); |
| | | jsonContainer.classList.add('active'); |
| | | } |
| | | } |
| | | |
| | | function syncFormToJson(formId) { |
| | | let params; |
| | | if (formId === 'task-create') { |
| | | // 对于任务创建表单,使用新的数组格式 |
| | | const formParams = getParamsFromForm(formId); |
| | | params = { |
| | | taskNo: formParams.taskNo, |
| | | batchNo: formParams.batchNo || '122334', |
| | | tasks: [{ |
| | | taskType: formParams.taskType, |
| | | oriSta: formParams.oriSta, |
| | | destSta: formParams.destSta, |
| | | oriLoc: formParams.oriLoc, |
| | | destLoc: formParams.destLoc, |
| | | priority: formParams.priority ? parseInt(formParams.priority) : 1 |
| | | }] |
| | | }; |
| | | } else if (formId === 'task-cancel') { |
| | | // 对于任务取消表单,使用tasks数组格式 |
| | | const formParams = getParamsFromForm(formId); |
| | | params = { |
| | | batchNo: formParams.batchNo || '12345', |
| | | tasks: formParams.tasks.split(',').map(task => task.trim()) |
| | | }; |
| | | } else { |
| | | // 对于其他表单,使用原有的格式 |
| | | params = getParamsFromForm(formId); |
| | | } |
| | | const textarea = document.getElementById(`${formId}-json`); |
| | | if (textarea) { |
| | | textarea.value = JSON.stringify(params, null, 2); |
| | | } |
| | | } |
| | | |
| | | function syncJsonToForm(formId) { |
| | | const textarea = document.getElementById(`${formId}-json`); |
| | | if (!textarea) return; |
| | | |
| | | try { |
| | | const params = JSON.parse(textarea.value); |
| | | const inputs = document.querySelectorAll(`#${formId}-form-container input, #${formId}-form-container select`); |
| | | |
| | | if (formId === 'task-create' && params.tasks && Array.isArray(params.tasks) && params.tasks.length > 0) { |
| | | // 对于任务创建表单,从tasks数组中获取第一个任务的数据 |
| | | const task = params.tasks[0]; |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } else if (task[key] !== undefined) { |
| | | input.value = task[key]; |
| | | } |
| | | }); |
| | | } else if (formId === 'task-cancel' && params.tasks && Array.isArray(params.tasks)) { |
| | | // 对于任务取消表单,将tasks数组转换为逗号分隔的字符串 |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (key === 'tasks') { |
| | | input.value = params.tasks.join(', '); |
| | | } else if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } |
| | | }); |
| | | } else { |
| | | // 对于其他表单,使用原有的逻辑 |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | if (params[key] !== undefined) { |
| | | input.value = params[key]; |
| | | } |
| | | }); |
| | | } |
| | | } catch (e) { |
| | | console.error('JSON解析失败,无法同步到表单', e); |
| | | } |
| | | } |
| | | |
| | | // 从表单获取参数 |
| | | function getParamsFromForm(formId) { |
| | | const params = {}; |
| | | const inputs = document.querySelectorAll(`#${formId}-form-container input, #${formId}-form-container select`); |
| | | inputs.forEach(input => { |
| | | const key = input.id.replace(`${formId}-`, ''); |
| | | params[key] = input.value.trim(); |
| | | }); |
| | | return params; |
| | | } |
| | | |
| | | // 从JSON获取参数 |
| | | function getParamsFromJson(jsonId) { |
| | | const textarea = document.getElementById(jsonId); |
| | | const errorDiv = document.getElementById(`${jsonId}-error`); |
| | | |
| | | try { |
| | | const json = JSON.parse(textarea.value); |
| | | textarea.classList.remove('error'); |
| | | errorDiv.classList.remove('show'); |
| | | return json; |
| | | } catch (e) { |
| | | textarea.classList.add('error'); |
| | | errorDiv.classList.add('show'); |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | // 验证任务创建JSON参数 |
| | | function validateTaskCreateJson(params) { |
| | | const errorDiv = document.getElementById('task-create-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.taskNo || !params.taskNo.trim()) { |
| | | errorDiv.textContent = 'taskNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.batchNo || !params.batchNo.trim()) { |
| | | errorDiv.textContent = 'batchNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.tasks || !Array.isArray(params.tasks)) { |
| | | errorDiv.textContent = 'tasks必须是数组格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (params.tasks.length === 0) { |
| | | errorDiv.textContent = 'tasks数组不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | // 验证tasks数组中的每个任务 |
| | | for (let i = 0; i < params.tasks.length; i++) { |
| | | const task = params.tasks[i]; |
| | | if (!task || typeof task !== 'object') { |
| | | errorDiv.textContent = `tasks数组第${i+1}个元素必须是对象`; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | // 验证起点和终点 |
| | | if (task.oriLoc && task.destLoc && task.oriLoc.trim() === task.destLoc.trim()) { |
| | | errorDiv.textContent = `tasks数组第${i+1}个元素的起点库位和终点库位不能相同`; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 生成任务单 |
| | | function mockTaskCreate() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-create-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-create-json'); |
| | | if (!params) return; |
| | | if (!validateTaskCreateJson(params)) return; |
| | | } else { |
| | | // 从表单获取参数并转换为新的数组格式 |
| | | const formParams = getParamsFromForm('task-create'); |
| | | params = { |
| | | taskNo: formParams.taskNo, |
| | | batchNo: formParams.batchNo || '122334', |
| | | tasks: [{ |
| | | taskType: formParams.taskType, |
| | | oriSta: formParams.oriSta, |
| | | destSta: formParams.destSta, |
| | | oriLoc: formParams.oriLoc, |
| | | destLoc: formParams.destLoc, |
| | | priority: formParams.priority ? parseInt(formParams.priority) : 1 |
| | | }] |
| | | }; |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-create-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const response = { |
| | | code: 200, |
| | | message: "任务创建成功", |
| | | data: { |
| | | taskNo: params.taskNo, |
| | | batchNo: params.batchNo, |
| | | taskId: "T" + Math.random().toString(36).substr(2, 10), |
| | | status: "ASSIGN", |
| | | taskCount: params.tasks.length |
| | | }, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(params, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #fff; border-radius: 8px; border: 2px solid #49cc90;">🎯 成功创建 ${params.tasks.length} 个搬运任务,等待分配机器人执行</p> |
| | | `; |
| | | }, 800); |
| | | } |
| | | |
| | | // 验证任务取消参数 |
| | | function validateTaskCancel() { |
| | | let isValid = true; |
| | | |
| | | const tasks = document.getElementById('task-cancel-tasks'); |
| | | |
| | | const tasksError = document.getElementById('task-cancel-tasks-error'); |
| | | |
| | | tasks.classList.remove('error'); |
| | | |
| | | tasksError.classList.remove('show'); |
| | | |
| | | if (!tasks.value.trim()) { |
| | | tasks.classList.add('error'); |
| | | tasksError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务取消表单 |
| | | function resetTaskCancelForm() { |
| | | document.getElementById('task-cancel-tasks').value = 'TASK20231220001,TASK20231220002'; |
| | | document.getElementById('task-cancel-batchNo').value = '12345'; |
| | | |
| | | syncFormToJson('task-cancel'); |
| | | |
| | | const inputs = document.querySelectorAll('#task-cancel-tasks'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-cancel-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-cancel-tasks-error') error.textContent = '请输入要取消的任务编号'; |
| | | }); |
| | | |
| | | const resultDiv = document.getElementById('mock-task-cancel-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | |
| | | // 验证任务取消JSON参数 |
| | | function validateTaskCancelJson(params) { |
| | | const errorDiv = document.getElementById('task-cancel-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.tasks || !Array.isArray(params.tasks) || params.tasks.length === 0) { |
| | | errorDiv.textContent = 'tasks必须是非空数组'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 取消任务 |
| | | function mockTaskCancel() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-cancel-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-cancel-json'); |
| | | if (!params) return; |
| | | if (!validateTaskCancelJson(params)) return; |
| | | } else { |
| | | if (!validateTaskCancel()) return; |
| | | const formParams = getParamsFromForm('task-cancel'); |
| | | // 将逗号分隔的任务编号字符串转换为数组 |
| | | params = { |
| | | tasks: formParams.tasks.split(',').map(task => task.trim()), |
| | | batchNo: formParams.batchNo |
| | | }; |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-cancel-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | // 生成每个任务的取消结果 |
| | | const data = params.tasks.map(taskNo => { |
| | | // 模拟随机的取消结果 |
| | | const success = Math.random() > 0.2; // 80%的概率成功 |
| | | return { |
| | | taskNo: taskNo, |
| | | success: success, |
| | | msg: success ? null : `${taskNo} 不存在或无法取消` |
| | | }; |
| | | }); |
| | | |
| | | const response = { |
| | | code: 200, |
| | | msg: "任务取消成功", |
| | | data: data, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(params, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #4caf50;">✅ 任务取消请求已处理,共取消 ${params.tasks.length} 个任务</p> |
| | | `; |
| | | }, 1000); |
| | | } |
| | | |
| | | // Mock 任务执行通知 |
| | | function mockTaskNotice() { |
| | | const callbackUrl = document.getElementById('task-notice-callback-url'); |
| | | |
| | | if (!callbackUrl.value.trim()) { |
| | | callbackUrl.classList.add('error'); |
| | | document.getElementById('task-notice-callback-url-error').classList.add('show'); |
| | | return; |
| | | } else { |
| | | callbackUrl.classList.remove('error'); |
| | | document.getElementById('task-notice-callback-url-error').classList.remove('show'); |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-task-notice-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | const pushData = { |
| | | taskNo: "TASK20231220001", |
| | | robotCode: "AGV" + Math.floor(Math.random() * 10 + 1).toString().padStart(3, '0'), |
| | | finishTime: new Date().toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }).replace(/\//g, '-') |
| | | }; |
| | | |
| | | fetch(callbackUrl.value.trim(), { |
| | | method: 'POST', |
| | | headers: { |
| | | 'Content-Type': 'application/json' |
| | | }, |
| | | body: JSON.stringify(pushData) |
| | | }) |
| | | .then(response => { |
| | | if (!response.ok) { |
| | | throw new Error(`HTTP error! status: ${response.status}`); |
| | | } |
| | | return response.json(); |
| | | }) |
| | | .then(data => { |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(pushData, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <div style="padding: 15px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;"> |
| | | <p style="font-weight: bold; color: #2e7d32; margin-bottom: 10px;">📥 返回数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(data, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #e8f5e9; border-radius: 8px; border-left: 4px solid #49cc90;">🎯 任务执行通知已成功发送</p> |
| | | `; |
| | | }) |
| | | .catch(error => { |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #f44336; font-weight: bold;" class="error-icon">✖ 请求失败</p> |
| | | <div style="margin-bottom: 20px; padding: 15px; background: #e3f2fd; border-radius: 8px; border-left: 4px solid #2196f3;"> |
| | | <p style="font-weight: bold; color: #1976d2; margin-bottom: 10px;">📤 发送数据</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(pushData, null, 2)}</code></pre> |
| | | </div> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #f44336; padding: 10px; background: #ffebee; border-radius: 8px; border-left: 4px solid #f44336;"> |
| | | ❌ 错误信息:<strong>${error.message}</strong> |
| | | </p> |
| | | <p style="margin-top: 10px; color: #999; font-size: 12px;">提示:请确保回调地址可访问,且服务器已启动并支持CORS跨域请求</p> |
| | | `; |
| | | }); |
| | | } |
| | | |
| | | function resetTaskNoticeForm() { |
| | | document.getElementById('task-notice-callback-url').value = 'http://localhost:8080/api/callback'; |
| | | |
| | | document.getElementById('mock-task-notice-result').classList.remove('show'); |
| | | document.getElementById('mock-task-notice-result').innerHTML = ''; |
| | | |
| | | const inputs = document.querySelectorAll('#api-task-notice input'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | const errors = document.querySelectorAll('#api-task-notice .error-message'); |
| | | errors.forEach(error => error.classList.remove('show')); |
| | | } |
| | | |
| | | // 验证库位状态修改参数 |
| | | function validateLocStatus() { |
| | | let isValid = true; |
| | | const locCode = document.getElementById('loc-status-locCode'); |
| | | const status = document.getElementById('loc-status-status'); |
| | | |
| | | if (!locCode.value.trim()) { |
| | | locCode.classList.add('error'); |
| | | document.getElementById('loc-status-locCode-error').classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | locCode.classList.remove('error'); |
| | | document.getElementById('loc-status-locCode-error').classList.remove('show'); |
| | | } |
| | | |
| | | if (!status.value) { |
| | | status.classList.add('error'); |
| | | document.getElementById('loc-status-status-error').classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | status.classList.remove('error'); |
| | | document.getElementById('loc-status-status-error').classList.remove('show'); |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | function validateLocStatusJson(params) { |
| | | const errorDiv = document.getElementById('loc-status-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.locCode || !params.locCode.trim()) { |
| | | errorDiv.textContent = 'locCode不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.status || !params.status.toString().trim()) { |
| | | errorDiv.textContent = 'status不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } else { |
| | | const statusValue = params.status.toString().trim(); |
| | | if (!['0', '1', '2', '3'].includes(statusValue)) { |
| | | errorDiv.textContent = 'status必须是0-3之间的数字(0-禁用、1-启用、2-在库、3-空库位)'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // 重置库位状态修改表单 |
| | | function resetLocStatusForm() { |
| | | document.getElementById('loc-status-locCode').value = 'A100100101'; |
| | | document.getElementById('loc-status-status').value = '1'; |
| | | |
| | | syncFormToJson('loc-status'); |
| | | |
| | | document.getElementById('mock-loc-status-result').classList.remove('show'); |
| | | document.getElementById('mock-loc-status-result').innerHTML = ''; |
| | | |
| | | const inputs = document.querySelectorAll('#loc-status-form-container input, #loc-status-form-container select'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | const errors = document.querySelectorAll('#loc-status-form-container .error-message'); |
| | | errors.forEach(error => error.classList.remove('show')); |
| | | |
| | | const jsonError = document.getElementById('loc-status-json-error'); |
| | | if (jsonError) jsonError.classList.remove('show'); |
| | | } |
| | | |
| | | // 验证任务优先级参数 |
| | | function validateTaskPriority() { |
| | | let isValid = true; |
| | | |
| | | const taskNo = document.getElementById('task-priority-taskNo'); |
| | | const priority = document.getElementById('task-priority-priority'); |
| | | |
| | | const taskNoError = document.getElementById('task-priority-taskNo-error'); |
| | | const priorityError = document.getElementById('task-priority-priority-error'); |
| | | |
| | | taskNo.classList.remove('error'); |
| | | priority.classList.remove('error'); |
| | | |
| | | taskNoError.classList.remove('show'); |
| | | priorityError.classList.remove('show'); |
| | | |
| | | if (!taskNo.value.trim()) { |
| | | taskNo.classList.add('error'); |
| | | taskNoError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | |
| | | if (!priority.value.trim()) { |
| | | priority.classList.add('error'); |
| | | priorityError.classList.add('show'); |
| | | isValid = false; |
| | | } else { |
| | | const priorityNum = parseInt(priority.value.trim()); |
| | | if (isNaN(priorityNum) || priorityNum < 1 || priorityNum > 300) { |
| | | priority.classList.add('error'); |
| | | priorityError.textContent = '优先级必须是1-300的数字'; |
| | | priorityError.classList.add('show'); |
| | | isValid = false; |
| | | } |
| | | } |
| | | |
| | | return isValid; |
| | | } |
| | | |
| | | // 重置任务优先级表单 |
| | | function resetTaskPriorityForm() { |
| | | document.getElementById('task-priority-taskNo').value = 'TASK20231220001'; |
| | | document.getElementById('task-priority-priority').value = '2'; |
| | | |
| | | syncFormToJson('task-priority'); |
| | | |
| | | const inputs = document.querySelectorAll('#task-priority-taskNo, #task-priority-priority'); |
| | | inputs.forEach(input => input.classList.remove('error')); |
| | | |
| | | const errors = document.querySelectorAll('[id^="task-priority-"][id$="-error"]'); |
| | | errors.forEach(error => { |
| | | error.classList.remove('show'); |
| | | if (error.id === 'task-priority-taskNo-error') error.textContent = '请输入任务编号'; |
| | | if (error.id === 'task-priority-priority-error') error.textContent = '请输入优先级(1-300)'; |
| | | }); |
| | | |
| | | const resultDiv = document.getElementById('mock-task-priority-result'); |
| | | resultDiv.classList.remove('show'); |
| | | resultDiv.innerHTML = ''; |
| | | } |
| | | |
| | | // 验证任务优先级JSON参数 |
| | | function validateTaskPriorityJson(params) { |
| | | const errorDiv = document.getElementById('task-priority-json-error'); |
| | | |
| | | if (!params || typeof params !== 'object') { |
| | | errorDiv.textContent = '请输入有效的JSON格式'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.taskNo || !params.taskNo.trim()) { |
| | | errorDiv.textContent = 'taskNo不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | |
| | | if (!params.priority || !params.priority.toString().trim()) { |
| | | errorDiv.textContent = 'priority不能为空'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } else { |
| | | const priorityNum = parseInt(params.priority.toString().trim()); |
| | | if (isNaN(priorityNum) || priorityNum < 1 || priorityNum > 300) { |
| | | errorDiv.textContent = 'priority必须是1-300的数字'; |
| | | errorDiv.classList.add('show'); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | errorDiv.classList.remove('show'); |
| | | return true; |
| | | } |
| | | |
| | | // Mock 任务优先级设置 |
| | | function mockTaskPriority() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('task-priority-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('task-priority-json'); |
| | | if (!params) return; |
| | | if (!validateTaskPriorityJson(params)) return; |
| | | } else { |
| | | if (!validateTaskPriority()) return; |
| | | params = getParamsFromForm('task-priority'); |
| | | } |
| | | |
| | | const taskNo = params.taskNo; |
| | | const priority = params.priority; |
| | | |
| | | const resultDiv = document.getElementById('mock-task-priority-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const response = { |
| | | code: 200, |
| | | message: "请求成功", |
| | | data: { |
| | | taskNo: taskNo, |
| | | priority: priority |
| | | }, |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | const priorityNum = parseInt(priority); |
| | | let priorityInfo; |
| | | if (priorityNum <= 100) { |
| | | priorityInfo = {text: '低', color: '#9e9e9e', icon: '⬇️'}; |
| | | } else if (priorityNum <= 200) { |
| | | priorityInfo = {text: '中', color: '#2196f3', icon: '➡️'}; |
| | | } else { |
| | | priorityInfo = {text: '高', color: '#f44336', icon: '⬆️'}; |
| | | } |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #f5f5f5; border-radius: 8px; border-left: 4px solid ${priorityInfo.color};"> |
| | | ${priorityInfo.icon} 任务优先级已设置为:<strong style="color: ${priorityInfo.color};">${priorityInfo.text}</strong> |
| | | </p> |
| | | `; |
| | | }, 600); |
| | | } |
| | | |
| | | // Mock 库位状态修改 |
| | | function mockLocStatus() { |
| | | let params; |
| | | const isJsonMode = document.getElementById('loc-status-json-container').classList.contains('active'); |
| | | |
| | | if (isJsonMode) { |
| | | params = getParamsFromJson('loc-status-json'); |
| | | if (!params) return; |
| | | if (!validateLocStatusJson(params)) return; |
| | | } else { |
| | | if (!validateLocStatus()) return; |
| | | params = getParamsFromForm('loc-status'); |
| | | } |
| | | |
| | | const resultDiv = document.getElementById('mock-loc-status-result'); |
| | | resultDiv.classList.add('show'); |
| | | resultDiv.innerHTML = '<p style="color: #999;" class="loading">⏳ 正在发送请求...</p>'; |
| | | |
| | | setTimeout(() => { |
| | | const locCode = params.locCode; |
| | | const status = params.status; |
| | | |
| | | const response = { |
| | | code: 200, |
| | | message: "库位状态修改成功", |
| | | timestamp: new Date().getTime() |
| | | }; |
| | | |
| | | const statusMap = { |
| | | '0': {text: '禁用', color: '#f44336', icon: '🚫'}, |
| | | '1': {text: '启用', color: '#4caf50', icon: '✅'}, |
| | | '2': {text: '在库', color: '#ff9800', icon: '📦'}, |
| | | '3': {text: '空库位', color: '#2196f3', icon: '⬜'} |
| | | }; |
| | | |
| | | const statusInfo = statusMap[status]; |
| | | |
| | | resultDiv.innerHTML = ` |
| | | <p style="color: #49cc90; font-weight: bold;" class="success-icon">✔ 请求成功</p> |
| | | <div class="code-wrapper"> |
| | | <button class="copy-btn" onclick="copyCode(this)">📋 复制</button> |
| | | <pre><code>${JSON.stringify(response, null, 2)}</code></pre> |
| | | </div> |
| | | <p style="margin-top: 15px; color: #666; padding: 10px; background: #f5f5f5; border-radius: 8px; border-left: 4px solid ${statusInfo.color};"> |
| | | ${statusInfo.icon} 库位 <strong>${locCode}</strong> 状态:<strong style="color: ${statusInfo.color};">${statusInfo.text}</strong> |
| | | </p> |
| | | `; |
| | | }, 700); |
| | | } |
| | | |
| | | |
| | | |
| | | // 复制代码功能 |
| | | function copyCode(button) { |
| | | const codeBlock = button.nextElementSibling.querySelector('code'); |
| | | const text = codeBlock.textContent; |
| | | |
| | | navigator.clipboard.writeText(text).then(() => { |
| | | const originalText = button.innerHTML; |
| | | button.innerHTML = '✓ 已复制'; |
| | | button.style.background = 'rgba(73, 204, 144, 0.2)'; |
| | | button.style.borderColor = 'rgba(73, 204, 144, 0.4)'; |
| | | button.style.color = '#49cc90'; |
| | | |
| | | setTimeout(() => { |
| | | button.innerHTML = originalText; |
| | | button.style.background = 'rgba(255, 255, 255, 0.1)'; |
| | | button.style.borderColor = 'rgba(255, 255, 255, 0.2)'; |
| | | button.style.color = '#d4d4d4'; |
| | | }, 2000); |
| | | }).catch(err => { |
| | | console.error('复制失败:', err); |
| | | }); |
| | | } |
| | | |
| | | function toggleMockContent(button) { |
| | | const content = button.nextElementSibling; |
| | | if (content.classList.contains('expanded')) { |
| | | content.classList.remove('expanded'); |
| | | content.classList.add('collapsed'); |
| | | button.textContent = '展开'; |
| | | } else { |
| | | content.classList.remove('collapsed'); |
| | | content.classList.add('expanded'); |
| | | button.textContent = '折叠'; |
| | | } |
| | | } |
| | | |
| | | // 监听滚动消息 |
| | | window.addEventListener('message', function (event) { |
| | | if (event.data.type === 'scrollToSection') { |
| | | const targetElement = document.getElementById(event.data.sectionId); |
| | | if (targetElement) { |
| | | targetElement.scrollIntoView({behavior: 'smooth', block: 'start'}); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | | </body> |
| | | </html> |