Bläddra i källkod

feat: file member in mobile show layout

Future 1 dag sedan
förälder
incheckning
13108810a3

+ 7 - 1
CHANGELOG.md

@@ -3,8 +3,14 @@
 ## 2025-10-24
 ### 项目启动访谈问卷
 
-### 组员管理(项目详情页)
+### 页面手机端适配
+- 项目详情-文件,标题与筛选操作栏,紧凑布局
+- 项目详情-成员,标题与筛选操作栏,紧凑布局
+- 项目详情-问题,标题与筛选操作栏,紧凑布局并全屏弹窗
+
+### 组员分配(项目详情页)
 - 增加删除组员功能,将组员移出项目组
+- 企业微信SDK:添加成员后,自动邀请进群(企业微信PC/手机端)
 
 ## 2025-10-23
 

+ 43 - 38
src/modules/project/components/project-files-modal/project-files-modal.component.html

@@ -18,31 +18,20 @@
           </svg>
           项目文件
         </h2>
-        <div class="file-stats">
-          <span class="stat-item">
-            <span class="stat-number">{{ totalFiles }}</span>
-            <span class="stat-label">文件</span>
-          </span>
-          <span class="stat-item">
-            <span class="stat-number">{{ formatFileSize(totalSize) }}</span>
-            <span class="stat-label">总大小</span>
-          </span>
-          @if (imageCount > 0) {
-            <span class="stat-item">
-              <span class="stat-number">{{ imageCount }}</span>
-              <span class="stat-label">图片</span>
-            </span>
-          }
-          @if (documentCount > 0) {
-            <span class="stat-item">
-              <span class="stat-number">{{ documentCount }}</span>
-              <span class="stat-label">文档</span>
-            </span>
-          }
-        </div>
-      </div>
 
-      <div class="header-right">
+         <!-- 搜索框 -->
+        <div class="search-box">
+            <svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
+              <circle cx="11" cy="11" r="8"></circle>
+              <path d="m21 21-4.35-4.35"></path>
+            </svg>
+            <input
+              type="text"
+              class="search-input"
+              placeholder="搜索文件..."
+              [(ngModel)]="searchQuery">
+        </div>
+        
         <!-- 视图切换 -->
         <div class="view-toggle">
           <button
@@ -73,27 +62,40 @@
           </button>
         </div>
 
-        <!-- 搜索框 -->
-        <div class="search-box">
-          <svg class="search-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-            <circle cx="11" cy="11" r="8"></circle>
-            <path d="m21 21-4.35-4.35"></path>
-          </svg>
-          <input
-            type="text"
-            class="search-input"
-            placeholder="搜索文件..."
-            [(ngModel)]="searchQuery">
-        </div>
+       
+      </div>
 
-        <!-- 过滤器 -->
+      <div class="header-right">
+        <div class="file-stats">
+          <span class="stat-item">
+            <span class="stat-number">{{ totalFiles }}</span>
+            <span class="stat-label">文件</span>
+          </span>
+          <span class="stat-item">
+            <span class="stat-number">{{ formatFileSize(totalSize) }}</span>
+            <span class="stat-label">总大小</span>
+          </span>
+          @if (imageCount > 0) {
+            <span class="stat-item">
+              <span class="stat-number">{{ imageCount }}</span>
+              <span class="stat-label">图片</span>
+            </span>
+          }
+          @if (documentCount > 0) {
+            <span class="stat-item">
+              <span class="stat-number">{{ documentCount }}</span>
+              <span class="stat-label">文档</span>
+            </span>
+          }
+         
+        </div>
+               <!-- 过滤器 -->
         <select class="filter-select" [(ngModel)]="filterType">
           <option value="all">全部文件</option>
           <option value="images">图片</option>
           <option value="documents">文档</option>
           <option value="videos">视频</option>
         </select>
