UNPKG

bytefun

Version:

一个打通了原型设计、UI设计与代码转换、跨平台原生代码开发等的平台

2,821 lines 96 kB
<!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",
                            "moduleCnName": "账号系统业务模块",
                            "description": "包括发送短信验证码、手机号登录、手机号注册、注销(退出)、账号密码登录业务服务",
                            "apiList": [
                                {
                                    "apiEnName": "sendSmsCode",
                                    "name": "发送短信验证码",
                                    "method": "POST",
                                    "path": "/client/biz/auth/send/code",
                                    "auth": "false",
                                    "headers": {
                                        "Content-Type": "application/json"
                                    },
                                    "parameters": [
                                        {
                                            "name": "mobile",
                                            "type": "string",
                                            "required": "true",
                                            "description": "手机号"
                                        }
                                    ],
                                    "responses": {
                                        "type": "object",
                                        "properties": {
                                            "code": {
                                                "type": "integer",
                                                "description": "编码 0表示成功,其他值表示失败"
                                            },
                                            "msg": {
                                                "type": "string",
                                                "description": "消息内容"
                                            },
                                            "data": {
                                                "type": "string",
                                                "description": "响应数据"
                                            }
                                        },
                                        "description": "响应"
                                    }
                                }
                            ]
                        }
                    ]
                }
                // 如果已经有配置数据,则渲染
                if (apiConfig.moduleList && apiConfig.moduleList.length > 0) {
                    renderModuleList();
                    selectModule(0);
                }
            } catch (error) {
                console.log('配置文件加载失败,使用默认配置');
                // 即使配置加载失败,也尝试选中第一个模块(如果有的话)
                if (apiConfig.moduleList && apiConfig.moduleList.length > 0) {
                    selectModule(0);
                }
            }
        }

        // 渲染悬浮模块列表
        function renderModuleList() {
            const modulesList = document.getElementById('floatingModulesList');
            modulesList.innerHTML = '';

            apiConfig.moduleList.forEach((module, index) => {
                const moduleItem = document.createElement('div');
                moduleItem.className = 'floating-module-item';
                if (index === currentModuleIndex) {
                    moduleItem.classList.add('active');
                }

                moduleItem.innerHTML = `
                    <div class="floating-module-info" onclick="selectModule(${index})">
                        <span class="floating-module-name">${module.moduleCnName}</span>
                        <span class="floating-api-count">${module.apiList ? module.apiList.length : 0}</span>
                    </div>
                    <div class="floating-module-actions">
                        <button class="floating-action-btn" onclick="event.stopPropagation(); editModule(${index})" title="编辑模块">
                            <i class="fas fa-edit"></i>
                        </button>
                        <button class="floating-action-btn delete" onclick="event.stopPropagation(); deleteModule(${index})" title="删除模块">
                            <i class="fas fa-trash"></i>
                        </button>
                    </div>
                `;

                modulesList.appendChild(moduleItem);
            });
        }

        // 选择模块
        function selectModule(index) {
            currentModuleIndex = index;
            renderModuleList();
            renderApiList();
        }

        // 渲染API列表
        function renderApiList() {
            const apiList = document.getElementById('apiList');
            const floatingAddApiBtn = document.getElementById('floatingAddApiBtn');

            if (currentModuleIndex === -1 || !apiConfig.moduleList[currentModuleIndex]) {
                floatingAddApiBtn.style.display = 'none';
                apiList.innerHTML = `
                    <div class="empty-state">
                        <i class="fas fa-cube"></i>
                        <h3>请选择一个业务模块</h3>
                        <p>从上方选择一个业务模块来查看和管理其API接口</p>
                    </div>
                `;
                return;
            }

            const currentModule = apiConfig.moduleList[currentModuleIndex];
            floatingAddApiBtn.style.display = 'flex';

            if (!currentModule.apiList || currentModule.apiList.length === 0) {
                apiList.innerHTML = `
                    <div class="empty-state">
                        <i class="fas fa-code"></i>
                        <h3>暂无API接口</h3>
                        <p>点击右下角的悬浮按钮来创建第一个接口</p>
                    </div>
                `;
                return;
            }

            apiList.innerHTML = '';
            currentModule.apiList.forEach((api, index) => {
                const apiItem = document.createElement('div');
                apiItem.className = 'api-item';
                apiItem.setAttribute('data-path', api.path || ''); // 添加data-path属性用于定位

                const methodClass = `method-${api.method.toLowerCase()}`;

                apiItem.innerHTML = `
                    <div class="api-header">
                        <div class="api-basic-info">
                            <div class="api-name-row">
                                <input class="api-name-input" value="${api.name}" onchange="updateApiField(${index}, 'name', this.value)" oninput="autoResizeInput(this)" placeholder="API名称">
                                <button class="api-delete-btn" onclick="deleteApi(${index})" title="删除接口">
                                    <i class="fas fa-trash"></i>
                                </button>
                            </div>
                            <div class="api-path">
                                <div class="custom-select">
                                    <select class="method-select" onchange="updateApiField(${index}, 'method', this.value)">
                                    <option value="GET" ${api.method === 'GET' ? 'selected' : ''}>GET</option>
                                    <option value="POST" ${api.method === 'POST' ? 'selected' : ''}>POST</option>
                                    <option value="PUT" ${api.method === 'PUT' ? 'selected' : ''}>PUT</option>
                                    <option value="DELETE" ${api.method === 'DELETE' ? 'selected' : ''}>DELETE</option>
                                    </select>
                                </div>
                                <label class="custom-checkbox auth-checkbox">
                                    <input type="checkbox" ${api.auth === 'true' || api.auth === true ? 'checked' : ''} onchange="updateApiField(${index}, 'auth', this.checked)">
                                    <span class="checkbox-icon"><i class="fas fa-check"></i></span>
                                    <span>需要认证</span>
                                </label>
                                <input class="api-path-input" value="${api.path}" onchange="updateApiField(${index}, 'path', this.value)" placeholder="/api/path">
                            </div>
                        </div>
                    </div>
                    <div class="api-details">
                        <div class="detail-section">
                            <div class="detail-header">
                                <div class="detail-title">请求参数</div>
                                <button class="add-param-btn-inline" onclick="addParameter(${index})">
                                    <i class="fas fa-plus"></i>
                                    参数
                                </button>
                            </div>
                            <div class="parameters-list" id="params-${index}">
                                ${renderEditableParameters(api.parameters || [], index)}
                            </div>
                        </div>
                        <div class="detail-section">
                            <div class="detail-title">响应结构</div>
                            <textarea class="response-textarea" id="response-${index}" onchange="updateApiField(${index}, 'responses', this.value)" oninput="autoResize(this)" placeholder="请输入响应结构的JSON格式">${api.responses ? (typeof api.responses === 'string' ? api.responses : JSON.stringify(api.responses, null, 2)) : ''}</textarea>
                        </div>
                    </div>
                `;

                apiList.appendChild(apiItem);
            });

            // 初始化新渲染的textarea高度和输入框宽度
            setTimeout(() => {
                initializeTextareaHeights();
                initializeInputWidths();
            }, 50);
        }

        // 渲染可编辑参数列表
        function renderEditableParameters(parameters, apiIndex) {
            if (!parameters || parameters.length === 0) {
                return '<div class="param-item"><span class="param-type">暂无参数</span></div>';
            }

            return parameters.map((param, paramIndex) => `
                <div class="param-edit-item">
                    <input class="param-input" value="${param.name}" onchange="updateParameter(${apiIndex}, ${paramIndex}, 'name', this.value)" placeholder="参数名">
                    <div class="custom-select">
                        <select class="param-select" onchange="updateParameter(${apiIndex}, ${paramIndex}, 'type', this.value)">
                        <option value="string" ${param.type === 'string' ? 'selected' : ''}>string</option>
                        <option value="number" ${param.type === 'number' ? 'selected' : ''}>number</option>
                        <option value="boolean" ${param.type === 'boolean' ? 'selected' : ''}>boolean</option>
                         <option value="object" ${param.type === 'object' ? 'selected' : ''}>object</option>
                         <option value="array" ${param.type === 'array' ? 'selected' : ''}>array</option>
                         </select>
                     </div>
                    <label class="custom-checkbox required-checkbox">
                        <input type="checkbox" ${param.required === 'true' || param.required === true ? 'checked' : ''} onchange="updateParameter(${apiIndex}, ${paramIndex}, 'required', this.checked)">
                        <span class="checkbox-icon"><i class="fas fa-check"></i></span>
                        <span>必需</span>
                    </label>
                    <input class="param-desc-input" value="${param.description || ''}" onchange="updateParameter(${apiIndex}, ${paramIndex}, 'description', this.value)" placeholder="参数描述">
                    <button class="remove-param-btn" onclick="removeParameterByElement(this, ${apiIndex})">
                        <i class="fas fa-times"></i>
                    </button>
                </div>
            `).join('');
        }

        // 更新API字段
        function updateApiField(apiIndex, field, value) {
            if (apiConfig.moduleList[currentModuleIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex]) {
                if (field === 'responses') {
                    // 尝试解析JSON,如果失败则保存为字符串
                    try {
                        apiConfig.moduleList[currentModuleIndex].apiList[apiIndex][field] = JSON.parse(value);
                    } catch (e) {
                        apiConfig.moduleList[currentModuleIndex].apiList[apiIndex][field] = value;
                    }
                } else {
                    apiConfig.moduleList[currentModuleIndex].apiList[apiIndex][field] = value;
                }
            }
        }

        // 更新参数
        function updateParameter(apiIndex, paramIndex, field, value) {
            if (apiConfig.moduleList[currentModuleIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters[paramIndex]) {
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters[paramIndex][field] = value;
            }
        }

        // 添加参数
        function addParameter(apiIndex) {
            if (!apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters) {
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters = [];
            }
            apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters.push({
                name: '',
                type: 'string',
                required: false,
                description: ''
            });
            renderApiList();
        }

        // 通过DOM元素移除参数
        function removeParameterByElement(button, apiIndex) {
            // 找到参数容器
            const paramItem = button.closest('.param-edit-item');
            if (!paramItem) {
                console.error('无法找到参数项容器');
                return;
            }

            // 找到参数在列表中的索引
            const paramsList = paramItem.parentElement;
            const paramItems = paramsList.querySelectorAll('.param-edit-item');
            let paramIndex = -1;

            for (let i = 0; i < paramItems.length; i++) {
                if (paramItems[i] === paramItem) {
                    paramIndex = i;
                    break;
                }
            }

            if (paramIndex === -1) {
                console.error('无法确定参数索引');
                return;
            }

            console.log('删除参数:', apiIndex, paramIndex);

            // 从数据中删除参数
            if (apiConfig.moduleList[currentModuleIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters[paramIndex] !== undefined) {
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters.splice(paramIndex, 1);
                renderApiList();
            } else {
                console.error('删除参数失败,参数不存在:', {
                    currentModuleIndex,
                    apiIndex,
                    paramIndex,
                    hasModule: !!apiConfig.moduleList[currentModuleIndex],
                    hasApi: !!(apiConfig.moduleList[currentModuleIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex]),
                    hasParams: !!(apiConfig.moduleList[currentModuleIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters)
                });
            }
        }

        // 移除参数(保留原函数以防其他地方调用)
        function removeParameter(apiIndex, paramIndex) {
            console.log('删除参数:', apiIndex, paramIndex);
            if (apiConfig.moduleList[currentModuleIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex] &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters &&
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters[paramIndex] !== undefined) {
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters.splice(paramIndex, 1);
                renderApiList();
            } else {
                console.error('删除参数失败,参数不存在:', {
                    currentModuleIndex,
                    apiIndex,
                    paramIndex,
                    hasModule: !!apiConfig.moduleList[currentModuleIndex],
                    hasApi: !!(apiConfig.moduleList[currentModuleIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex]),
                    hasParams: !!(apiConfig.moduleList[currentModuleIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex] && apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters)
                });
            }
        }

        // 显示添加模块模态框
        function showAddModuleModal() {
            editingModuleIndex = -1;
            document.getElementById('moduleModalTitle').textContent = '添加业务模块';
            document.getElementById('moduleForm').reset();
            document.getElementById('moduleModal').classList.add('show');
        }

        // 编辑模块
        function editModule(index) {
            editingModuleIndex = index;
            const module = apiConfig.moduleList[index];

            document.getElementById('moduleModalTitle').textContent = '编辑业务模块';
            document.getElementById('moduleEnName').value = module.moduleEnName || '';
            document.getElementById('moduleCnName').value = module.moduleCnName || '';
            document.getElementById('moduleDescription').value = module.description || '';

            document.getElementById('moduleModal').classList.add('show');
        }

        // 隐藏模块模态框
        function hideModuleModal() {
            document.getElementById('moduleModal').classList.remove('show');
        }

        // 删除模块
        function deleteModule(index) {
            showConfirmDialog(
                '删除模块',
                '确定要删除这个模块吗?这将同时删除该模块下的所有API接口。',
                'danger',
                function () {
                    apiConfig.moduleList.splice(index, 1);
                    if (currentModuleIndex === index) {
                        currentModuleIndex = -1;
                    } else if (currentModuleIndex > index) {
                        currentModuleIndex--;
                    }
                    renderModuleList();
                    renderApiList();
                }
            );
        }

        // 添加新API
        function showAddApiModal() {
            if (currentModuleIndex === -1) {
                showAlert('提示', '请先选择一个模块', 'info');
                return;
            }

            const newApi = {
                apiEnName: '',
                name: '新API接口',
                method: 'POST',
                path: '/api/new',
                auth: 'false',
                headers: {
                    "Content-Type": "application/json"
                },
                parameters: [],
                responses: {
                    type: "object",
                    properties: {
                        code: {
                            type: "integer",
                            description: "编码 0表示成功,其他值表示失败"
                        },
                        msg: {
                            type: "string",
                            description: "消息内容"
                        },
                        data: {
                            type: "object",
                            description: "响应数据"
                        }
                    },
                    description: "响应"
                }
            };

            if (!apiConfig.moduleList[currentModuleIndex].apiList) {
                apiConfig.moduleList[currentModuleIndex].apiList = [];
            }
            apiConfig.moduleList[currentModuleIndex].apiList.push(newApi);
            renderModuleList();
            renderApiList();
        }

        // 编辑API
        function editApi(index) {
            editingApiIndex = index;
            const api = apiConfig.moduleList[currentModuleIndex].apiList[index];

            document.getElementById('apiModalTitle').textContent = '编辑API接口';
            document.getElementById('apiEnName').value = api.apiEnName || '';
            document.getElementById('apiName').value = api.name || '';
            document.getElementById('apiMethod').value = api.method || 'POST';
            document.getElementById('apiPath').value = api.path || '';
            document.getElementById('apiAuth').checked = api.auth === 'true' || api.auth === true;
            document.getElementById('apiResponse').value = api.responses ? (typeof api.responses === 'string' ? api.responses : JSON.stringify(api.responses, null, 2)) : '';

            // 渲染参数列表
            const paramsList = document.getElementById('paramsList');
            paramsList.innerHTML = `
                <div class="param-row header">
                    <div>参数名称</div>
                    <div>参数类型</div>
                    <div>是否必需</div>
                    <div>描述</div>
                    <div>操作</div>
                </div>
            `;

            if (api.parameters && api.parameters.length > 0) {
                api.parameters.forEach(param => {
                    addParameterRow(param);
                });
            }

            document.getElementById('apiModal').classList.add('show');
        }

        // 隐藏API模态框
        function hideApiModal() {
            document.getElementById('apiModal').classList.remove('show');
        }

        // 删除API
        function deleteApi(index) {
            showConfirmDialog(
                '删除API接口',
                '确定要删除这个API接口吗?',
                'danger',
                function () {
                    apiConfig.moduleList[currentModuleIndex].apiList.splice(index, 1);
                    renderModuleList();
                    renderApiList();
                }
            );
        }

        // 添加参数到模态框
        function addParameterToModal() {
            addParameterRow();
        }

        // 添加参数到API列表
        function addParameter(apiIndex) {
            if (!apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters) {
                apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters = [];
            }
            apiConfig.moduleList[currentModuleIndex].apiList[apiIndex].parameters.push({
                name: '',
                type: 'string',
                required: false,
                description: ''
            });
            renderApiList();
        }

        // 添加参数行
        function addParameterRow(param = null) {
            const paramsList = document.getElementById('paramsList');
            const paramRow = document.createElement('div');
            paramRow.className = 'param-row';

            paramRow.innerHTML = `
                <input type="text" class="param-input" placeholder="参数名" value="${param?.name || ''}">
                <div class="custom-select">
                    <select class="param-select">
                        <option value="string" ${param?.type === 'string' ? 'selected' : ''}>string</option>
                        <option value="number" ${param?.type === 'number' ? 'selected' : ''}>number</option>
                        <option value="boolean" ${param?.type === 'boolean' ? 'selected' : ''}>boolean</option>
                        <option value="object" ${param?.type === 'object' ? 'selected' : ''}>object</option>
                        <option value="array" ${param?.type === 'array' ? 'selected' : ''}>array</option>
                    </select>
                </div>
                <div class="custom-select">
                    <select class="param-select">
                        <option value="true" ${param?.required === 'true' || param?.required === true ? 'selected' : ''}>必需</option>
                        <option value="false" ${param?.required === 'false' || param?.required === false ? 'selected' : ''}>可选</option>
                    </select>
                </div>
                <input type="text" class="param-input" placeholder="参数描述" value="${param?.description || ''}">
                <button type="button" class="remove-param-btn" onclick="removeParameterFromModal(this)">
                    <i class="fas fa-times"></i>
                </button>
            `;

            paramsList.appendChild(paramRow);
        }

        // 移除参数
        function removeParameter(button) {
            let parent = button.parentElement;
            while (parent && !parent.classList.contains('param-row') && !parent.classList.contains('param-edit-item')) {
                parent = parent.parentElement;
            }
            if (parent) {
                parent.remove();
            }
        }

        // 移除模态框中的参数
        function removeParameterFromModal(button) {
            let parent = button.parentElement;
            while (parent && !parent.classList.contains('param-row')) {
                parent = parent.parentElement;
            }
            if (parent) {
                parent.remove();
            }
        }

        // 处理模块表单提交
        document.getElementById('moduleForm').addEventListener('submit', function (e) {
            e.preventDefault();

            const moduleData = {
                moduleEnName: document.getElementById('moduleEnName').value,
                moduleCnName: document.getElementById('moduleCnName').value,
                description: document.getElementById('moduleDescription').value,
                apiList: []
            };

            if (editingModuleIndex === -1) {
                // 添加新模块
                apiConfig.moduleList.push(moduleData);
            } else {
                // 编辑现有模块
                const existingModule = apiConfig.moduleList[editingModuleIndex];
                moduleData.apiList = existingModule.apiList || [];
                apiConfig.moduleList[editingModuleIndex] = moduleData;
            }

            renderModuleList();
            hideModuleModal();
        });

        // 处理API表单提交
        document.getElementById('apiForm').addEventListener('submit', function (e) {
            e.preventDefault();

            // 收集参数
            const paramRows = document.querySelectorAll('#paramsList .param-row:not(.header)');
            const parameters = [];

            paramRows.forEach(row => {
                const inputs = row.querySelectorAll('input, select');
                if (inputs[0].value.trim()) {
                    parameters.push({
                        name: inputs[0].value.trim(),
                        type: inputs[1].value,
                        required: inputs[2].value,
                        description: inputs[3].value.trim()
                    });
                }
            });

            // 处理响应结构
            let responseData;
            const responseText = document.getElementById('apiResponse').value.trim();
            if (responseText) {
                try {
                    responseData = JSON.parse(responseText);
                } catch (e) {
                    responseData = responseText; // 如果不是有效JSON,保存为字符串
                }
            } else {
                responseData = {
                    type: "object",
                    properties: {
                        code: {
                            type: "integer",
                            description: "编码 0表示成功,其他值表示失败"
                        },
                        msg: {
                            type: "string",
                            description: "消息内容"
                        },
                        data: {
                            type: "object",
                            description: "响应数据"
                        }
                    },
                    description: "响应"
                };
            }

            const apiData = {
                apiEnName: document.getElementById('apiEnName').value,
                name: document.getElementById('apiName').value,
                method: document.getElementById('apiMethod').value,
                path: document.getElementById('apiPath').value,
                auth: document.getElementById('apiAuth').checked ? 'true' : 'false',
                headers: {
                    "Content-Type": "application/json"
                },
                parameters: parameters,
                responses: responseData
            };

            let isNewApi = false;
            let newApiIndex = -1;

            if (editingApiIndex === -1) {
                // 添加新API
                if (!apiConfig.moduleList[currentModuleIndex].apiList) {
                    apiConfig.moduleList[currentModuleIndex].apiList = [];
                }
                apiConfig.moduleList[currentModuleIndex].apiList.push(apiData);
                newApiIndex = apiConfig.moduleList[currentModuleIndex].apiList.length - 1;
                isNewApi = true;
            } else {
                // 编辑现有API
                apiConfig.moduleList[currentModuleIndex].apiList[editingApiIndex] = apiData;
                newApiIndex = editingApiIndex;
            }

            renderModuleList();
            renderApiList();
            hideApiModal();

            // 如果是新添加的API,滚动到新添加的接口卡片
            if (isNewApi) {
                setTimeout(() => {
                    scrollToNewApi(newApiIndex);
                }, 100);
            }
        });

        // 导入配置
        function importConfig() {
            const input = document.createElement('input');
            input.type = 'file';
            input.accept = '.json';
            input.onchange = function (e) {
                const file = e.target.files[0];
                if (file) {
                    const reader = new FileReader();
                    reader.onload = function (e) {
                        try {
                            const config = JSON.parse(e.target.result);
                            apiConfig = config;
                            currentModuleIndex = -1;
                            renderModuleList();
                            renderApiList();
                            showAlert('导入成功', '配置导入成功!', 'info');
                        } catch (error) {
                            showAlert('导入失败', '配置文件格式错误!', 'danger');
                        }
                    };
                    reader.readAsText(file);
                }
            };
            input.click();
        }

        // 导出配置
        function exportConfig() {
            const dataStr = JSON.stringify(apiConfig, null, 2);
            const dataBlob = new Blob([dataStr], { type: 'application/json' });
            const url = URL.createObjectURL(dataBlob);
            const link = document.createElement('a');
            link.href = url;
            link.download = 'backend-design-config.json';
            link.click();
            URL.revokeObjectURL(url);
        }



        // 主题切换
        function toggleTheme() {
            const body = document.body;
            const themeText = document.getElementById('theme-text');
            const themeIcon = document.querySelector('.theme-toggle i');

            if (body.hasAttribute('data-theme')) {
                body.removeAttribute('data-theme');
                themeText.textContent = '亮色模式';
                themeIcon.className = 'fas fa-sun';
            } else {
                body.setAttribute('data-theme', 'light');
                themeText.textContent = '暗色模式';
                themeIcon.className = 'fas fa-moon';
            }
        }

        // 自定义确认对话框
        let confirmCallback = null;

        function showConfirmDialog(title, message, type = 'warning', callback = null) {
            const overlay = document.getElementById('confirmDialog');
            const titleEl = document.getElementById('confirmTitle');
            const messageEl = document.getElementById('confirmMessage');
            const iconEl = document.getElementById('confirmIcon');
            const confirmBtn = document.getElementById('confirmBtn');

            titleEl.textContent = title;
            messageEl.textContent = message;
            confirmCallback = callback;

            // 设置图标和样式
            iconEl.className = `confirm-dialog-icon ${type}`;
            if (type === 'danger') {
                iconEl.innerHTML = '<i class="fas fa-exclamation-triangle"></i>';
                confirmBtn.className = 'confirm-dialog-btn confirm';
                confirmBtn.textContent = '删除';
            } else if (type === 'warning') {
                iconEl.innerHTML = '<i class="fas fa-exclamation-triangle"></i>';
                confirmBtn.className = 'confirm-dialog-btn primary';
                confirmBtn.textContent = '确认';
            } else if (type === 'info') {
                iconEl.innerHTML = '<i class="fas fa-info-circle"></i>';
                confirmBtn.className = 'confirm-dialog-btn primary';
                confirmBtn.textContent = '确认';
            }

            overlay.classList.add('show');
        }

        function hideConfirmDialog(confirmed) {
            const overlay = document.getElementById('confirmDialog');
            overlay.classList.remove('show');

            if (confirmed && confirmCallback) {
                confirmCallback();
            }
            confirmCallback = null;
        }

        function showAlert(title, message, type = 'info') {
            showConfirmDialog(title, message, type, null);
            // 隐藏取消按钮,只显示确认按钮
            const cancelBtn = document.querySelector('.confirm-dialog-btn.cancel');
            const confirmBtn = document.getElementById('confirmBtn');
            cancelBtn.style.display = 'none';
            confirmBtn.textContent = '确定';
            confirmBtn.className = 'confirm-dialog-btn primary';

            // 重新显示取消按钮(为下次使用准备)
            setTimeout(() => {
                cancelBtn.style.display = 'block';
            }, 300);
        }

        // 自动调整textarea高度
        function autoResize(textarea) {
            textarea.style.height = 'auto';
            textarea.style.height = textarea.scrollHeight + 'px';
        }

        // 自动调整输入框宽度
        function autoResizeInput(input) {
            // 创建一个临时的span元素来测量文字宽度
            const tempSpan = document.createElement('span');
            tempSpan.style.visibility = 'hidden';
            tempSpan.style.position = 'absolute';
            tempSpan.style.fontSize = window.getComputedStyle(input).fontSize;
            tempSpan.style.fontFamily = window.getComputedStyle(input).fontFamily;
            tempSpan.style.fontWeight = window.getComputedStyle(input).fontWeight;
            tempSpan.textContent = input.value || input.placeholder;

            document.body.appendChild(tempSpan);
            const textWidth = tempSpan.offsetWidth;
            document.body.removeChild(tempSpan);

            // 设置输入框宽度,加上一些padding
            const newWidth = Math.max(100, Math.min(300, textWidth + 20));
            input.style.width = newWidth + 'px';
        }

        // 初始化所有response textarea的高度
        function initializeTextareaHeights() {
            const textareas = document.querySelectorAll('.response-textarea');
            textareas.forEach(textarea => {
                if (textarea.value.trim()) {
                    autoResize(textarea);
                }
            });
        }

        // 初始化所有API名称输入框的宽度
        function initializeInputWidths() {
            const inputs = document.querySelectorAll('.api-name-input');
            inputs.forEach(input => {
                autoResizeInput(input);
            });
        }

        // 滚动到接口列表底部
        function scrollToNewApi(apiIndex) {
            const apiList = document.getElementById('apiList');
            if (apiList) {
                // 滚动到接口列表的底部
                apiList.scrollTo({
                    top: apiList.scrollHeight,
                    behavior: 'smooth'
                });

                // 如果有新添加的接口,给它添加高亮效果
                const apiItems = document.querySelectorAll('.api-item');
                if (apiItems[apiIndex]) {
                    // 添加高亮效果
                    apiItems[apiIndex].style.transition = 'all 0.3s ease';
                    apiItems[apiIndex].style.backgroundColor = 'rgba(0, 122, 255, 0.1)';
                    apiItems[apiIndex].style.borderColor = 'var(--primary-color)';

                    // 3秒后移除高亮效果
                    setTimeout(() => {
                        apiItems[apiIndex].style.backgroundColor = '';
                        apiItems[apiIndex].style.borderColor = '';
                    }, 3000);
                }
            }
        }

        // 点击模态框外部关闭
        document.addEventListener('click', function (e) {
            if (e.target.classList.contains('modal-overlay')) {
                e.target.classList.remove('show');
            }
            if (e.target.classList.contains('confirm-dialog-overlay')) {
                hideConfirmDialog(false);
            }
        });

        // 全局VSCode API实例
        let vsCodeApi = null;

        // VSCode webview消息监听器
        if (typeof acquireVsCodeApi !== 'undefined') {
            vsCodeApi = acquireVsCodeApi();
            window.addEventListener('message', function (event) {
                const message = event.data;
                if (message.command === 'importBackendDesignData') {
                    try {
                        console.log('🔧 [后端设计] 收到配置数据,正在导入...');
                        importDataFromString(message.data);
                        console.log('🔧 [后端设计] 配置数据导入成功');
                    } catch (error) {
                        console.error('❌ [后端设计] 导入配置数据失败:', error);
                    }
                }
            });
        }

        // 保存配置功能
        function saveConfig() {
            try {
                const dataStr = JSON.stringify(apiConfig, null, 2);
                // 通过VSCode webview API发送数据
                if (vsCodeApi) {
                    vsCodeApi.postMessage({
                        command: 'saveConfig',
                        data: dataStr
                    });
                } else {
                    // 如果不在VSCode环境中,则下载文件作为备用方案
                    const dataBlob = new Blob([dataStr], { type: 'application/json' });
                    const url = URL.createObjectURL(dataBlob);
                    const link = document.createElement('a');
                    link.href = url;
                    link.download = 'backend-design-config.json';
                    document.body.appendChild(link);
                    link.click();
                    document.body.removeChild(link);
                    URL.revokeObjectURL(url);
                }

                // 显示保存成功提示
                const saveButton = document.querySelector('.right-btn.save');
                if (saveButton) {
                    const originalText = saveButton.innerHTML;
                    saveButton.innerHTML = '<i class="fas fa-check"></i><span>已保存</span>';
                    saveButton.style.background = '#34C759';

                    setTimeout(() => {
                        saveButton.innerHTML = originalText;
                        saveButton.style.background = '';
                    }, 2000);
                }
            } catch (error) {
                console.error('保存配置失败:', error);
                // 保存失败时显示在按钮上
                const saveButton = document.querySelector('.right-btn.save');
                if (saveButton) {
                    const originalText = saveButton.innerHTML;
                    saveButton.innerHTML = '<i class="fas fa-times"></i><span>保存失败</span>';
                    saveButton.style.background = '#FF3B30';

                    setTimeout(() => {
                        saveButton.innerHTML = originalText;
                        saveButton.style.background = '';
                    }, 2000);
                }
            }
        }

        /**
         * 根据API路径滚动到指定的API卡片
         */
        function scrollToApiByPath(apiPath) {
            try {
                console.log('[Backend Design] 尝试滚动到API:', apiPath);

                // 查找具有指定data-path属性的API item
                const apiItem = document.querySelector(`[data-path="${apiPath}"]`);

                if (apiItem) {
                    console.log('[Backend Design] 找到API卡片,开始滚动');

                    // 滚动到API item,并添加高亮效果
                    apiItem.scrollIntoView({
                        behavior: 'smooth',
                        block: 'center'
                    });

                    // 添加临时高亮效果
                    apiItem.style.border = '2px solid #007AFF';
                    apiItem.style.boxShadow = '0 0 10px rgba(0, 122, 255, 0.3)';

                    // 3秒后移除高亮效果
                    setTimeout(() => {
                        apiItem.style.border = '';
                        apiItem.style.boxShadow = '';
                    }, 3000);

                } else {
                    console.warn('[Backend Design] 未找到路径为', apiPath, '的API卡片');

                    // 如果没找到,尝试搜索所有API卡片
                    const allApiItems = document.querySelectorAll('[data-path]');
                    console.log('[Backend Design] 当前页面所有API路径:',
                        Array.from(allApiItems).map(item => item.getAttribute('data-path')));
                }
            } catch (error) {
                console.error('[Backend Design] 滚动到API失败:', error);
            }
        }

        /**
         * 监听来自VS Code的消息
         */
        window.addEventListener('message', event => {
            const message = event.data;
            console.log('[Backend Design] 收到消息:', message);

            switch (message.type) {
                case 'preViewOneAPI':
                    console.log('[Backend Design] 处理preViewOneAPI消息:', message.apiPath);
                    if (message.apiPath) {
                        // 延迟一点确保页面完全渲染
                        setTimeout(() => {
                            scrollToApiByPath(message.apiPath);
                        }, 200);
                    }
                    break;
                default:
                    // 其他消息类型的处理
                    break;
            }
        });

        // 页面加载完成后初始化textarea高度和输入框宽度
        document.addEventListener('DOMContentLoaded', function () {
            setTimeout(() => {
                initializeTextareaHeights();
                initializeInputWidths();
            }, 100);
        });
    </script>
</body>

</html>