Pārlūkot izejas kodu

折叠工具条可以正常工作

qdy 1 mēnesi atpakaļ
revīzija
6693627732

+ 17
- 20
src/app/app.component.html Parādīt failu

@@ -1,21 +1,22 @@
1 1
 @if (isLoginPage) {
2 2
   <router-outlet></router-outlet>
3 3
 } @else {
4
-  <!-- 使用可拖动分割线的布局 -->
5
-  <div class="h-screen w-screen bg-gray-50 flex overflow-hidden">
6
-    <!-- 左侧导航栏 -->
7
-    <div class="h-full overflow-hidden bg-white border-r border-gray-200 flex-shrink-0 flex flex-col" [style.width.px]="sidebarWidth">
8
-      <div class="px-4 pt-[22px] pb-[10px] border-b border-gray-200 bg-gradient-to-r from-blue-50 to-indigo-50 flex items-start">
9
-        <h2 class="text-lg font-semibold text-gray-800 flex items-center">
4
+  <!-- 使用grid布局 + 可拖动分割线 -->
5
+  <!-- 关键:grid布局确保高度链完整,滚动容器独立 -->
6
+  <div class="app-layout" [style.gridTemplateColumns]="sidebarWidth + 'px 8px 1fr'">
7
+    <!-- 左侧面板 -->
8
+    <div class="left-panel">
9
+      <div class="logo-section">
10
+        <h2 class="flex items-center">
10 11
           <mat-icon class="mr-2 text-blue-600">home</mat-icon>
11 12
           Talking - ERP
12 13
         </h2>
13 14
       </div>
14
-      <div class="flex-1 overflow-auto">
15
+      <div class="tree-container">
15 16
         <app-tree-nav [treeData]="treeData" (refresh)="onTreeRefresh()"></app-tree-nav>
16 17
       </div>
17 18
       <!-- 底部退出区域 -->
18
-      <div class="p-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between">
19
+      <div class="footer-info">
19 20
         <div class="flex items-center cursor-pointer hover:bg-gray-200 rounded p-2 group" (click)="logout()" matTooltip="退出登录" matTooltipPosition="above">
20 21
           <mat-icon class="mr-2 text-gray-600 group-hover:text-red-600">logout</mat-icon>
21 22
           <span class="text-sm text-gray-700 group-hover:text-red-700">退出</span>
@@ -27,21 +28,17 @@
27 28
     </div>
28 29
     
29 30
     <!-- 可拖动分割线 -->
30
-    <div class="w-2 h-full flex-shrink-0 cursor-ew-resize bg-gray-300 hover:bg-blue-400 active:bg-blue-500 transition-colors relative"
31
+    <div class="splitter"
31 32
          (mousedown)="startDrag($event)"
32
-         [class.bg-blue-400]="isDragging">
33
-      <div class="absolute inset-0 flex items-center justify-center">
34
-        <div class="w-1 h-8 bg-gray-400 rounded-full"></div>
35
-      </div>
33
+         [class.dragging]="isDragging">
34
+      <div class="splitter-handle"></div>
36 35
     </div>
37 36
     
38
-    <!-- 右侧内容区 -->
39
-    <div class="flex-1 h-full overflow-hidden bg-white flex flex-col">
40
-
41
-      <div class="flex-1 overflow-auto content-area">
42
-         <div class="pt-[5px] px-4 pb-4 h-full">
43
-          <router-outlet></router-outlet>
44
-        </div>
37
+    <!-- 右侧面板 -->
38
+    <div class="right-panel">
39
+      <!-- 关键:滚动容器,sticky-header检测此容器 -->
40
+      <div class="content-container">
41
+        <router-outlet></router-outlet>
45 42
       </div>
46 43
     </div>
47 44
   </div>

+ 46
- 0
src/app/app.component.html.backup Parādīt failu

@@ -0,0 +1,46 @@
1
+@if (isLoginPage) {
2
+  <router-outlet></router-outlet>
3
+} @else {
4
+  <!-- 使用可拖动分割线的布局 -->
5
+  <div class="h-screen w-screen bg-gray-50 flex">
6
+    <!-- 左侧导航栏 -->
7
+    <div class="h-full overflow-hidden bg-white border-r border-gray-200 flex-shrink-0 flex flex-col" [style.width.px]="sidebarWidth">
8
+      <div class="px-4 pt-[22px] pb-[10px] border-b border-gray-200 bg-gradient-to-r from-blue-50 to-indigo-50 flex items-start">
9
+        <h2 class="text-lg font-semibold text-gray-800 flex items-center">
10
+          <mat-icon class="mr-2 text-blue-600">home</mat-icon>
11
+          Talking - ERP
12
+        </h2>
13
+      </div>
14
+      <div class="flex-1 overflow-auto">
15
+        <app-tree-nav [treeData]="treeData" (refresh)="onTreeRefresh()"></app-tree-nav>
16
+      </div>
17
+      <!-- 底部退出区域 -->
18
+      <div class="p-3 border-t border-gray-200 bg-gray-50 flex items-center justify-between">
19
+        <div class="flex items-center cursor-pointer hover:bg-gray-200 rounded p-2 group" (click)="logout()" matTooltip="退出登录" matTooltipPosition="above">
20
+          <mat-icon class="mr-2 text-gray-600 group-hover:text-red-600">logout</mat-icon>
21
+          <span class="text-sm text-gray-700 group-hover:text-red-700">退出</span>
22
+        </div>
23
+        <span class="text-sm text-gray-700">
24
+          {{ username }}
25
+        </span>
26
+      </div>
27
+    </div>
28
+    
29
+    <!-- 可拖动分割线 -->
30
+    <div class="w-2 h-full flex-shrink-0 cursor-ew-resize bg-gray-300 hover:bg-blue-400 active:bg-blue-500 transition-colors relative"
31
+         (mousedown)="startDrag($event)"
32
+         [class.bg-blue-400]="isDragging">
33
+      <div class="absolute inset-0 flex items-center justify-center">
34
+        <div class="w-1 h-8 bg-gray-400 rounded-full"></div>
35
+      </div>
36
+    </div>
37
+    
38
+    <!-- 右侧内容区 -->
39
+    <div class="flex-1 h-full bg-white flex flex-col">
40
+
41
+      <div class="flex-1 content-area">
42
+        <router-outlet></router-outlet>
43
+      </div>
44
+    </div>
45
+  </div>
46
+}

+ 171
- 1
src/app/app.component.scss Parādīt failu

@@ -1,7 +1,177 @@
1
+/* 主应用布局 - 基于工作示例的grid布局 + 可拖动分割线 */
1 2
 :host {
2 3
   display: block;
3 4
   width: 100vw;
4 5
   height: 100vh;
5
-  overflow: hidden;
6 6
   background-color: #f9fafb; /* gray-50 */
7
+}
8
+
9
+/* Grid布局容器 */
10
+.app-layout {
11
+  display: grid;
12
+  grid-template-columns: 320px 8px 1fr; /* 默认宽度 */
13
+  height: 100vh;
14
+  overflow: hidden;
15
+  font-family: system-ui, -apple-system, sans-serif;
16
+}
17
+
18
+/* 左侧面板 */
19
+.left-panel {
20
+  background: white;
21
+  color: #333;
22
+  display: flex;
23
+  flex-direction: column;
24
+  overflow-y: auto;
25
+  border-right: 1px solid #e0e0e0;
26
+  box-shadow: 1px 0 3px rgba(0, 0, 0, 0.05);
27
+}
28
+
29
+.logo-section {
30
+  padding: 20px;
31
+  border-bottom: 1px solid #e0e0e0;
32
+  background: linear-gradient(to right, #f8f9fa, #e9ecef);
33
+}
34
+
35
+.logo-section h2 {
36
+  margin: 0;
37
+  font-size: 18px;
38
+  font-weight: 600;
39
+  color: #2c3e50;
40
+  display: flex;
41
+  align-items: center;
42
+}
43
+
44
+.logo-section mat-icon {
45
+  color: #3b82f6;
46
+}
47
+
48
+.tree-container {
49
+  flex: 1;
50
+  overflow-y: auto;
51
+  padding: 10px;
52
+}
53
+
54
+.footer-info {
55
+  margin-top: auto;
56
+  padding: 16px 20px;
57
+  border-top: 1px solid #e0e0e0;
58
+  display: flex;
59
+  justify-content: space-between;
60
+  align-items: center;
61
+  background: #f8f9fa;
62
+}
63
+
64
+.footer-info .flex {
65
+  display: flex;
66
+  align-items: center;
67
+  transition: all 0.2s;
68
+}
69
+
70
+.footer-info .flex:hover {
71
+  background-color: #e9ecef;
72
+}
73
+
74
+.footer-info mat-icon {
75
+  font-size: 18px;
76
+}
77
+
78
+.footer-info span {
79
+  color: #6c757d;
80
+  font-size: 14px;
81
+}
82
+
83
+/* 可拖动分割线 */
84
+.splitter {
85
+  background: #e5e7eb;
86
+  cursor: col-resize;
87
+  display: flex;
88
+  align-items: center;
89
+  justify-content: center;
90
+  transition: background-color 0.2s;
91
+  position: relative;
92
+  user-select: none;
93
+}
94
+
95
+.splitter:hover,
96
+.splitter.dragging {
97
+  background: #3b82f6;
98
+}
99
+
100
+.splitter-handle {
101
+  width: 2px;
102
+  height: 40px;
103
+  background: #9ca3af;
104
+  border-radius: 1px;
105
+  transition: background-color 0.2s;
106
+}
107
+
108
+.splitter:hover .splitter-handle,
109
+.splitter.dragging .splitter-handle {
110
+  background: white;
111
+}
112
+
113
+/* 右侧面板 */
114
+.right-panel {
115
+  background: #f8f9fa;
116
+  overflow: hidden;
117
+  position: relative;
118
+}
119
+
120
+/* 关键:滚动容器 - sticky-header检测此容器 */
121
+.content-container {
122
+  height: 100%;
123
+  overflow-y: auto;
124
+  background: white;
125
+}
126
+
127
+/* 滚动条样式 */
128
+.content-container::-webkit-scrollbar {
129
+  width: 8px;
130
+}
131
+
132
+.content-container::-webkit-scrollbar-track {
133
+  background: #f1f2f6;
134
+  border-radius: 4px;
135
+}
136
+
137
+.content-container::-webkit-scrollbar-thumb {
138
+  background: #bdc3c7;
139
+  border-radius: 4px;
140
+}
141
+
142
+.content-container::-webkit-scrollbar-thumb:hover {
143
+  background: #95a5a6;
144
+}
145
+
146
+/* 响应式设计 */
147
+@media (max-width: 1024px) {
148
+  .app-layout {
149
+    grid-template-columns: 240px 8px 1fr;
150
+  }
151
+}
152
+
153
+@media (max-width: 768px) {
154
+  .app-layout {
155
+    grid-template-columns: 1fr;
156
+    grid-template-rows: auto 8px auto;
157
+  }
158
+  
159
+  .left-panel {
160
+    max-height: 300px;
161
+    border-right: none;
162
+    border-bottom: 1px solid #e0e0e0;
163
+  }
164
+  
165
+  .logo-section {
166
+    padding: 16px;
167
+  }
168
+  
169
+  .splitter {
170
+    cursor: row-resize;
171
+  }
172
+  
173
+  .splitter-handle {
174
+    width: 40px;
175
+    height: 2px;
176
+  }
7 177
 }

+ 6
- 0
src/app/app.component.scss.backup Parādīt failu

@@ -0,0 +1,6 @@
1
+:host {
2
+  display: block;
3
+  width: 100vw;
4
+  height: 100vh;
5
+  background-color: #f9fafb; /* gray-50 */
6
+}

+ 1
- 1
src/app/app.routes.ts Parādīt failu

@@ -27,5 +27,5 @@ export const routes: Routes = [
27 27
   { path: 'tenant/list', component: TenantListComponent, canActivate: [authGuard] },
28 28
   { path: 'role/list', component: RoleListComponent, canActivate: [authGuard] },
29 29
   { path: 'user/list', component: UserListComponent, canActivate: [authGuard] },
30
-  { path: '**', redirectTo: '/home/readme' }
30
+ { path: '**', redirectTo: '/home/readme' }
31 31
 ];

+ 95
- 27
src/app/pages/service-register-config/service-register-config.component.html Parādīt failu

@@ -1,28 +1,96 @@
1
-<!-- 顶部标题区域 -->
2
-<app-sticky-header
3
-  [title]="title"
4
-  [hintText]="hintText"
5
-  [buttons]="headerButtons"
6
-  [showDebugInfo]="true"
7
-  [autoDetect]="true"
8
-  [scrollContainer]="'.content-area'"
9
-  [scrollThreshold]="20"
10
-  [compactThreshold]="80"
11
- [widthTarget]="'#tabulator-table'"
12
-  (buttonAction)="onHeaderButtonAction($event)"
13
-></app-sticky-header>
1
+<!-- 页面容器 - 采用与工作示例相同的布局结构 -->
2
+<div class="page-container">
3
+  <!-- Sticky Header组件 -->
4
+  <app-sticky-header [collapseThreshold]="50" [scrollContainer]="'#service-register-content'">
5
+    <!-- 工具条区域 - 保持固定 -->
6
+    <div toolbar class="page-toolbar">
7
+      <div class="toolbar-content">
8
+        <!-- 标题区域 -->
9
+        <div class="title-section">
10
+          <mat-icon class="title-icon">description</mat-icon>
11
+          <h1 class="page-title">{{ title }}</h1>
12
+        </div>
13
+      </div>
14
+      
15
+      <!-- 按钮区域 -->
16
+      <div class="button-section">
17
+        <!-- 注册按钮 -->
18
+        <button 
19
+          type="button"
20
+          class="btn btn-primary"
21
+          (click)="onRegister()"
22
+          [disabled]="isRegistering"
23
+        >
24
+          @if (isRegistering) {
25
+            <mat-icon class="mr-1">hourglass_empty</mat-icon>
26
+            <span>处理中...</span>
27
+          } @else {
28
+            <mat-icon class="mr-1">add_circle</mat-icon>
29
+            <span>注册</span>
30
+          }
31
+        </button>
32
+        
33
+        <!-- 刷新按钮 -->
34
+        <button 
35
+          type="button"
36
+          class="btn btn-secondary"
37
+          (click)="refresh()"
38
+          [disabled]="isRefreshing"
39
+        >
40
+          @if (isRefreshing) {
41
+            <mat-icon class="mr-1 spin-icon">refresh</mat-icon>
42
+            <span>刷新中...</span>
43
+          } @else {
44
+            <mat-icon class="mr-1">refresh</mat-icon>
45
+            <span>刷新</span>
46
+          }
47
+        </button>
48
+      </div>
49
+    </div>
50
+    
51
+    <!-- 提示区域 - 可折叠 -->
52
+    <div hint class="page-hint">
53
+      <!-- 提示信息区域 -->
54
+      <div class="hint-section">
55
+        <div class="hint-content">
56
+          <p>点击"注册"按钮将同步所有配置元信息到数据库,并显示配置列表。</p>
57
+        </div>
58
+      </div>
59
+      
60
+      <!-- 调试信息区域 -->
61
+      <div class="debug-section">
62
+        <div class="debug-item">
63
+          <span class="debug-label">数据源:</span>
64
+          <span class="debug-value">{{ config.useMockData ? '模拟数据' : 'API数据' }}</span>
65
+        </div>
66
+        <div class="debug-item">
67
+          <span class="debug-label">记录条数:</span>
68
+          <span class="debug-value">{{ recordCount }}</span>
69
+        </div>
70
+        <div class="debug-item">
71
+          <span class="debug-label">更新时间:</span>
72
+          <span class="debug-value">{{ currentTime | date:'yyyy-MM-dd HH:mm:ss' }}</span>
73
+        </div>
74
+      </div>
75
+    </div>
76
+  </app-sticky-header>
77
+  
78
+  <!-- 内容区域 - 内部滚动 -->
79
+  <div id="service-register-content" class="content-area">
80
+    <!-- Tabulator 表格组件 -->
81
+    <app-tabulator-grid id="tabulator-table" #matCard
82
+      [columns]="columns"
83
+      [dataLoader]="dataLoader"
84
+      [height]="'1000px'"
85
+      [paginationSize]="100"
86
+      [paginationSizeSelector]="[10, 20, 50, 100,200,500]"
87
+      [showPagination]="true"
88
+      [remoteSort]="true"
89
+      [remoteFilter]="true"
90
+      (dataLoaded)="onDataLoaded($event)"
91
+      (ajaxError)="onAjaxError($event)"
92
+    ></app-tabulator-grid>
93
+  </div>
94
+</div>
95
+
14 96
 
15
-<!-- Tabulator 表格组件 -->
16
-<app-tabulator-grid id="tabulator-table" #matCard
17
-  [columns]="columns"
18
-  [dataLoader]="dataLoader"
19
-  [height]="'600px'"
20
-  [paginationSize]="20"
21
-  [paginationSizeSelector]="[10, 20, 50, 100,200,500]"
22
-  [showPagination]="true"
23
-  [remoteSort]="true"
24
-  [remoteFilter]="true"
25
-  (dataLoaded)="onDataLoaded($event)"
26
-  (ajaxError)="onAjaxError($event)"
27
-  class="flex-1"
28
-></app-tabulator-grid>

+ 200
- 25
src/app/pages/service-register-config/service-register-config.component.scss Parādīt failu

@@ -1,27 +1,202 @@
1
-/* config-meta-tabulator.component.scss */
2
-.tabulator-container {
3
-  padding: 16px;
4
-  
5
-  .toolbar {
6
-    margin-bottom: 16px;
7
-    
8
-    .btn {
9
-      margin-right: 8px;
10
-      padding: 8px 16px;
11
-      background: #007bff;
12
-      color: white;
13
-      border: none;
14
-      border-radius: 4px;
15
-      cursor: pointer;
16
-      
17
-      &:hover {
18
-        background: #0056b3;
19
-      }
20
-    }
21
-  }
22
-  
23
-  #tabulator-table {
24
-    border: 1px solid #ddd;
25
-    border-radius: 4px;
1
+/* Service Register Config 页面样式 */
2
+/* 采用与工作示例相同的布局结构 */
3
+
4
+/* 组件宿主元素 - 继承父容器高度 */
5
+:host {
6
+  display: block;
7
+  height: 100%;
8
+}
9
+
10
+/* ==================== 页面容器 ==================== */
11
+.page-container {
12
+  display: flex;
13
+  flex-direction: column;
14
+  height: 100%;
15
+  background: white;
16
+  min-height: 0; /* 关键:flex容器需要此属性 */
17
+  overflow-y: visible; /* 确保不破坏sticky定位 */
18
+  position: relative; /* 为sticky定位创建定位上下文 */
19
+}
20
+
21
+/* ==================== 工具条内容样式 ==================== */
22
+.page-toolbar {
23
+  display: flex;
24
+  justify-content: space-between;
25
+  align-items: center;
26
+  width: 100%;
27
+  min-height: 48px; /* 与组件最小高度匹配 */
28
+  padding: 0 16px; /* 与组件toolbar-area内边距匹配 */
29
+}
30
+
31
+.toolbar-content {
32
+  display: flex;
33
+  align-items: center;
34
+}
35
+
36
+/* 标题区域 */
37
+.title-section {
38
+  display: flex;
39
+  align-items: center;
40
+  gap: 8px;
41
+}
42
+
43
+.title-icon {
44
+  color: #3b82f6; /* 蓝色图标 */
45
+  font-size: 1.5rem;
46
+  width: 1.5rem;
47
+  height: 1.5rem;
48
+}
49
+
50
+.page-title {
51
+  margin: 0;
52
+  font-size: 1.25rem; /* text-xl */
53
+  font-weight: 600; /* font-semibold */
54
+  color: #1f2937; /* text-gray-800 */
55
+}
56
+
57
+/* 按钮区域 */
58
+.button-section {
59
+  display: flex;
60
+  gap: 8px;
61
+}
62
+
63
+/* 按钮基础样式 */
64
+.btn {
65
+  display: inline-flex;
66
+  align-items: center;
67
+  gap: 4px;
68
+  padding: 0.5rem 1rem; /* px-4 py-2 */
69
+  border: none;
70
+  border-radius: 0.375rem; /* rounded-md */
71
+  font-weight: 500;
72
+  cursor: pointer;
73
+  transition: background-color 0.2s;
74
+  outline: none;
75
+}
76
+
77
+.btn:disabled {
78
+  opacity: 0.5;
79
+  cursor: not-allowed;
80
+}
81
+
82
+/* 主要按钮 */
83
+.btn-primary {
84
+  background-color: #2563eb; /* bg-blue-600 */
85
+  color: white;
86
+}
87
+
88
+.btn-primary:hover:not(:disabled) {
89
+  background-color: #1d4ed8; /* hover:bg-blue-700 */
90
+}
91
+
92
+.btn-primary:focus {
93
+  box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.5); /* focus:ring-2 focus:ring-blue-500 */
94
+}
95
+
96
+/* 次要按钮 */
97
+.btn-secondary {
98
+  background-color: #e5e7eb; /* bg-gray-200 */
99
+  color: #1f2937; /* text-gray-800 */
100
+}
101
+
102
+.btn-secondary:hover:not(:disabled) {
103
+  background-color: #d1d5db; /* hover:bg-gray-300 */
104
+}
105
+
106
+.btn-secondary:focus {
107
+  box-shadow: 0 0 0 2px rgba(107, 114, 128, 0.5); /* focus:ring-2 focus:ring-gray-500 */
108
+}
109
+
110
+/* 旋转加载指示器 */
111
+.spinner {
112
+  display: inline-block;
113
+  width: 1rem;
114
+  height: 1rem;
115
+  border: 2px solid currentColor;
116
+  border-radius: 50%;
117
+  border-top-color: transparent;
118
+  animation: spin 1s linear infinite;
119
+}
120
+
121
+@keyframes spin {
122
+  to { transform: rotate(360deg); }
123
+}
124
+
125
+/* ==================== 提示区域样式 ==================== */
126
+.page-hint .hint-section {
127
+  padding: 1rem; /* p-4 */
128
+  background-color: #eff6ff; /* bg-blue-50 */
129
+  border-bottom: 1px solid #dbeafe; /* border-blue-100 */
130
+}
131
+
132
+.hint-content {
133
+  font-size: 0.875rem; /* text-sm */
134
+  color: #1e40af; /* text-blue-800 */
135
+}
136
+
137
+.hint-content p {
138
+  margin: 0;
139
+  font-weight: 500; /* font-medium */
140
+}
141
+
142
+/* 调试信息区域 */
143
+.debug-section {
144
+  padding: 0.75rem; /* p-3 */
145
+  background-color: #fffbeb; /* bg-amber-50 */
146
+  border-bottom: 1px solid #fef3c7; /* border-amber-100 */
147
+  display: grid;
148
+  grid-template-columns: 1fr;
149
+  gap: 0.75rem; /* gap-3 */
150
+}
151
+
152
+@media (min-width: 768px) {
153
+  .debug-section {
154
+    grid-template-columns: repeat(3, 1fr); /* md:grid-cols-3 */
26 155
   }
156
+}
157
+
158
+.debug-item {
159
+  font-size: 0.875rem; /* text-sm */
160
+  color: #92400e; /* text-amber-800 */
161
+}
162
+
163
+.debug-label {
164
+  font-weight: 500; /* font-medium */
165
+}
166
+
167
+.debug-value {
168
+  margin-left: 0.5rem; /* ml-2 */
169
+  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
170
+}
171
+
172
+/* ==================== 内容区域 ==================== */
173
+/* 内部滚动容器,确保 sticky header 能正确检测滚动 */
174
+/* 采用工作示例的精确配置 */
175
+.content-area {
176
+  flex: 1 1 0%; /* 工作示例使用的精确值 */
177
+  overflow-y: auto !important; /* 确保优先级 */
178
+  overflow-x: hidden; /* 防止水平滚动 */
179
+  padding: 16px;
180
+  background: white;
181
+  min-height: 0; /* flex容器关键设置,防止内容溢出 */
182
+  -webkit-overflow-scrolling: touch; /* 移动端平滑滚动 */
183
+  position: relative; /* 创建新的堆叠上下文 */
184
+}
185
+
186
+/* Tabulator 表格样式 */
187
+#tabulator-table {
188
+  border: 1px solid #ddd;
189
+  border-radius: 4px;
190
+  height: 100% !important; /* 确保表格填满内容区域 */
191
+  min-height: 600px; /* 确保有足够内容产生滚动 */
192
+}
193
+
194
+/* 旋转图标 - 用于刷新按钮加载状态 */
195
+.spin-icon {
196
+  animation: spin 1s linear infinite;
197
+}
198
+
199
+@keyframes spin {
200
+  from { transform: rotate(0deg); }
201
+  to { transform: rotate(360deg); }
27 202
 }

+ 1
- 1
src/app/pages/service-register-config/service-register-config.component.spec.ts Parādīt failu

@@ -69,7 +69,7 @@ describe('ServiceRegisterConfigComponent', () => {
69 69
 
70 70
   it('should initialize with default values', () => {
71 71
     expect(component.title).toBe('注册服务配置');
72
-    expect(component.hintText).toBe('点击"注册"按钮将同步所有配置元信息到数据库,并显示配置列表。');
72
+    expect(component.recordCount).toBe(0);
73 73
     expect(component.headerButtons.length).toBe(2);
74 74
     expect(component.headerButtons[0].name).toBe('register');
75 75
     expect(component.headerButtons[1].name).toBe('refresh');

+ 24
- 32
src/app/pages/service-register-config/service-register-config.component.ts Parādīt failu

@@ -1,19 +1,20 @@
1 1
 
2 2
 import { Component, inject, ViewChild, OnInit, AfterViewInit } from '@angular/core';
3 3
 import { ConfigMetaService } from '../../services/config-meta.service';
4
-import { ConfigService, StickyHeaderComponent, StickyHeaderButton, TabulatorGridComponent } from 'base-core';
4
+import { ConfigService, StickyHeaderComponent, TabulatorGridComponent } from 'base-core';
5 5
 import { CommonModule } from '@angular/common';
6
+import { MatIconModule } from '@angular/material/icon';
6 7
 import { Observable } from 'rxjs';
7 8
 
8 9
 @Component({
9
-  imports: [CommonModule, StickyHeaderComponent, TabulatorGridComponent],
10
+  imports: [CommonModule, StickyHeaderComponent, TabulatorGridComponent, MatIconModule],
10 11
   selector: 'app-service-register-config',
11 12
   templateUrl: './service-register-config.component.html',
12 13
   styleUrl: './service-register-config.component.scss'
13 14
 })
14 15
 export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
15 16
   private configMetaService = inject(ConfigMetaService);
16
-  private config = inject(ConfigService);
17
+  config = inject(ConfigService);
17 18
 
18 19
   @ViewChild(TabulatorGridComponent) tabulatorGrid!: TabulatorGridComponent;
19 20
 
@@ -28,15 +29,15 @@ export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
28 29
    }
29 30
 
30 31
   ngAfterViewInit(): void {
31
-    console.log('👀 ServiceRegisterConfigComponent: TabulatorGrid 视图初始化完成');
32
+     console.log('👀 ServiceRegisterConfigComponent: 视图初始化完成');
33
+     console.log('👀 ServiceRegisterConfigComponent: TabulatorGrid 视图初始化完成');
32 34
   }
33 35
 
34 36
   title = '注册服务配置';
35
-  hintText = '点击"注册"按钮将同步所有配置元信息到数据库,并显示配置列表。';
36
-  headerButtons: StickyHeaderButton[] = [
37
-    { title: '注册', name: 'register', icon: 'add', color: 'primary' },
38
-    { title: '刷新', name: 'refresh', icon: 'refresh', color: 'accent' }
39
-  ];
37
+  recordCount = 0; // 用于动态区域变量绑定
38
+  isRegistering = false;
39
+  isRefreshing = false;
40
+  currentTime = new Date();
40 41
   
41 42
   // 外部查询条件预留字段(用于将来扩展)
42 43
   externalFilters: any = {};
@@ -93,14 +94,16 @@ export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
93 94
       headerFilter: 'input', 
94 95
       headerFilterFunc: 'like' 
95 96
     }
96
-  ];
97
+   ];
98
+
99
+
97 100
 
98 101
    /**
99 102
     * 数据加载函数 - 适配 TabulatorGridComponent
100 103
     */
101 104
    dataLoader = (params: any): Observable<{ last_page: number; data: any[] }> => {
102 105
      console.group('🚨🚨🚨 ServiceRegisterConfigComponent 数据加载函数被调用 🚨🚨🚨');
103
-     console.log('🔍 调用来源堆栈:', new Error().stack);
106
+     //console.log('🔍 调用来源堆栈:', new Error().stack);
104 107
      console.log('🔍 原始参数结构:', {
105 108
        type: typeof params,
106 109
        isObject: params && typeof params === 'object',
@@ -153,11 +156,11 @@ export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
153 156
    */
154 157
   onRegister(): void {
155 158
     console.log('注册按钮被点击');
156
-    this.headerButtons[0].loading = true;
159
+    this.isRegistering = true;
157 160
 
158 161
     this.configMetaService.initConfigMeta().subscribe({
159 162
       next: (result: any) => {
160
-        this.headerButtons[0].loading = false;
163
+        this.isRegistering = false;
161 164
         if (result.success) {
162 165
           console.log('注册完成:', result.data);
163 166
           // 注册成功后刷新表格数据
@@ -168,39 +171,24 @@ export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
168 171
         }
169 172
       },
170 173
       error: (error) => {
171
-        this.headerButtons[0].loading = false;
174
+        this.isRegistering = false;
172 175
         console.error('注册请求失败:', error);
173 176
       }
174 177
     });
175 178
   }
176 179
 
177
-  /**
178
-   * 处理头部按钮点击事件
179
-   */
180
-  onHeaderButtonAction(name: string): void {
181
-    console.log(`头部按钮点击: ${name}`);
182
-    switch (name) {
183
-      case 'register':
184
-        this.onRegister();
185
-        break;
186
-      case 'refresh':
187
-        this.refresh();
188
-        break;
189
-      default:
190
-        console.warn(`未知按钮操作: ${name}`);
191
-    }
192
-  }
180
+
193 181
 
194 182
   /**
195 183
    * 刷新表格数据
196 184
    */
197 185
   refresh(): void {
198 186
     if (this.tabulatorGrid) {
199
-      this.headerButtons[1].loading = true;
187
+      this.isRefreshing = true;
200 188
       this.tabulatorGrid.refresh();
201 189
       // 简单延迟后清除loading状态
202 190
       setTimeout(() => {
203
-        this.headerButtons[1].loading = false;
191
+        this.isRefreshing = false;
204 192
       }, 500);
205 193
     }
206 194
   }
@@ -246,6 +234,10 @@ export class ServiceRegisterConfigComponent implements OnInit, AfterViewInit {
246 234
       data_count: response?.data?.length,
247 235
       data_sample: response?.data?.slice(0, 2)
248 236
     });
237
+    
238
+    // 更新记录数和时间
239
+    this.recordCount = response?.data?.length || 0;
240
+    this.currentTime = new Date();
249 241
   }
250 242
 
251 243
   /**

+ 1
- 13
src/app/pages/tenant-list/tenant-list.component.html Parādīt failu

@@ -1,17 +1,5 @@
1 1
 <div class="h-full flex flex-col pt-0 px-4 pb-4 min-w-0">
2
-   <app-sticky-header
3
-    [title]="'租户管理'"
4
-    [buttonText]="'新增租户'"
5
-    [buttonIcon]="'add'"
6
-    [buttonColor]="'primary'"
7
-    [autoDetect]="true"
8
-    [scrollContainer]="'.content-area'"
9
-     [scrollThreshold]="20"
10
-    [compactThreshold]="80"
11
-    [widthTarget]="'#tenantMatCard'"
12
-    [headerHeight]="'200px'"
13
-    (buttonClick)="openAddDialog()">
14
-  </app-sticky-header>
2
+
15 3
 
16 4
    <mat-card id="tenantMatCard" class="h-[400px]">
17 5
      <mat-card-content class="overflow-auto">

+ 2
- 3
src/app/pages/tenant-list/tenant-list.component.ts Parādīt failu

@@ -10,7 +10,7 @@ import { MatProgressSpinner } from '@angular/material/progress-spinner';
10 10
 import { MatIcon } from '@angular/material/icon';
11 11
 import { TenantService } from '../../services/tenant.service';
12 12
 import { Tenant, TenantRequest } from '../../models/tenant.model';
13
-import { EnterNavigationDirective, StickyHeaderComponent } from 'base-core';
13
+import { EnterNavigationDirective } from 'base-core';
14 14
 
15 15
 @Component({
16 16
   selector: 'app-tenant-list',
@@ -25,8 +25,7 @@ import { EnterNavigationDirective, StickyHeaderComponent } from 'base-core';
25 25
     MatInputModule,
26 26
     MatProgressSpinner,
27 27
     MatIcon,
28
-    EnterNavigationDirective,
29
-    StickyHeaderComponent
28
+    EnterNavigationDirective
30 29
   ],
31 30
   templateUrl: './tenant-list.component.html',
32 31
   styleUrl: './tenant-list.component.scss'

+ 22
- 0
src/app/services/tree.service.ts Parādīt failu

@@ -174,6 +174,28 @@ export class TreeService {
174 174
             route: '/user/list'
175 175
           }
176 176
         ]
177
+      },
178
+      {
179
+        id: 'test-group',
180
+        name: '测试',
181
+        icon: 'bug_report',
182
+        type: 'group',
183
+        children: [
184
+          {
185
+            id: 'sticky-test',
186
+            name: 'StickyHeader测试',
187
+            icon: 'vertical_align_top',
188
+            type: 'page',
189
+            route: '/test/sticky'
190
+          },
191
+          {
192
+            id: 'service-register-test',
193
+            name: '服务注册测试',
194
+            icon: 'app_registration',
195
+            type: 'page',
196
+            route: '/test/service-register'
197
+          }
198
+        ]
177 199
       }
178 200
     ];
179 201
   }

+ 180
- 0
src/app/services/tree.service.ts.backup Parādīt failu

@@ -0,0 +1,180 @@
1
+import { Injectable } from '@angular/core';
2
+import { HttpClient } from '@angular/common/http';
3
+import { Observable, of, catchError, map } from 'rxjs';
4
+import { TreeNode } from '../models/tree-node.model';
5
+import { ConfigService } from 'base-core';
6
+
7
+@Injectable({
8
+  providedIn: 'root'
9
+})
10
+export class TreeService {
11
+  constructor(
12
+    private http: HttpClient,
13
+    private config: ConfigService
14
+  ) {}
15
+
16
+  getTree(): Observable<TreeNode[]> {
17
+    console.log('TreeService.getTree() 调用');
18
+    console.log('config.useMockData:', this.config.useMockData);
19
+    console.log('config.apiBaseUrl:', this.config.apiBaseUrl);
20
+    
21
+    if (this.config.useMockData) {
22
+      console.log('使用模拟树数据');
23
+      const mockTree = this.getMockTree();
24
+      console.log('模拟数据节点数:', mockTree.length);
25
+      // 调试:打印第一个节点的图标信息
26
+      if (mockTree.length > 0 && mockTree[0].children) {
27
+        console.log('[模拟数据]第一个分组节点图标:', mockTree[0].icon);
28
+        console.log('[模拟数据]第一个分组子节点图标:', mockTree[0].children.map(c => ({name: c.name, icon: c.icon})));
29
+      }
30
+      console.log('模拟数据结构:', JSON.stringify(mockTree, null, 2));
31
+      return of(mockTree);
32
+    }
33
+    
34
+    const apiUrl = `${this.config.apiBaseUrl}/projects/tree`;
35
+    console.log('请求树数据:', apiUrl);
36
+    
37
+    return this.http.get<any>(apiUrl).pipe(
38
+      map(response => {
39
+        console.log('树数据响应:', response);
40
+        // 后端返回 {success: true, data: [...]}
41
+        if (response && response.success && response.data) {
42
+          console.log('提取data字段,节点数:', response.data.length);
43
+          // 调试:打印第一个节点的图标信息
44
+          if (response.data.length > 0 && response.data[0].children) {
45
+            console.log('第一个分组节点图标:', response.data[0].icon);
46
+            console.log('第一个分组子节点图标:', response.data[0].children.map((c: any) => ({name: c.name, icon: c.icon})));
47
+          }
48
+          return response.data;
49
+        } else {
50
+          console.warn('响应格式不符合预期,返回空数组');
51
+          return [];
52
+        }
53
+      }),
54
+      catchError((error) => {
55
+        console.error('获取树数据失败:', error);
56
+        console.error('错误详情:', error.status, error.message, error.url);
57
+        // 认证失败或其他错误时返回空数组,不显示模拟数据
58
+        console.warn('API请求失败,回退到模拟数据');
59
+        const mockTree = this.getMockTree();
60
+        console.log('回退模拟数据节点数:', mockTree.length);
61
+        return of(mockTree);
62
+      })
63
+    );
64
+  }
65
+
66
+  private getMockTree(): TreeNode[] {
67
+    // 模拟树数据,基于Go后端返回的结构
68
+    return [
69
+      {
70
+        id: 'home',
71
+        name: '首页',
72
+        icon: 'home',
73
+        type: 'group',
74
+        children: [
75
+          {
76
+            id: 'readme',
77
+            name: '说明',
78
+            icon: 'description',
79
+            type: 'page',
80
+            route: '/home/readme'
81
+          }
82
+        ]
83
+      },
84
+      {
85
+        id: 'service-group',
86
+        name: '服务',
87
+        icon: 'settings',
88
+        type: 'group',
89
+        children: [
90
+          {
91
+            id: 'service-register',
92
+            name: '注册服务配置',
93
+            icon: 'app_registration',
94
+            type: 'page',
95
+            route: '/service/register-config'
96
+          },
97
+          {
98
+            id: 'service-management',
99
+            name: '微服务管理',
100
+            icon: 'dns',
101
+            type: 'page',
102
+            route: '/service/management'
103
+          },
104
+          {
105
+            id: 'service-config',
106
+            name: '微服务配置管理',
107
+            icon: 'settings_applications',
108
+            type: 'page',
109
+            route: '/service/config-management'
110
+          },
111
+          {
112
+            id: 'boot-config',
113
+            name: '微服务启动配置管理',
114
+            icon: 'play_circle',
115
+            type: 'page',
116
+            route: '/service/boot-config'
117
+          }
118
+        ]
119
+      },
120
+      {
121
+        id: 'user-group',
122
+        name: '项目',
123
+        icon: 'folder',
124
+        type: 'group',
125
+        children: [
126
+          {
127
+            id: 'project-management',
128
+            name: '项目管理',
129
+            icon: 'folder_open',
130
+            type: 'page',
131
+            route: '/project/list'
132
+          },
133
+          {
134
+            id: 'agent-management',
135
+            name: 'Agent管理',
136
+            icon: 'smart_toy',
137
+            type: 'page',
138
+            route: '/agent/list'
139
+          },
140
+          {
141
+            id: 'skill-management',
142
+            name: 'Skill管理',
143
+            icon: 'build',
144
+            type: 'page',
145
+            route: '/skill/list'
146
+          }
147
+        ]
148
+      },
149
+      {
150
+        id: 'tenant-group',
151
+        name: '租户管理',
152
+        icon: 'apartment',
153
+        type: 'group',
154
+        children: [
155
+          {
156
+            id: 'tenant-management',
157
+            name: '租户管理',
158
+            icon: 'apartment',
159
+            type: 'page',
160
+            route: '/tenant/list'
161
+          },
162
+          {
163
+            id: 'role-management',
164
+            name: '角色管理',
165
+            icon: 'admin_panel_settings',
166
+            type: 'page',
167
+            route: '/role/list'
168
+          },
169
+          {
170
+            id: 'user-management',
171
+            name: '用户管理',
172
+            icon: 'people',
173
+            type: 'page',
174
+            route: '/user/list'
175
+          }
176
+        ]
177
+      }
178
+    ];
179
+  }
180
+}

+ 5
- 5
src/styles.scss Parādīt failu

@@ -121,11 +121,11 @@ code:not(.prism-code code) {
121 121
   font-size: 0.875rem;
122 122
 }
123 123
 
124
-/* 内容区域滚动优化 */
125
-.content-area {
126
-  scrollbar-width: thin;
127
-  scrollbar-color: #cbd5e1 #f1f5f9;
128
-}
124
+ /* 内容区域滚动条样式 */
125
+ .content-area {
126
+   scrollbar-width: thin;
127
+   scrollbar-color: #cbd5e1 #f1f5f9;
128
+ }
129 129
 
130 130
 .content-area::-webkit-scrollbar {
131 131
   width: 8px;

Notiek ielāde…
Atcelt
Saglabāt