-
         <!-- 关闭按钮 -->
         <button class="close-btn" (click)="onClose()">
           <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -102,6 +104,9 @@
           </svg>
         </button>
       </div>
+
+ 
+
     </div>
 
     <!-- 模态框内容 -->

+ 74 - 99
src/modules/project/components/project-files-modal/project-files-modal.component.scss

@@ -8,7 +8,7 @@
   display: flex;
   align-items: center;
   justify-content: center;
-  z-index: 99;
+  z-index: 1000;
   padding: 20px;
 }
 
@@ -34,8 +34,10 @@
   flex-shrink: 0;
 
   .header-left {
-    flex: 1;
+    display:flex;
+    align-items: center;
     min-width: 0;
+    flex-direction: row;
 
     .modal-title {
       font-size: 24px;
@@ -53,44 +55,12 @@
       }
     }
 
-    .file-stats {
-      display: flex;
-      gap: 16px;
-      flex-wrap: wrap;
-
-      .stat-item {
-        display: flex;
-        flex-direction: column;
-        align-items: center;
-        min-width: 50px;
-
-        .stat-number {
-          font-size: 18px;
-          font-weight: 600;
-          color: #1f2937;
-          line-height: 1;
-        }
-
-        .stat-label {
-          font-size: 12px;
-          color: #6b7280;
-          margin-top: 2px;
-        }
-      }
-    }
-  }
-
-  .header-right {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-    flex-shrink: 0;
-
+ 
+    
     .view-toggle {
       display: flex;
       border: 1px solid #e5e7eb;
       border-radius: 6px;
-      overflow: hidden;
 
       .toggle-btn {
         background: white;
@@ -165,10 +135,44 @@
         border-color: #3b82f6;
       }
     }
+  }
+
+  .header-right {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    flex-shrink: 0;
+   .file-stats {
+      display: flex;
+      justify-content: between;
+      align-items: center;
+
+      .stat-item {
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        min-width: 50px;
+
+        .stat-number {
+          font-size: 18px;
+          font-weight: 600;
+          color: #1f2937;
+          line-height: 1;
+        }
+
+        .stat-label {
+          font-size: 12px;
+          color: #6b7280;
+          margin-top: 2px;
+        }
+      }
+    }
 
     .close-btn {
       background: none;
       border: none;
+      width:32px;
+      height:32px;
       padding: 8px;
       border-radius: 6px;
       cursor: pointer;
@@ -568,7 +572,7 @@
   display: flex;
   align-items: center;
   justify-content: center;
-  z-index: 100;
+  z-index: 1001;
   padding: 20px;
 }
 
@@ -745,92 +749,63 @@
 }
 
 // 响应式设计
