bytefun
Version:
一个打通了原型设计、UI设计与代码转换、跨平台原生代码开发等的平台
1,815 lines (1,575 loc) • 96 kB
HTML
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>32号旅游APP 后端API管理系统</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--bg-primary: #1B1B1B;
--bg-secondary: #232323;
--bg-tertiary: #2C2C2C;
--bg-four: #323232;
--text-primary: #FFFFFF;
--text-secondary: #8E8E93;
--border-color: #2C2C2C;
--border-hover-color: #4D4D4D;
--input-bg: #232323;
--success-color: #34C759;
--warning-color: #FF9500;
--error-color: #67211d;
--error-hover-color: #8a2420;
--primary-color: #303d4b;
--primary-hover-color: #485b70;
}
[data-theme="light"] {
--bg-primary: #FDFDFD;
--bg-secondary: #F5F5F5;
--bg-tertiary: #E8E8E8;
--bg-four: #e4e4e4;
--bg-text: #E8E8E8;
--text-primary: #1C1C1E;
--text-secondary: #6D6D70;
--border-color: #D1D1D6;
--border-hover-color: #cdcdd2;
--input-bg: #FFFFFF;
}
body {
font-family: 'Poppins', 'Arial', sans-serif;
background-color: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
transition: background-color 0.3s ease, color 0.3s ease;
}
.container {
margin: 0 auto;
padding: 12px;
max-width: 1400px;
}
.header {
text-align: center;
margin-bottom: 24px;
padding: 20px;
background: linear-gradient(135deg, #007AFF, #5856D6);
color: white;
border-radius: 12px;
position: relative;
}
/* 悬浮模块列表容器 */
.floating-modules-container {
position: fixed;
top: 20px;
left: 20px;
right: 120px;
z-index: 100;
}
/* 右侧按钮组 */
.right-button-group {
position: fixed;
top: 20px;
right: 20px;
display: flex;
flex-direction: column;
gap: 12px;
z-index: 101;
}
.right-btn {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 3px 6px;
cursor: pointer;
font-size: 12px;
color: var(--text-primary);
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 6px;
min-width: 90px;
justify-content: center;
}
.right-btn:hover {
background: var(--bg-tertiary);
border-color: var(--primary-color);
}
.right-btn.add-module {
background: var(--primary-color);
color: white;
}
.right-btn.add-module:hover {
background: var(--primary-hover-color);
}
.right-btn.save {
background: var(--primary-color);
color: white;
}
.right-btn.save:hover {
background: var(--primary-hover-color);
}
/* 右下角悬浮添加API按钮 */
.floating-add-api-btn {
position: fixed;
bottom: 30px;
right: 30px;
width: 40px;
height: 40px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 50%;
cursor: pointer;
font-size: 18px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
z-index: 1000;
}
.floating-add-api-btn:hover {
background: #0056CC;
transform: scale(1.1);
box-shadow: 0 6px 25px rgba(0, 122, 255, 0.4);
}
.floating-add-api-btn:active {
transform: scale(0.95);
}
.floating-modules-list {
display: flex;
gap: 12px;
overflow-x: auto;
background-color: var(--bg-primary);
padding: 4px 6px;
border-radius: 10px;
scrollbar-width: thin;
scrollbar-color: var(--border-color) transparent;
}
.floating-modules-list::-webkit-scrollbar {
height: 6px;
}
.floating-modules-list::-webkit-scrollbar-track {
background: transparent;
}
.floating-modules-list::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 3px;
}
.floating-modules-list::-webkit-scrollbar-thumb:hover {
background: var(--text-secondary);
}
.floating-module-item {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding-right: 5px;
padding-left: 8px;
padding-top: 4px;
padding-bottom: 4px;
cursor: pointer;
transition: all 0.3s ease;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
}
.floating-module-item:hover {
background: var(--bg-tertiary);
border-color: var(--primary-color);
}
.floating-module-item.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.floating-module-info {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
}
.floating-module-name {
font-size: 13px;
font-weight: 500;
color: inherit;
}
.floating-api-count {
background: rgba(255, 255, 255, 0.2);
color: inherit;
padding: 2px 6px;
border-radius: 10px;
font-size: 10px;
font-weight: 600;
}
.floating-module-item.active .floating-api-count {
background: rgba(255, 255, 255, 0.3);
}
.floating-module-actions {
display: flex;
}
.floating-action-btn {
background: transparent;
border: none;
color: var(--text-secondary);
cursor: pointer;
padding: 4px;
border-radius: 4px;
font-size: 12px;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
}
.floating-action-btn:hover {
background: rgba(255, 255, 255, 0.1);
color: var(--text-primary);
}
.floating-module-item.active .floating-action-btn {
color: rgba(255, 255, 255, 0.8);
}
.floating-module-item.active .floating-action-btn:hover {
color: white;
background: rgba(255, 255, 255, 0.2);
}
.floating-action-btn.delete:hover {
color: var(--error-color);
background: rgba(255, 59, 48, 0.1);
}
.header h1 {
font-size: 24px;
font-weight: 700;
margin-bottom: 8px;
}
.header p {
font-size: 16px;
opacity: 0.9;
}
.header-controls {
position: absolute;
top: 20px;
right: 20px;
display: flex;
gap: 12px;
}
.header-btn {
background: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 8px;
padding: 8px 16px;
cursor: pointer;
font-size: 14px;
color: white;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 6px;
}
.header-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.top-module-card {
background: var(--bg-secondary);
border-radius: 12px;
padding: 20px;
margin-bottom: 20px;
border: 1px solid var(--border-color);
margin-top: 20px;
}
.module-section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.module-section-title {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
}
.module-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 16px;
}
.module-grid-item {
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding-left: 16px;
padding-top: 16px;
padding-bottom: 30px;
padding-right: 10px;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.module-grid-item:hover {
background-color: var(--bg-four);
}
.module-grid-item.active {
border-color: var(--primary-color);
background: var(--bg-primary);
box-shadow: 0 4px 12px rgba(0, 122, 255, 0.15);
}
.add-module-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px;
border-radius: 6px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 4px;
transition: all 0.3s ease;
}
.add-module-btn:hover {
background: var(--primary-hover-color);
}
.module-grid-info {
flex: 1;
}
.module-grid-name {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 6px;
line-height: 1.3;
}
.edit-btn {
position: absolute;
bottom: 8px;
right: 60px;
}
.delete-btn {
position: absolute;
bottom: 8px;
right: 8px;
}
.module-grid-action-btn {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
cursor: pointer;
padding: 2px 6px;
border-radius: 3px;
font-size: 10px;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 2px;
}
.module-grid-action-btn:hover {
color: var(--text-primary);
border: 1px solid transparent;
}
.delete-btn:hover {
color: var(--error-color);
border: 1px solid transparent;
}
.api-count {
background: var(--primary-color);
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 11px;
margin-left: 3px;
}
.content-area {
background: var(--bg-secondary);
border-radius: 8px;
padding: 16px;
border: 1px solid var(--border-color);
overflow-y: auto;
min-width: 0;
}
.content-header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.content-title {
font-size: 15px;
font-weight: 600;
color: var(--text-primary);
}
.add-api-btn {
background: var(--primary-color);
color: white;
border: none;
padding: 8px;
border-radius: 8px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 6px;
transition: all 0.3s ease;
}
.add-api-btn:hover {
background: var(--primary-hover-color);
}
.api-list {
display: grid;
gap: 16px;
margin-top: 50px;
}
.api-item {
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 16px;
transition: all 0.3s ease;
}
.api-item:hover {
border-color: var(--primary-color);
}
.api-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
max-width: 600px;
}
.api-basic-info {
flex: 1;
}
.api-name-row {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 6px;
}
.api-name-input {
font-size: 14px;
font-weight: 600;
color: var(--text-primary);
line-height: 1.3;
background: transparent;
border: none;
outline: none;
padding: 3px 6px;
width: auto;
min-width: 100px;
max-width: 300px;
}
.api-name-input:focus {
background: var(--input-bg);
border: 1px solid var(--primary-color);
border-radius: 4px;
}
.api-delete-btn {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
cursor: pointer;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
.api-delete-btn:hover {
color: var(--error-color);
border-color: var(--error-color);
background: rgba(255, 59, 48, 0.1);
}
.api-path {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.method-select {
background: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 4px 8px;
color: var(--text-primary);
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
.api-path-input {
background: transparent;
border: none;
outline: none;
color: var(--text-secondary);
font-family: 'Monaco', monospace;
font-size: 14px;
padding: 2px 4px;
min-width: 300px;
}
.api-path-input:focus {
background: var(--input-bg);
border: 1px solid var(--primary-color);
border-radius: 4px;
}
.auth-checkbox {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: var(--text-secondary);
}
.auth-checkbox input {
width: 14px;
height: 14px;
}
.method-tag {
padding: 3px 6px;
border-radius: 4px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
}
/* 自定义复选框样式 */
.custom-checkbox {
display: inline-flex;
align-items: center;
gap: 6px;
cursor: pointer;
user-select: none;
}
.custom-checkbox input[type="checkbox"] {
display: none;
}
.custom-checkbox .checkbox-icon {
width: 16px;
height: 16px;
border: 1px solid var(--border-color);
border-radius: 3px;
display: flex;
align-items: center;
justify-content: center;
background: var(--input-bg);
transition: all 0.3s ease;
font-size: 10px;
color: transparent;
}
.custom-checkbox input[type="checkbox"]:checked+.checkbox-icon {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.custom-checkbox:hover .checkbox-icon {
border-color: var(--primary-color);
}
/* 自定义下拉选择框样式 */
.custom-select {
position: relative;
display: inline-block;
}
.custom-select select {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
background: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 8px 30px 8px 12px;
color: var(--text-primary);
font-size: 12px;
cursor: pointer;
width: 100%;
transition: all 0.3s ease;
}
/* 自定义下拉选项样式 */
.custom-select select option {
background: var(--bg-secondary);
color: var(--text-primary);
padding: 8px 12px;
border: none;
font-size: 12px;
}
.custom-select select option:hover {
background: var(--bg-tertiary);
color: var(--text-primary);
}
.custom-select select option:checked,
.custom-select select option:selected {
background: var(--primary-color);
color: white;
}
/* Firefox 特殊处理 */
@-moz-document url-prefix() {
.custom-select select {
background-image: none;
}
.custom-select select option {
background-color: var(--bg-secondary);
color: var(--text-primary);
}
.custom-select select option:hover {
background-color: var(--bg-tertiary) !important;
}
.custom-select select option:checked {
background-color: var(--primary-color) !important;
color: white !important;
}
}
/* WebKit 浏览器特殊处理 */
@media screen and (-webkit-min-device-pixel-ratio:0) {
.custom-select select {
background-image: none;
}
.custom-select select option {
background: var(--bg-secondary);
color: var(--text-primary);
}
}
.method-select {
min-width: 80px;
max-width: 100px;
}
.param-select {
min-width: 90px;
max-width: 120px;
}
.custom-select select:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.1);
}
.custom-select::after {
content: '\f107';
font-family: 'Font Awesome 6 Free';
font-weight: 900;
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
color: var(--text-secondary);
pointer-events: none;
transition: transform 0.3s ease;
z-index: 1;
}
.custom-select:hover::after {
color: var(--text-primary);
}
.custom-select:focus-within::after {
transform: translateY(-50%) rotate(180deg);
color: var(--primary-color);
}
/* 自定义下拉菜单样式 */
.custom-dropdown {
position: relative;
display: inline-block;
}
.dropdown-button {
background: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 8px 30px 8px 12px;
color: var(--text-primary);
font-size: 12px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: space-between;
min-width: 80px;
transition: all 0.3s ease;
}
.dropdown-button:hover {
border-color: var(--primary-color);
}
.dropdown-button.active {
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(0, 122, 255, 0.1);
}
.dropdown-arrow {
margin-left: 8px;
transition: transform 0.3s ease;
}
.dropdown-button.active .dropdown-arrow {
transform: rotate(180deg);
}
.dropdown-menu {
position: absolute;
top: 100%;
left: 0;
right: 0;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
opacity: 0;
visibility: hidden;
transform: translateY(-10px);
transition: all 0.3s ease;
max-height: 200px;
overflow-y: auto;
}
.dropdown-menu.show {
opacity: 1;
visibility: visible;
transform: translateY(0);
}
.dropdown-item {
padding: 8px 12px;
cursor: pointer;
transition: background-color 0.2s ease;
font-size: 12px;
color: var(--text-primary);
}
.dropdown-item:hover {
background: var(--bg-tertiary);
}
.dropdown-item.selected {
background: var(--primary-color);
color: white;
}
/* 自定义确认对话框 */
.confirm-dialog-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
display: flex;
align-items: center;
justify-content: center;
z-index: 2000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.confirm-dialog-overlay.show {
opacity: 1;
visibility: visible;
}
.confirm-dialog {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 16px;
padding: 24px;
min-width: 400px;
max-width: 500px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);
transform: scale(0.9) translateY(-20px);
transition: transform 0.3s ease;
}
.confirm-dialog-overlay.show .confirm-dialog {
transform: scale(1) translateY(0);
}
.confirm-dialog-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 16px;
}
.confirm-dialog-icon {
width: 48px;
height: 48px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.confirm-dialog-icon.warning {
background: rgba(255, 149, 0, 0.1);
color: var(--warning-color);
}
.confirm-dialog-icon.danger {
background: rgba(255, 59, 48, 0.1);
color: var(--error-color);
}
.confirm-dialog-icon.info {
background: rgba(0, 122, 255, 0.1);
color: var(--primary-color);
}
.confirm-dialog-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
}
.confirm-dialog-message {
color: var(--text-secondary);
font-size: 14px;
line-height: 1.5;
margin-bottom: 24px;
}
.confirm-dialog-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
}
.confirm-dialog-btn {
padding: 10px 20px;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
min-width: 80px;
}
.confirm-dialog-btn.cancel {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.confirm-dialog-btn.cancel:hover {
background: var(--bg-primary);
}
.confirm-dialog-btn.confirm {
background: var(--error-color);
color: white;
}
.confirm-dialog-btn.confirm:hover {
background: #E5342B;
}
.confirm-dialog-btn.primary {
background: var(--primary-color);
color: white;
}
.confirm-dialog-btn.primary:hover {
background: #0056CC;
}
.method-get {
background: #E3F2FD;
color: #1976D2;
}
.method-post {
background: #E8F5E8;
color: #388E3C;
}
.method-put {
background: #FFF3E0;
color: #F57C00;
}
.method-delete {
background: #FFEBEE;
color: #D32F2F;
}
.api-path-text {
font-family: 'Monaco', monospace;
font-size: 14px;
color: var(--text-secondary);
}
.api-actions {
display: flex;
gap: 8px;
}
.api-action-btn {
background: transparent;
border: 1px solid var(--border-color);
color: var(--text-secondary);
cursor: pointer;
padding: 6px 12px;
border-radius: 6px;
font-size: 12px;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 4px;
}
.api-action-btn:hover {
color: var(--text-primary);
border: 1px solid transparent;
}
.api-action-btn.delete:hover {
color: var(--error-color);
border: 1px solid transparent;
}
.auth-badge {
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
}
.auth-required {
background: #FFEBEE;
color: #D32F2F;
}
.auth-not-required {
background: #E8F5E8;
color: #388E3C;
}
.api-details {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
margin-top: 12px;
}
.detail-section {
background: var(--bg-primary);
border-radius: 4px;
padding: 12px;
}
.response-textarea {
width: 100%;
min-height: auto;
background: var(--bg-primary);
border: none;
border-radius: 0;
padding: 12px;
color: var(--text-primary);
font-family: 'Monaco', 'Consolas', monospace;
font-size: 12px;
line-height: 1.4;
resize: none;
overflow: hidden;
transition: none;
}
.response-textarea:focus {
outline: none;
}
.detail-header {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 8px;
}
.detail-title {
font-size: 13px;
font-weight: 600;
color: var(--text-primary);
}
.add-param-btn-inline {
background: var(--primary-color);
color: white;
border: none;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
font-size: 10px;
display: flex;
align-items: center;
gap: 3px;
transition: all 0.3s ease;
}
.add-param-btn-inline:hover {
background: var(--primary-hover-color);
}
.param-edit-item {
display: grid;
grid-template-columns: 1fr 100px 80px 1fr 30px;
gap: 8px;
padding-bottom: 8px;
align-items: center;
}
.param-edit-item:last-child {
border-bottom: none;
}
.param-input {
background: transparent;
border: none;
outline: none;
color: var(--text-primary);
font-size: 13px;
padding: 4px;
}
.param-input:focus {
background: var(--input-bg);
border: 1px solid var(--primary-color);
border-radius: 4px;
}
.param-select {
background: var(--input-bg);
border: 1px solid var(--border-color);
border-radius: 4px;
padding: 4px;
color: var(--text-primary);
font-size: 12px;
}
.required-checkbox {
display: flex;
align-items: center;
gap: 4px;
font-size: 11px;
color: var(--text-secondary);
}
.required-checkbox input {
width: 12px;
height: 12px;
}
.param-desc-input {
background: transparent;
border: none;
outline: none;
color: var(--text-secondary);
font-size: 12px;
padding: 4px;
}
.param-desc-input:focus {
background: var(--input-bg);
border: 1px solid var(--primary-color);
border-radius: 4px;
}
.remove-param-btn {
background: var(--error-color);
color: white;
border: none;
border-radius: 4px;
padding: 4px;
cursor: pointer;
font-size: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.remove-param-btn:hover {
background: var(--error-hover-color);
}
.param-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid var(--border-color);
}
.param-item:last-child {
border-bottom: none;
}
.param-name {
font-family: 'Monaco', monospace;
font-size: 13px;
color: var(--text-primary);
}
.param-type {
font-size: 12px;
color: var(--text-secondary);
}
.param-required {
background: var(--error-color);
color: white;
padding: 2px 6px;
border-radius: 4px;
font-size: 10px;
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state i {
font-size: 48px;
margin-bottom: 16px;
opacity: 0.5;
}
.empty-state h3 {
font-size: 18px;
margin-bottom: 8px;
}
.empty-state p {
font-size: 14px;
}
/* 模态框样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.3s ease, visibility 0.3s ease;
}
.modal-overlay.show {
opacity: 1;
visibility: visible;
}
.modal {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 12px;
padding: 24px;
min-width: 500px;
max-width: 800px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
transform: scale(0.9);
transition: transform 0.3s ease;
}
.modal-overlay.show .modal {
transform: scale(1);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 16px;
border-bottom: 1px solid var(--border-color);
}
.modal-title {
font-size: 20px;
font-weight: 600;
color: var(--text-primary);
}
.modal-close {
background: transparent;
border: none;
color: var(--text-secondary);
cursor: pointer;
font-size: 20px;
padding: 4px;
}
.modal-close:hover {
color: var(--text-primary);
}
.form-group {
margin-bottom: 20px;
}
.form-label {
display: block;
font-size: 14px;
font-weight: 500;
color: var(--text-primary);
margin-bottom: 8px;
}
.form-input {
width: 100%;
padding: 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
background: var(--input-bg);
color: var(--text-primary);
font-size: 14px;
transition: border-color 0.3s ease;
}
.form-input:focus {
outline: none;
border-color: var(--primary-color);
}
.form-textarea {
min-height: 80px;
resize: vertical;
}
.form-select {
width: 100%;
padding: 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
background: var(--input-bg);
color: var(--text-primary);
font-size: 14px;
cursor: pointer;
}
.form-checkbox {
display: flex;
align-items: center;
gap: 8px;
}
.form-checkbox input {
width: 16px;
height: 16px;
}
.modal-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 24px;
padding-top: 16px;
border-top: 1px solid var(--border-color);
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: #0056CC;
}
.btn-secondary {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.btn-secondary:hover {
background: var(--bg-primary);
}
.params-list {
border: 1px solid var(--border-color);
border-radius: 6px;
background: var(--bg-primary);
}
.param-row {
display: grid;
grid-template-columns: 1fr 100px 80px 60px 40px;
gap: 12px;
padding: 12px;
border-bottom: 1px solid var(--border-color);
align-items: center;
}
.param-row:last-child {
border-bottom: none;
}
.param-row.header {
background: var(--bg-tertiary);
font-weight: 600;
font-size: 12px;
color: var(--text-secondary);
}
.param-input {
padding: 6px 8px;
border: 1px solid var(--border-color);
border-radius: 4px;
background: var(--input-bg);
color: var(--text-primary);
font-size: 12px;
}
.param-select {
padding: 6px 8px;
border: 1px solid var(--border-color);
border-radius: 4px;
background: var(--input-bg);
color: var(--text-primary);
font-size: 12px;
}
.remove-param-btn {
background: var(--error-color);
color: white;
border: none;
border-radius: 4px;
padding: 4px;
cursor: pointer;
font-size: 12px;
}
.add-param-btn {
background: var(--success-color);
color: white;
border: none;
border-radius: 6px;
padding: 8px 12px;
cursor: pointer;
font-size: 12px;
margin-top: 8px;
display: flex;
align-items: center;
gap: 4px;
}
@media (max-width: 1024px) {
.module-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 12px;
}
.content-area {
padding: 12px;
}
.api-item {
padding: 12px;
}
.api-details {
grid-template-columns: 1fr;
gap: 8px;
}
}
@media (max-width: 768px) {
.top-controls {
top: 10px;
right: 10px;
gap: 8px;
}
.control-btn {
font-size: 12px;
padding: 6px 12px;
}
.module-grid {
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 12px;
}
.content-area {
padding: 12px;
border-radius: 6px;
}
}
@media (max-width: 480px) {
.container {
padding: 8px;
}
.top-controls {
top: 8px;
right: 8px;
gap: 6px;
}
.control-btn {
font-size: 11px;
padding: 4px 8px;
}
.top-module-card {
padding: 12px;
margin-bottom: 16px;
border-radius: 8px;
margin-top: 50px;
}
.module-section-title {
font-size: 16px;
}
.module-grid {
grid-template-columns: 1fr;
gap: 8px;
}
.module-grid-item {
padding: 12px;
}
.content-header {
padding-bottom: 8px;
}
.content-title {
font-size: 16px;
}
.add-api-btn {
padding: 8px 12px;
font-size: 12px;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 悬浮业务模块列表 -->
<div class="floating-modules-container">
<div class="floating-modules-list" id="floatingModulesList">
<!-- 动态生成模块列表 -->
</div>
</div>
<!-- 右侧按钮组 -->
<div class="right-button-group">
<button class="right-btn add-module" onclick="showAddModuleModal()">
<i class="fas fa-plus"></i>
<span>添加模块</span>
</button>
<button class="right-btn save" onclick="saveConfig()">
<i class="fas fa-save"></i>
<span>保存</span>
</button>
<button class="right-btn theme-toggle" onclick="toggleTheme()">
<i class="fas fa-sun"></i>
<span id="theme-text">亮色模式</span>
</button>
</div>
<!-- 主内容区 - API列表 -->
<div class="content-area">
<div class="content-header" style="display: none;">
<h2 class="content-title" id="contentTitle">选择一个模块查看API接口</h2>
<button class="add-api-btn" id="addApiBtn" onclick="showAddApiModal()" style="display: none;">
<i class="fas fa-plus"></i>
添加API接口
</button>
</div>
<div class="api-list" id="apiList">
<div class="empty-state">
<i class="fas fa-cube"></i>
<h3>请选择一个业务模块</h3>
<p>从上方选择一个业务模块来查看和管理其API接口</p>
</div>
</div>
</div>
<!-- 右下角悬浮添加API按钮 -->
<button class="floating-add-api-btn" id="floatingAddApiBtn" onclick="showAddApiModal()" style="display: none;"
title="添加API接口">
<i class="fas fa-plus"></i>
</button>
</div>
<!-- 添加/编辑模块模态框 -->
<div class="modal-overlay" id="moduleModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title" id="moduleModalTitle">添加业务模块</h3>
<button class="modal-close" onclick="hideModuleModal()">
<i class="fas fa-times"></i>
</button>
</div>
<form id="moduleForm">
<div class="form-group">
<label class="form-label">模块英文名称</label>
<input type="text" class="form-input" id="moduleEnName" placeholder="例如:accountBizModule" required>
</div>
<div class="form-group">
<label class="form-label">模块中文名称</label>
<input type="text" class="form-input" id="moduleCnName" placeholder="例如:账号系统业务模块" required>
</div>
<div class="form-group">
<label class="form-label">模块描述</label>
<textarea class="form-input form-textarea" id="moduleDescription"
placeholder="描述该模块的主要功能和业务范围"></textarea>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideModuleModal()">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
<!-- 添加/编辑API模态框 -->
<div class="modal-overlay" id="apiModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title" id="apiModalTitle">添加API接口</h3>
<button class="modal-close" onclick="hideApiModal()">
<i class="fas fa-times"></i>
</button>
</div>
<form id="apiForm">
<div class="form-group">
<label class="form-label">API英文名称</label>
<input type="text" class="form-input" id="apiEnName" placeholder="例如:sendSmsCode" required>
</div>
<div class="form-group">
<label class="form-label">API中文名称</label>
<input type="text" class="form-input" id="apiName" placeholder="例如:发送短信验证码" required>
</div>
<div class="form-group">
<label class="form-label">请求方法</label>
<div class="custom-select">
<select class="form-select" id="apiMethod" required>
<option value="GET">GET</option>
<option value="POST">POST</option>
<option value="PUT">PUT</option>
<option value="DELETE">DELETE</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label class="form-label">API路径</label>
<input type="text" class="form-input" id="apiPath" placeholder="例如:/client/biz/auth/send/code" required>
</div>
<div class="form-group">
<label class="custom-checkbox form-checkbox">
<input type="checkbox" id="apiAuth">
<span class="checkbox-icon"><i class="fas fa-check"></i></span>
<span class="form-label">需要身份验证</span>
</label>
</div>
<div class="form-group">
<label class="form-label">请求参数</label>
<div class="params-list" id="paramsList">
<div class="param-row header">
<div>参数名称</div>
<div>参数类型</div>
<div>是否必需</div>
<div>描述</div>
<div>操作</div>
</div>
</div>
<button type="button" class="add-param-btn" onclick="addParameterToModal()">
<i class="fas fa-plus"></i>
添加参数
</button>
</div>
<div class="form-group">
<label class="form-label">响应结构</label>
<textarea class="form-input form-textarea response-textarea" id="apiResponse" oninput="autoResize(this)"
placeholder="请输入响应结构的JSON格式,例如:\n{\n \" code\": 0,\n \"msg\": \"success\",\n \"data\":
{}\n}"></textarea>
</div>
<div class="modal-actions">
<button type="button" class="btn btn-secondary" onclick="hideApiModal()">取消</button>
<button type="submit" class="btn btn-primary">保存</button>
</div>
</form>
</div>
</div>
<!-- 自定义确认对话框 -->
<div class="confirm-dialog-overlay" id="confirmDialog">
<div class="confirm-dialog">
<div class="confirm-dialog-header">
<div class="confirm-dialog-icon" id="confirmIcon">
<i class="fas fa-exclamation-triangle"></i>
</div>
<h3 class="confirm-dialog-title" id="confirmTitle">确认操作</h3>
</div>
<div class="confirm-dialog-message" id="confirmMessage">
您确定要执行此操作吗?
</div>
<div class="confirm-dialog-actions">
<button class="confirm-dialog-btn cancel" onclick="hideConfirmDialog(false)">取消</button>
<button class="confirm-dialog-btn confirm" id="confirmBtn" onclick="hideConfirmDialog(true)">确认</button>
</div>
</div>
</div>
<script>
// 全局变量
let apiConfig = {
projectName: "32号旅游",
moduleList: []
};
let currentModuleIndex = -1;
let editingModuleIndex = -1;
let editingApiIndex = -1;
// 初始化
document.addEventListener('DOMContentLoaded', function () {
loadConfig();
renderModuleList();
// 默认选中第一个业务模块
if (apiConfig.moduleList && apiConfig.moduleList.length > 0) {
selectModule(0);
}
});
// 从JSON字符串导入数据
function importDataFromString(jsonString) {
try {
const importedData = JSON.parse(jsonString);
// 验证数据结构
if (validateApiConfigStructure(importedData)) {
apiConfig = importedData;
currentModuleIndex = -1;
renderModuleList();
renderApiList();
// 默认选中第一个业务模块
if (apiConfig.moduleList && apiConfig.moduleList.length > 0) {
selectModule(0);
}
console.log('后端API配置数据导入成功');
return true;
} else {
console.error('导入失败:JSON格式不正确');
return false;
}
} catch (error) {
console.error('导入失败:', error.message);
return false;
}
}
// 验证API配置数据结构
function validateApiConfigStructure(data) {
return data &&
typeof data.projectName === 'string' &&
Array.isArray(data.moduleList);
}
// 加载配置
async function loadConfig() {
try {
// 配置数据将通过VS Code扩展的postMessage传递过来
// 这里只是初始化默认配置,等待外部数据传入
console.log('🔧 [后端设计] 等待配置数据传入...');
apiConfig = {
"projectName": "后端工程",
"moduleList": [
{
"moduleEnName": "accountSystemBizModule",
"moduleCnNam