+// 新增:移动端全屏与紧凔标题栏覆盖(优先级高,置于文件末尾以覆盖前面的规则)
 @media (max-width: 768px) {
   .modal-overlay {
     padding: 0;
+    align-items: stretch;
+    justify-content: stretch;
   }
 
   .modal-container {
+    width: 100vw;
+    height: 100vh;
     max-height: 100vh;
     border-radius: 0;
   }
 
   .modal-header {
-    padding: 16px;
-    flex-direction: column;
-    gap: 16px;
-
-    .header-left {
-      .modal-title {
-        font-size: 20px;
-      }
-
-      .file-stats {
-        justify-content: center;
-        gap: 12px;
-      }
-    }
-
-    .header-right {
-      width: 100%;
-      flex-direction: column;
-      gap: 12px;
-
-      .search-box .search-input {
-        width: 100%;
-      }
-    }
+    padding: 0px;
+    flex-direction: column; /* 紧凑布局,保持同一行或两行 */
+    align-items: center;
+    gap: 8px;
   }
 
-  .modal-content {
-    padding: 16px;
+  .modal-header .header-left {
+    display:flex;
+    justify-content: space-between;
+    min-width: 0;
   }
 
-  .files-grid {
-    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
-    gap: 16px;
+  .modal-header .header-left .modal-title {
+    margin: 0;
+    font-size: 18px;
+    white-space: nowrap;
+    text-overflow: ellipsis;
   }
 
-  .file-card {
-    .file-info {
-      padding: 12px;
-    }
-
-    .file-footer {
-      flex-direction: column;
-      gap: 8px;
-      align-items: stretch;
-
-      .uploader-info {
-        justify-content: center;
-      }
-
-      .file-actions {
-        justify-content: center;
-      }
-    }
+  .modal-header .header-left .file-stats {
+    min-width:175px;
+    gap: 8px;
   }
 
-  .files-list {
-    .file-list-item {
-      padding: 12px;
-      gap: 12px;
+  .modal-header .header-right {
+    flex-direction: row;
+    width: 90%;
+    display: flex;
+    align-items: center;
+  }
 
-      .list-file-icon {
-        width: 40px;
-        height: 40px;
-      }
-    }
+  .modal-header .header-left .search-box .search-input {
+    width: 140px;
   }
 
-  .preview-overlay {
-    padding: 0;
+  .modal-header .header-left .filter-select {
+    width: auto;
   }
 
-  .preview-container {
-    max-width: 100vw;
-    max-height: 100vh;
-    border-radius: 0;
+  .modal-content {
+    padding: 12px;
   }
 }
 

+ 52 - 0
src/modules/project/components/project-issues-modal/project-issues-modal.component.scss

@@ -229,4 +229,56 @@
     padding: 12px;
     color: #6b7280;
   }
+}
+
+// 新增:移动端全屏与紧凑标题栏覆盖(保证手机端弹窗全屏且工具区紧凑)
+@media (max-width: 768px) {
+  .issues-modal {
+    .overlay {
+      /* 保持遮罩层覆盖全屏 */
+    }
+    .modal {
+      left: 0;
+      top: 0;
+      transform: none;
+      width: 100vw;
+      height: 100vh;
+      max-height: 100vh;
+      border-radius: 0;
+    }
+
+    .header {
+      padding: 10px 12px;
+      display: flex;
+      align-items: center;
+      gap: 8px;
+      flex-wrap: wrap; /* 最多两行 */
+    }
+
+    .header .title-area {
+      flex: 1 1 auto;
+      min-width: 0;
+      gap: 8px;
+    }
+
+    .header .title-area h3 {
+      font-size: 16px;
+      margin: 0;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+
+    .tools {
+      padding: 8px 12px;
+      gap: 8px;
+      display: flex;
+      align-items: center;
+      flex-wrap: wrap;
+    }
+
+    .tools .search-input {
+      flex: 0 0 140px;
+    }
+  }
 }

+ 4 - 16
src/modules/project/components/project-members-modal/project-members-modal.component.html

@@ -34,9 +34,7 @@
             </span>
           }
         </div>
-      </div>
 
-      <div class="header-right">
         <!-- 环境指示器 -->
         <div class="environment-indicator">
           @if (isWxworkEnvironment) {
@@ -55,6 +53,10 @@
             </span>
           }
         </div>
+      </div>
+
+      <div class="header-right">
+        
 
         <!-- 搜索框 -->
         <div class="search-box">
@@ -180,20 +182,6 @@
                   </button>
                 }
 
-                <!-- 新增:移出项目 -->
-                @if (member.isInProjectTeam) {
-                  <button
-                    class="action-btn remove-btn"
-                    (click)="removeMemberFromProject(member)"
-                    title="移出项目">
-                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
-                      <circle cx="12" cy="12" r="10"></circle>
-                      <line x1="15" y1="9" x2="9" y2="15"></line>
-                      <line x1="9" y1="9" x2="15" y2="15"></line>
-                    </svg>
-                    <span>移出项目</span>
-                  </button>
-                }
 
                 <div class="status-indicator" [class]="getMemberStatusClass(member)">
                   @if (member.isInProjectTeam && member.isInGroupChat) {

+ 56 - 87
src/modules/project/components/project-members-modal/project-members-modal.component.scss

@@ -34,8 +34,10 @@
   flex-shrink: 0;
 
   .header-left {
-    flex: 1;
-    min-width: 0;
+    display:flex;
+    flex-direction: row;
+    align-items: center;
+    flex-wrap:none;
 
     .modal-title {
       font-size: 24px;
@@ -90,12 +92,6 @@
     }
   }
 
-  .header-right {
-    display: flex;
-    align-items: center;
-    gap: 12px;
-    flex-shrink: 0;
-
     .environment-indicator {
       .env-badge {
         display: flex;
@@ -118,6 +114,13 @@
       }
     }
 
+  .header-right {
+    display: flex;
+    align-items: center;
+    gap: 12px;
+    flex-shrink: 0;
+
+ 
     .search-box {
       position: relative;
       display: flex;
@@ -526,111 +529,77 @@
 }
 
 // 响应式设计
+// 新增:移动端全屏与紧凑标题栏覆盖
 @media (max-width: 768px) {
   .modal-overlay {
     padding: 0;
+    align-items: stretch;
+    justify-content: stretch;
   }
 
+
   .modal-container {
+    width: 100vw;
+    height: 100vh;
     max-height: 100vh;
     border-radius: 0;
   }
 
   .modal-header {
-    padding: 16px;
-    flex-direction: column;
-    gap: 16px;
+    padding: 12px;
+    flex-direction: row;
+    align-items: center;
+    gap: 8px;
+    flex-wrap: wrap; /* 最多两行 */
+  }
 
-    .header-left {
-      .modal-title {
-        font-size: 20px;
-      }
+  .modal-header .header-left {
+    min-width: 0;
+    justify-content: space-between;
+    width: 100%;
+  }
 
-      .member-stats {
-        justify-content: center;
-        gap: 12px;
-      }
-    }
+  .modal-header .header-left .modal-title {
+    margin: 0;
+    font-size: 18px;
+    white-space: nowrap;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
 
-    .header-right {
-      width: 100%;
-      flex-direction: column;
-      gap: 12px;
+  .modal-header .header-left .member-stats {
+    gap: 8px;
+  }
+  .environment-indicator{
+    display:none;
+  }
 
-      .search-box .search-input {
-        width: 100%;
-      }
+  .modal-header .header-right {
+    flex: 1 1 auto;
+    width: auto;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    gap: 8px;
+  }
 
-      .filter-select {
-        width: 100%;
-      }
-    }
+  .modal-header .header-right .search-box .search-input {
+    width: 140px;
   }
 
-  .modal-content {
-    padding: 16px;
+  .modal-header .header-right .filter-select {
+    width: auto;
   }
 
-  .member-card {
+  .modal-content {
     padding: 12px;
-    gap: 12px;
-
-    .member-avatar {
-      width: 40px;
-      height: 40px;
-    }
-
-    .member-info {
-      .member-name {
-        font-size: 14px;
-      }
-
-      .member-meta {
-        gap: 6px;
-        flex-wrap: wrap;
-
-        .role-badge {
-          font-size: 11px;
-          padding: 2px 6px;
-        }
-
-        .member-department {
-          font-size: 11px;
-        }
-
-        .member-status {
-          font-size: 10px;
-          padding: 2px 6px;
-        }
-      }
-
-      .add-to-group-hint {
-        font-size: 11px;
-        gap: 4px;
-      }
-    }
-
-    .member-actions {
-      flex-direction: row;
-      gap: 8px;
-
-      .action-btn {
-        padding: 6px 10px;
-        font-size: 11px;
-
-        &.add-btn {
-          span {
-            display: none;
-          }
-        }
-      }
-    }
   }
 }
 
 @media (max-width: 480px) {
   .member-card {
-    flex-direction: column;
+    flex-direction: row;
     align-items: stretch;
     gap: 12px;