徐福静0235668 19 小時之前
父節點
當前提交
1343842716
共有 50 個文件被更改,包括 6655 次插入1020 次删除
  1. 29 0
      package-lock.json
  2. 3 1
      package.json
  3. 0 196
      src/app/app.html
  4. 3 3
      src/app/app.routes.ts
  5. 84 5
      src/app/auth/login/login.html
  6. 259 130
      src/app/auth/login/login.scss
  7. 156 0
      src/app/auth/login/login.ts
  8. 105 5
      src/app/auth/register/register.html
  9. 251 167
      src/app/auth/register/register.scss
  10. 151 0
      src/app/auth/register/register.ts
  11. 1 1
      src/app/business/ai-operations-assistant/ai-operations-assistant.ts
  12. 1 1
      src/app/business/dashboard/dashboard.ts
  13. 1 1
      src/app/business/data-reports/data-reports.ts
  14. 1 1
      src/app/business/device-management/device-management.ts
  15. 1 1
      src/app/business/enterprise-center/enterprise-center.ts
  16. 1 1
      src/app/business/order-management/order-management.ts
  17. 60 2
      src/app/consumer/ai-assistant/ai-assistant.html
  18. 77 0
      src/app/consumer/ai-assistant/ai-assistant.scss
  19. 50 4
      src/app/consumer/ai-assistant/ai-assistant.ts
  20. 187 5
      src/app/consumer/booking-recycle/booking-recycle.html
  21. 715 0
      src/app/consumer/booking-recycle/booking-recycle.scss
  22. 264 5
      src/app/consumer/booking-recycle/booking-recycle.ts
  23. 19 3
      src/app/consumer/consumer-module.ts
  24. 7 4
      src/app/consumer/consumer-routing-module.ts
  25. 241 5
      src/app/consumer/earnings/earnings.html
  26. 491 0
      src/app/consumer/earnings/earnings.scss
  27. 458 6
      src/app/consumer/earnings/earnings.ts
  28. 95 3
      src/app/consumer/eco-knowledge/eco-knowledge.html
  29. 160 0
      src/app/consumer/eco-knowledge/eco-knowledge.scss
  30. 107 4
      src/app/consumer/eco-knowledge/eco-knowledge.ts
  31. 92 5
      src/app/consumer/home/home.html
  32. 416 424
      src/app/consumer/home/home.scss
  33. 6 6
      src/app/consumer/home/home.spec.ts
  34. 244 7
      src/app/consumer/home/home.ts
  35. 166 5
      src/app/consumer/points-mall/points-mall.html
  36. 639 0
      src/app/consumer/points-mall/points-mall.scss
  37. 419 4
      src/app/consumer/points-mall/points-mall.ts
  38. 212 5
      src/app/consumer/profile/profile.html
  39. 243 0
      src/app/consumer/profile/profile.scss
  40. 117 4
      src/app/consumer/profile/profile.ts
  41. 1 1
      src/app/government/ai-decision-assistant/ai-decision-assistant.ts
  42. 1 1
      src/app/government/government-center/government-center.ts
  43. 1 1
      src/app/government/industry-analysis/industry-analysis.ts
  44. 1 1
      src/app/government/subsidy-management/subsidy-management.ts
  45. 1 1
      src/app/government/supervision-overview/supervision-overview.ts
  46. 22 0
      src/app/shared/bottom-nav/bottom-nav.component.html
  47. 56 0
      src/app/shared/bottom-nav/bottom-nav.component.scss
  48. 37 0
      src/app/shared/bottom-nav/bottom-nav.component.ts
  49. 1 0
      src/index.html
  50. 2 1
      src/styles.scss

+ 29 - 0
package-lock.json

@@ -14,6 +14,8 @@
         "@angular/forms": "^20.3.0",
         "@angular/platform-browser": "^20.3.0",
         "@angular/router": "^20.3.0",
+        "@fortawesome/fontawesome-free": "^7.0.1",
+        "chart.js": "^4.5.0",
         "rxjs": "~7.8.0",
         "tslib": "^2.3.0",
         "zone.js": "~0.15.0"
@@ -1375,6 +1377,15 @@
         "node": ">=18"
       }
     },
+    "node_modules/@fortawesome/fontawesome-free": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-7.0.1.tgz",
+      "integrity": "sha512-RLmb9U6H2rJDnGxEqXxzy7ANPrQz7WK2/eTjdZqyU9uRU5W+FkAec9uU5gTYzFBH7aoXIw2WTJSCJR4KPlReQw==",
+      "license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/@inquirer/ansi": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.0.tgz",
@@ -1871,6 +1882,12 @@
         "@jridgewell/sourcemap-codec": "^1.4.14"
       }
     },
+    "node_modules/@kurkle/color": {
+      "version": "0.3.4",
+      "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz",
+      "integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==",
+      "license": "MIT"
+    },
     "node_modules/@listr2/prompt-adapter-inquirer": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.1.tgz",
@@ -4383,6 +4400,18 @@
       "dev": true,
       "license": "MIT"
     },
+    "node_modules/chart.js": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.5.0.tgz",
+      "integrity": "sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@kurkle/color": "^0.3.0"
+      },
+      "engines": {
+        "pnpm": ">=8"
+      }
+    },
     "node_modules/chokidar": {
       "version": "4.0.3",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",

+ 3 - 1
package.json

@@ -28,6 +28,8 @@
     "@angular/forms": "^20.3.0",
     "@angular/platform-browser": "^20.3.0",
     "@angular/router": "^20.3.0",
+    "@fortawesome/fontawesome-free": "^7.0.1",
+    "chart.js": "^4.5.0",
     "rxjs": "~7.8.0",
     "tslib": "^2.3.0",
     "zone.js": "~0.15.0"
@@ -45,4 +47,4 @@
     "karma-jasmine-html-reporter": "~2.1.0",
     "typescript": "~5.9.2"
   }
-}
+}

文件差異過大導致無法顯示
+ 0 - 196
src/app/app.html


+ 3 - 3
src/app/app.routes.ts

@@ -11,11 +11,11 @@ export const routes: Routes = [
     loadChildren: () => import('./auth/auth-module').then(m => m.AuthModule)
   },
   
-  // C端个人用户路由 - 需要认证
+  // C端个人用户路由 - 临时移除认证守卫用于测试
   {
     path: 'consumer',
-    loadChildren: () => import('./consumer/consumer-module').then(m => m.ConsumerModule),
-    canActivate: [authGuard]
+    loadChildren: () => import('./consumer/consumer-module').then(m => m.ConsumerModule)
+    // canActivate: [authGuard] // 临时注释掉用于测试
   },
   
   // B端企业用户路由 - 需要认证

+ 84 - 5
src/app/auth/login/login.html

@@ -1,8 +1,87 @@
-<div class="login-container">
-  <div class="login-card">
-    <div class="login-header">
-      <h1>登录页面</h1>
+<div class="header">
+  <a (click)="goBack()" class="back-btn">←</a>
+  <div class="app-title">绿色回收</div>
+  <div class="logo">♻️</div>
+</div>
+
+<div class="container">
+  <h2 class="form-title">欢迎回来</h2>
+  <p class="form-subtitle">登录您的账户,继续环保之旅</p>
+  
+  <form (ngSubmit)="onSubmit()" #loginFormRef="ngForm">
+    <div class="form-group">
+      <label for="account">账户信息</label>
+      <div class="input-with-icon">
+        <span class="input-icon">📱</span>
+        <input 
+          type="text" 
+          id="account" 
+          name="account"
+          [(ngModel)]="loginForm.account"
+          placeholder="手机号/邮箱/用户名" 
+          required>
+      </div>
+      <div class="error-message" [style.display]="errors.account ? 'block' : 'none'">
+        {{ errors.account }}
+      </div>
     </div>
-    <!-- 页面内容已清理,保留基本结构 -->
+    
+    <div class="form-group">
+      <label for="password">密码</label>
+      <div class="input-with-icon">
+        <span class="input-icon">🔒</span>
+        <input 
+          [type]="passwordVisible ? 'text' : 'password'" 
+          id="password" 
+          name="password"
+          [(ngModel)]="loginForm.password"
+          placeholder="请输入密码" 
+          required>
+        <button 
+          type="button" 
+          class="password-toggle"
+          (click)="togglePasswordVisibility()">
+          {{ passwordVisible ? '🙈' : '👁️' }}
+        </button>
+      </div>
+      <div class="error-message" [style.display]="errors.password ? 'block' : 'none'">
+        {{ errors.password }}
+      </div>
+    </div>
+    
+    <div class="remember-forgot">
+      <div class="remember-me">
+        <input 
+          type="checkbox" 
+          id="remember" 
+          name="remember"
+          [(ngModel)]="loginForm.remember">
+        <label for="remember">记住我</label>
+      </div>
+      <a (click)="forgotPassword()" class="forgot-password">忘记密码?</a>
+    </div>
+    
+    <button 
+      type="submit" 
+      class="btn-login"
+      [disabled]="isLoading">
+      {{ isLoading ? '登录中...' : '登录' }}
+    </button>
+    
+    <div class="divider">或使用以下方式登录</div>
+    
+    <div class="social-login">
+      <div class="social-btn wechat" (click)="socialLogin('微信')">💬</div>
+      <div class="social-btn qq" (click)="socialLogin('QQ')">🐧</div>
+      <div class="social-btn weibo" (click)="socialLogin('微博')">🔴</div>
+    </div>
+  </form>
+  
+  <div class="register-link">
+    还没有账户?<a (click)="goToRegister()">立即注册</a>
   </div>
+</div>
+
+<div class="footer">
+  登录即表示同意<a href="#">《用户协议》</a>和<a href="#">《隐私政策》</a>
 </div>

+ 259 - 130
src/app/auth/login/login.scss

@@ -1,176 +1,305 @@
-.login-container {
-  min-height: 100vh;
+// 全局样式重置和基础设置
+:host {
+  display: block;
+  width: 100%;
+  height: 100vh;
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+  background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
+  padding: 20px 20px 40px;
+}
+
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+// 头部样式
+.header {
+  display: flex;
+  align-items: center;
+  margin-bottom: 30px;
+  padding-top: 10px;
+}
+
+.back-btn {
+  width: 40px;
+  height: 40px;
+  border-radius: 50%;
+  background: rgba(255, 255, 255, 0.7);
   display: flex;
   align-items: center;
   justify-content: center;
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-  padding: 20px;
+  font-size: 20px;
+  color: #2e7d32;
+  text-decoration: none;
+  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+  cursor: pointer;
+  border: none;
 }
 
-.login-card {
+.app-title {
+  flex: 1;
+  text-align: center;
+  font-size: 20px;
+  font-weight: 600;
+  color: #1b5e20;
+}
+
+.logo {
+  width: 40px;
+  height: 40px;
+  background: #2e7d32;
+  border-radius: 10px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  font-size: 22px;
+  margin-right: 10px;
+}
+
+// 主容器样式
+.container {
   background: white;
-  border-radius: 16px;
-  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
-  padding: 40px;
-  width: 100%;
-  max-width: 400px;
-  animation: slideUp 0.6s ease-out;
+  border-radius: 20px;
+  padding: 25px;
+  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
+  margin-bottom: 20px;
 }
 
-@keyframes slideUp {
-  from {
-    opacity: 0;
-    transform: translateY(30px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
+.form-title {
+  font-size: 24px;
+  font-weight: 600;
+  color: #1b5e20;
+  margin-bottom: 5px;
+}
+
+.form-subtitle {
+  color: #7c8a7e;
+  font-size: 14px;
+  margin-bottom: 25px;
+}
+
+// 表单样式
+.form-group {
+  margin-bottom: 20px;
+}
+
+label {
+  display: block;
+  margin-bottom: 8px;
+  font-weight: 500;
+  color: #455a64;
+  font-size: 15px;
+}
+
+.input-with-icon {
+  position: relative;
+}
+
+.input-icon {
+  position: absolute;
+  left: 15px;
+  top: 50%;
+  transform: translateY(-50%);
+  color: #7c8a7e;
+  font-size: 18px;
+}
+
+input {
+  width: 100%;
+  padding: 16px 16px 16px 50px;
+  border: 1px solid #e0e0e0;
+  border-radius: 12px;
+  font-size: 16px;
+  transition: all 0.3s;
+  background: #fafafa;
+
+  &:focus {
+    outline: none;
+    border-color: #4caf50;
+    background: white;
+    box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
   }
 }
 
-.login-header {
-  text-align: center;
-  margin-bottom: 32px;
+.password-toggle {
+  position: absolute;
+  right: 15px;
+  top: 50%;
+  transform: translateY(-50%);
+  background: none;
+  border: none;
+  color: #7c8a7e;
+  font-size: 18px;
+  cursor: pointer;
+}
+
+// 记住我和忘记密码
+.remember-forgot {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 25px;
+}
+
+.remember-me {
+  display: flex;
+  align-items: center;
 
-  h1 {
-    color: #2d3748;
-    font-size: 28px;
-    font-weight: 700;
-    margin: 0 0 8px 0;
+  input {
+    width: auto;
+    margin-right: 8px;
+    padding: 0;
   }
 
-  p {
-    color: #718096;
-    font-size: 16px;
-    margin: 0;
+  label {
+    margin-bottom: 0;
+    font-size: 14px;
+    cursor: pointer;
   }
 }
 
-.login-form {
-  .form-group {
-    margin-bottom: 24px;
+.forgot-password {
+  color: #2e7d32;
+  text-decoration: none;
+  font-size: 14px;
+  cursor: pointer;
 
-    label {
-      display: block;
-      color: #2d3748;
-      font-weight: 600;
-      margin-bottom: 8px;
-      font-size: 14px;
-    }
+  &:hover {
+    text-decoration: underline;
+  }
+}
 
-    .form-control {
-      width: 100%;
-      padding: 12px 16px;
-      border: 2px solid #e2e8f0;
-      border-radius: 8px;
-      font-size: 16px;
-      transition: all 0.3s ease;
-      box-sizing: border-box;
-
-      &:focus {
-        outline: none;
-        border-color: #667eea;
-        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
-      }
-
-      &::placeholder {
-        color: #a0aec0;
-      }
-    }
+// 错误信息
+.error-message {
+  color: #f44336;
+  font-size: 13px;
+  margin-top: 5px;
+}
 
-    select.form-control {
-      cursor: pointer;
-    }
+// 登录按钮
+.btn-login {
+  width: 100%;
+  padding: 18px;
+  background: linear-gradient(to right, #4caf50, #2e7d32);
+  color: white;
+  border: none;
+  border-radius: 12px;
+  font-size: 17px;
+  font-weight: 600;
+  cursor: pointer;
+  transition: all 0.3s;
+  box-shadow: 0 4px 10px rgba(76, 175, 80, 0.3);
+  margin-bottom: 20px;
+
+  &:active {
+    transform: translateY(2px);
+    box-shadow: 0 2px 5px rgba(76, 175, 80, 0.3);
   }
 
-  .error-message {
-    background: #fed7d7;
-    color: #c53030;
-    padding: 12px 16px;
-    border-radius: 8px;
-    margin-bottom: 24px;
-    font-size: 14px;
-    border: 1px solid #feb2b2;
+  &:disabled {
+    opacity: 0.7;
+    cursor: not-allowed;
+    transform: none;
   }
+}
 
-  .btn-primary {
-    width: 100%;
-    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-    color: white;
-    border: none;
-    padding: 14px 24px;
-    border-radius: 8px;
-    font-size: 16px;
-    font-weight: 600;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: 8px;
-
-    &:hover:not(:disabled) {
-      transform: translateY(-2px);
-      box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
-    }
+// 分割线
+.divider {
+  display: flex;
+  align-items: center;
+  margin: 25px 0;
+  color: #7c8a7e;
+  font-size: 14px;
 
-    &:disabled {
-      opacity: 0.6;
-      cursor: not-allowed;
-      transform: none;
-    }
+  &::before,
+  &::after {
+    content: "";
+    flex: 1;
+    height: 1px;
+    background: #e0e0e0;
+  }
 
-    .loading-spinner {
-      width: 16px;
-      height: 16px;
-      border: 2px solid transparent;
-      border-top: 2px solid white;
-      border-radius: 50%;
-      animation: spin 1s linear infinite;
-    }
+  &::before {
+    margin-right: 15px;
   }
 
-  @keyframes spin {
-    0% { transform: rotate(0deg); }
-    100% { transform: rotate(360deg); }
+  &::after {
+    margin-left: 15px;
   }
 }
 
-.login-footer {
-  text-align: center;
-  margin-top: 24px;
+// 社交登录
+.social-login {
+  display: flex;
+  justify-content: center;
+  gap: 20px;
+  margin-bottom: 25px;
+}
 
-  p {
-    color: #718096;
-    font-size: 14px;
-    margin: 0;
+.social-btn {
+  width: 50px;
+  height: 50px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 20px;
+  background: #f5f5f5;
+  border: 1px solid #e0e0e0;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &:active {
+    transform: scale(0.95);
+  }
+
+  &.wechat {
+    color: #09bb07;
+  }
+
+  &.qq {
+    color: #12b7f5;
   }
 
-  .link {
-    color: #667eea;
+  &.weibo {
+    color: #e6162d;
+  }
+}
+
+// 注册链接
+.register-link {
+  text-align: center;
+  color: #7c8a7e;
+  font-size: 15px;
+
+  a {
+    color: #2e7d32;
     text-decoration: none;
-    font-weight: 600;
+    font-weight: 500;
     cursor: pointer;
-    transition: color 0.3s ease;
 
     &:hover {
-      color: #5a67d8;
       text-decoration: underline;
     }
   }
 }
 
-// 响应式设计
-@media (max-width: 480px) {
-  .login-container {
-    padding: 16px;
-  }
-
-  .login-card {
-    padding: 24px;
-  }
+// 页脚
+.footer {
+  text-align: center;
+  margin-top: auto;
+  color: #7c8a7e;
+  font-size: 13px;
+  padding-top: 20px;
 
-  .login-header h1 {
-    font-size: 24px;
+  a {
+    color: #2e7d32;
+    text-decoration: none;
   }
 }

+ 156 - 0
src/app/auth/login/login.ts

@@ -3,6 +3,21 @@ import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { Router, RouterModule } from '@angular/router';
 
+// 定义登录表单接口
+interface LoginForm {
+  account: string;
+  password: string;
+  remember: boolean;
+}
+
+// 定义用户接口
+interface User {
+  id: string;
+  account: string;
+  password: string;
+  name: string;
+}
+
 @Component({
   selector: 'app-login',
   imports: [CommonModule, FormsModule, RouterModule],
@@ -10,5 +25,146 @@ import { Router, RouterModule } from '@angular/router';
   styleUrl: './login.scss'
 })
 export class LoginComponent {
+  // 表单数据
+  loginForm: LoginForm = {
+    account: '',
+    password: '',
+    remember: false
+  };
+
+  // 错误信息
+  errors = {
+    account: '',
+    password: ''
+  };
+
+  // 密码可见性
+  passwordVisible = false;
+
+  // 登录状态
+  isLoading = false;
+
+  // Mock用户数据
+  private mockUsers: User[] = [
+    {
+      id: '1',
+      account: '13800138000',
+      password: '123456',
+      name: '张三'
+    },
+    {
+      id: '2',
+      account: 'user@example.com',
+      password: 'password',
+      name: '李四'
+    },
+    {
+      id: '3',
+      account: 'admin',
+      password: 'admin123',
+      name: '管理员'
+    }
+  ];
+
   constructor(private router: Router) {}
+
+  // 切换密码可见性
+  togglePasswordVisibility(): void {
+    this.passwordVisible = !this.passwordVisible;
+  }
+
+  // 验证账户信息
+  validateAccount(): boolean {
+    this.errors.account = '';
+    
+    if (!this.loginForm.account.trim()) {
+      this.errors.account = '请输入有效的账户信息';
+      return false;
+    }
+    
+    return true;
+  }
+
+  // 验证密码
+  validatePassword(): boolean {
+    this.errors.password = '';
+    
+    if (!this.loginForm.password.trim()) {
+      this.errors.password = '密码不能为空';
+      return false;
+    }
+    
+    return true;
+  }
+
+  // 表单提交
+  onSubmit(): void {
+    // 重置错误信息
+    this.errors = { account: '', password: '' };
+
+    // 验证表单
+    const isAccountValid = this.validateAccount();
+    const isPasswordValid = this.validatePassword();
+
+    if (!isAccountValid || !isPasswordValid) {
+      return;
+    }
+
+    // 开始登录
+    this.isLoading = true;
+
+    // 模拟登录API调用
+    setTimeout(() => {
+      const user = this.authenticateUser(this.loginForm.account, this.loginForm.password);
+      
+      if (user) {
+        // 登录成功
+        console.log('登录成功:', user);
+        
+        // 保存用户信息到localStorage
+        localStorage.setItem('currentUser', JSON.stringify(user));
+        
+        if (this.loginForm.remember) {
+          localStorage.setItem('rememberLogin', 'true');
+        }
+
+        // 跳转到主页面(这里可以根据实际需要修改路由)
+        alert('登录成功!');
+        // this.router.navigate(['/dashboard']); // 实际项目中取消注释
+        
+      } else {
+        // 登录失败
+        this.errors.account = '账户或密码错误';
+      }
+      
+      this.isLoading = false;
+    }, 1500);
+  }
+
+  // 验证用户凭据
+  private authenticateUser(account: string, password: string): User | null {
+    return this.mockUsers.find(user => 
+      user.account === account && user.password === password
+    ) || null;
+  }
+
+  // 社交登录
+  socialLogin(platform: string): void {
+    alert(`即将通过${platform}登录`);
+  }
+
+  // 忘记密码
+  forgotPassword(): void {
+    alert('忘记密码功能开发中...');
+  }
+
+  // 跳转到注册页面
+  goToRegister(): void {
+    this.router.navigate(['/auth/register']);
+  }
+
+  // 返回上一页
+  goBack(): void {
+    window.history.back();
+  }
 }

+ 105 - 5
src/app/auth/register/register.html

@@ -1,8 +1,108 @@
-<div class="register-container">
-  <div class="register-card">
-    <div class="register-header">
-      <h1>注册页面</h1>
+<div class="register-page">
+  <div class="header">
+    <button class="back-btn" (click)="goBack()">←</button>
+    <div class="app-title">绿色回收</div>
+    <div class="logo">♻️</div>
+  </div>
+  
+  <div class="container">
+    <h2 class="form-title">创建账户</h2>
+    <p class="form-subtitle">加入我们,共同守护地球家园</p>
+    
+    <form #regForm="ngForm" (ngSubmit)="onSubmit()">
+      <div class="form-group">
+        <label for="identity">选择身份</label>
+        <div class="identity-options">
+          <div 
+            *ngFor="let option of identityOptions" 
+            class="identity-option"
+            [class.active]="registerForm.identity === option.value"
+            (click)="selectIdentity(option.value)">
+            <div class="identity-icon">{{option.icon}}</div>
+            <div>{{option.label}}</div>
+          </div>
+        </div>
+        <div class="error-message" [style.display]="formErrors.identity ? 'block' : 'none'">
+          请选择身份类型
+        </div>
+      </div>
+      
+      <div class="form-group">
+        <label for="account">账户信息</label>
+        <div class="input-with-icon">
+          <span class="input-icon">📱</span>
+          <input 
+            type="text" 
+            id="account" 
+            name="account"
+            [(ngModel)]="registerForm.account"
+            (blur)="validateAccount()"
+            placeholder="手机号/邮箱/用户名" 
+            required>
+        </div>
+        <div class="error-message" [style.display]="formErrors.account ? 'block' : 'none'">
+          请输入有效的账户信息
+        </div>
+      </div>
+      
+      <div class="form-group">
+        <label for="password">设置密码</label>
+        <div class="input-with-icon">
+          <span class="input-icon">🔒</span>
+          <input 
+            [type]="showPassword ? 'text' : 'password'" 
+            id="password" 
+            name="password"
+            [(ngModel)]="registerForm.password"
+            (input)="validatePassword()"
+            placeholder="6-20位数字、字母或特殊字符" 
+            required>
+          <button 
+            type="button" 
+            class="password-toggle"
+            (click)="togglePasswordVisibility('password')">
+            {{showPassword ? '🙈' : '👁️'}}
+          </button>
+        </div>
+        <div class="password-requirements">密码需包含6-20位字符,可使用数字、字母或特殊字符</div>
+        <div class="error-message" [style.display]="formErrors.password ? 'block' : 'none'">
+          密码不符合要求
+        </div>
+      </div>
+      
+      <div class="form-group">
+        <label for="confirmPassword">确认密码</label>
+        <div class="input-with-icon">
+          <span class="input-icon">🔒</span>
+          <input 
+            [type]="showConfirmPassword ? 'text' : 'password'" 
+            id="confirmPassword" 
+            name="confirmPassword"
+            [(ngModel)]="registerForm.confirmPassword"
+            (input)="validateConfirmPassword()"
+            placeholder="请再次输入密码" 
+            required>
+          <button 
+            type="button" 
+            class="password-toggle"
+            (click)="togglePasswordVisibility('confirmPassword')">
+            {{showConfirmPassword ? '🙈' : '👁️'}}
+          </button>
+        </div>
+        <div class="error-message" [style.display]="formErrors.confirmPassword ? 'block' : 'none'">
+          两次输入的密码不一致
+        </div>
+      </div>
+      
+      <button type="submit" class="btn-register">注册账号</button>
+    </form>
+    
+    <div class="login-link">
+      已有账户?<a (click)="goToLogin()">立即登录</a>
     </div>
-    <!-- 页面内容已清理,保留基本结构 -->
+  </div>
+  
+  <div class="footer">
+    注册即表示同意<a href="#">《用户协议》</a>和<a href="#">《隐私政策》</a>
   </div>
 </div>

+ 251 - 167
src/app/auth/register/register.scss

@@ -1,197 +1,281 @@
-.register-container {
+// 注册页面样式
+.register-page {
+  * {
+    margin: 0;
+    padding: 0;
+    box-sizing: border-box;
+    font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+  }
+  
+  background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
   min-height: 100vh;
   display: flex;
-  align-items: center;
-  justify-content: center;
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-  padding: 20px;
-}
-
-.register-card {
-  background: white;
-  border-radius: 16px;
-  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
-  padding: 40px;
-  width: 100%;
-  max-width: 480px;
-  animation: slideUp 0.6s ease-out;
-}
-
-@keyframes slideUp {
-  from {
-    opacity: 0;
-    transform: translateY(30px);
-  }
-  to {
-    opacity: 1;
-    transform: translateY(0);
-  }
-}
-
-.register-header {
-  text-align: center;
-  margin-bottom: 32px;
-
-  h1 {
-    color: #2d3748;
-    font-size: 28px;
-    font-weight: 700;
-    margin: 0 0 8px 0;
-  }
-
-  p {
-    color: #718096;
-    font-size: 16px;
-    margin: 0;
+  flex-direction: column;
+  padding: 20px 20px 40px;
+  
+  .header {
+    display: flex;
+    align-items: center;
+    margin-bottom: 30px;
+    padding-top: 10px;
+    
+    .back-btn {
+      width: 40px;
+      height: 40px;
+      border-radius: 50%;
+      background: rgba(255, 255, 255, 0.7);
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      font-size: 20px;
+      color: #2e7d32;
+      border: none;
+      cursor: pointer;
+      box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+      transition: all 0.3s;
+      
+      &:hover {
+        background: rgba(255, 255, 255, 0.9);
+        transform: translateY(-1px);
+      }
+    }
+    
+    .app-title {
+      flex: 1;
+      text-align: center;
+      font-size: 20px;
+      font-weight: 600;
+      color: #1b5e20;
+    }
+    
+    .logo {
+      width: 40px;
+      height: 40px;
+      background: #2e7d32;
+      border-radius: 10px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      color: white;
+      font-size: 22px;
+      margin-right: 10px;
+    }
   }
-}
-
-.register-form {
-  .form-group {
+  
+  .container {
+    background: white;
+    border-radius: 20px;
+    padding: 25px;
+    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.05);
     margin-bottom: 20px;
-
-    label {
-      display: block;
-      color: #4a5568;
+    
+    .form-title {
+      font-size: 24px;
       font-weight: 600;
-      margin-bottom: 8px;
+      color: #1b5e20;
+      margin-bottom: 5px;
+    }
+    
+    .form-subtitle {
+      color: #7c8a7e;
       font-size: 14px;
+      margin-bottom: 25px;
     }
-
-    .form-control {
-      width: 100%;
-      padding: 12px 16px;
-      border: 2px solid #e2e8f0;
-      border-radius: 8px;
-      font-size: 16px;
-      transition: all 0.3s ease;
-      box-sizing: border-box;
-
-      &:focus {
-        outline: none;
-        border-color: #667eea;
-        box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
+    
+    .form-group {
+      margin-bottom: 20px;
+      
+      label {
+        display: block;
+        margin-bottom: 8px;
+        font-weight: 500;
+        color: #455a64;
+        font-size: 15px;
       }
-
-      &::placeholder {
-        color: #a0aec0;
+      
+      .input-with-icon {
+        position: relative;
+        
+        .input-icon {
+          position: absolute;
+          left: 15px;
+          top: 50%;
+          transform: translateY(-50%);
+          color: #7c8a7e;
+          font-size: 18px;
+          z-index: 1;
+        }
+        
+        input {
+          width: 100%;
+          padding: 16px 16px 16px 50px;
+          border: 1px solid #e0e0e0;
+          border-radius: 12px;
+          font-size: 16px;
+          transition: all 0.3s;
+          background: #fafafa;
+          
+          &:focus {
+            outline: none;
+            border-color: #4caf50;
+            background: white;
+            box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.2);
+          }
+        }
+        
+        .password-toggle {
+          position: absolute;
+          right: 15px;
+          top: 50%;
+          transform: translateY(-50%);
+          background: none;
+          border: none;
+          color: #7c8a7e;
+          font-size: 18px;
+          cursor: pointer;
+          z-index: 1;
+          
+          &:hover {
+            color: #2e7d32;
+          }
+        }
+      }
+      
+      .password-requirements {
+        font-size: 12px;
+        color: #7c8a7e;
+        margin-top: 8px;
+        line-height: 1.4;
+      }
+      
+      .error-message {
+        color: #f44336;
+        font-size: 13px;
+        margin-top: 5px;
+        display: none;
+        
+        &[style*="block"] {
+          display: block !important;
+        }
+      }
+      
+      .identity-options {
+        display: flex;
+        gap: 10px;
+        margin-top: 10px;
+        
+        .identity-option {
+          flex: 1;
+          text-align: center;
+          padding: 15px 10px;
+          border: 1px solid #e0e0e0;
+          border-radius: 12px;
+          background: #fafafa;
+          cursor: pointer;
+          transition: all 0.3s;
+          
+          &:hover {
+            border-color: #4caf50;
+            background: rgba(76, 175, 80, 0.05);
+          }
+          
+          &.active {
+            border-color: #4caf50;
+            background: rgba(76, 175, 80, 0.1);
+            color: #2e7d32;
+            font-weight: 500;
+          }
+          
+          .identity-icon {
+            font-size: 24px;
+            margin-bottom: 8px;
+          }
+        }
       }
     }
-
-    select.form-control {
+    
+    .btn-register {
+      width: 100%;
+      padding: 18px;
+      background: linear-gradient(to right, #4caf50, #2e7d32);
+      color: white;
+      border: none;
+      border-radius: 12px;
+      font-size: 17px;
+      font-weight: 600;
       cursor: pointer;
-      background-color: white;
-    }
-  }
-
-  .error-message {
-    background-color: #fed7d7;
-    color: #c53030;
-    padding: 12px 16px;
-    border-radius: 8px;
-    margin-bottom: 20px;
-    font-size: 14px;
-    border: 1px solid #feb2b2;
-  }
-
-  .submit-btn {
-    width: 100%;
-    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-    color: white;
-    border: none;
-    padding: 14px 24px;
-    border-radius: 8px;
-    font-size: 16px;
-    font-weight: 600;
-    cursor: pointer;
-    transition: all 0.3s ease;
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    gap: 8px;
-
-    &:hover:not(:disabled) {
-      transform: translateY(-2px);
-      box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
-    }
-
-    &:disabled {
-      opacity: 0.6;
-      cursor: not-allowed;
-      transform: none;
+      transition: all 0.3s;
+      box-shadow: 0 4px 10px rgba(76, 175, 80, 0.3);
+      margin-top: 10px;
+      
+      &:hover {
+        transform: translateY(-2px);
+        box-shadow: 0 6px 15px rgba(76, 175, 80, 0.4);
+      }
+      
+      &:active {
+        transform: translateY(2px);
+        box-shadow: 0 2px 5px rgba(76, 175, 80, 0.3);
+      }
     }
-
-    .loading-spinner {
-      width: 16px;
-      height: 16px;
-      border: 2px solid transparent;
-      border-top: 2px solid white;
-      border-radius: 50%;
-      animation: spin 1s linear infinite;
+    
+    .login-link {
+      text-align: center;
+      margin-top: 25px;
+      color: #7c8a7e;
+      font-size: 15px;
+      
+      a {
+        color: #2e7d32;
+        text-decoration: none;
+        font-weight: 500;
+        cursor: pointer;
+        
+        &:hover {
+          text-decoration: underline;
+        }
+      }
     }
   }
-
-  .login-link {
+  
+  .footer {
     text-align: center;
-    margin-top: 24px;
-    color: #718096;
-    font-size: 14px;
-
+    margin-top: auto;
+    color: #7c8a7e;
+    font-size: 13px;
+    padding-top: 20px;
+    
     a {
-      color: #667eea;
+      color: #2e7d32;
       text-decoration: none;
-      font-weight: 600;
-      transition: color 0.3s ease;
-
+      
       &:hover {
-        color: #5a67d8;
         text-decoration: underline;
       }
     }
   }
 }
 
-@keyframes spin {
-  0% { transform: rotate(0deg); }
-  100% { transform: rotate(360deg); }
-}
-
 // 响应式设计
 @media (max-width: 768px) {
-  .register-container {
-    padding: 16px;
-  }
-
-  .register-card {
-    padding: 24px;
-    margin: 0;
-  }
-
-  .register-header {
-    margin-bottom: 24px;
-
-    h1 {
-      font-size: 24px;
-    }
-
-    p {
-      font-size: 14px;
-    }
-  }
-
-  .register-form {
-    .form-group {
-      margin-bottom: 16px;
-
-      .form-control {
-        padding: 10px 14px;
-        font-size: 16px; // 防止iOS缩放
+  .register-page {
+    padding: 15px 15px 30px;
+    
+    .container {
+      padding: 20px;
+      
+      .form-title {
+        font-size: 22px;
+      }
+      
+      .identity-options {
+        flex-direction: column;
+        gap: 8px;
+        
+        .identity-option {
+          padding: 12px 10px;
+        }
       }
-    }
-
-    .submit-btn {
-      padding: 12px 20px;
-      font-size: 16px;
     }
   }
 }

+ 151 - 0
src/app/auth/register/register.ts

@@ -3,6 +3,20 @@ import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { Router, RouterModule } from '@angular/router';
 
+interface RegisterForm {
+  identity: string;
+  account: string;
+  password: string;
+  confirmPassword: string;
+}
+
+interface FormErrors {
+  identity: boolean;
+  account: boolean;
+  password: boolean;
+  confirmPassword: boolean;
+}
+
 @Component({
   selector: 'app-register',
   imports: [CommonModule, FormsModule, RouterModule],
@@ -10,5 +24,142 @@ import { Router, RouterModule } from '@angular/router';
   styleUrl: './register.scss'
 })
 export class Register {
+  // 表单数据
+  registerForm: RegisterForm = {
+    identity: 'user',
+    account: '',
+    password: '',
+    confirmPassword: ''
+  };
+
+  // 错误状态
+  formErrors: FormErrors = {
+    identity: false,
+    account: false,
+    password: false,
+    confirmPassword: false
+  };
+
+  // 密码显示状态
+  showPassword = false;
+  showConfirmPassword = false;
+
+  // 身份选项
+  identityOptions = [
+    { value: 'user', label: 'C端用户', icon: '👤' },
+    { value: 'business', label: 'B端企业', icon: '🏢' },
+    { value: 'government', label: 'G端政府', icon: '🏛️' }
+  ];
+
   constructor(private router: Router) {}
+
+  // 选择身份
+  selectIdentity(identity: string) {
+    this.registerForm.identity = identity;
+    this.formErrors.identity = false;
+  }
+
+  // 切换密码显示
+  togglePasswordVisibility(field: 'password' | 'confirmPassword') {
+    if (field === 'password') {
+      this.showPassword = !this.showPassword;
+    } else {
+      this.showConfirmPassword = !this.showConfirmPassword;
+    }
+  }
+
+  // 实时验证密码
+  validatePassword() {
+    const passwordRegex = /^[A-Za-z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]{6,20}$/;
+    this.formErrors.password = !passwordRegex.test(this.registerForm.password);
+  }
+
+  // 实时验证确认密码
+  validateConfirmPassword() {
+    this.formErrors.confirmPassword = this.registerForm.password !== this.registerForm.confirmPassword;
+  }
+
+  // 验证账户信息
+  validateAccount() {
+    this.formErrors.account = !this.registerForm.account.trim();
+  }
+
+  // 表单提交
+  onSubmit() {
+    // 重置错误状态
+    this.formErrors = {
+      identity: false,
+      account: false,
+      password: false,
+      confirmPassword: false
+    };
+
+    let isValid = true;
+
+    // 验证身份选择
+    if (!this.registerForm.identity) {
+      this.formErrors.identity = true;
+      isValid = false;
+    }
+
+    // 验证账户信息
+    if (!this.registerForm.account.trim()) {
+      this.formErrors.account = true;
+      isValid = false;
+    }
+
+    // 验证密码
+    const passwordRegex = /^[A-Za-z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]{6,20}$/;
+    if (!passwordRegex.test(this.registerForm.password)) {
+      this.formErrors.password = true;
+      isValid = false;
+    }
+
+    // 验证确认密码
+    if (this.registerForm.password !== this.registerForm.confirmPassword) {
+      this.formErrors.confirmPassword = true;
+      isValid = false;
+    }
+
+    if (isValid) {
+      // Mock 注册成功
+      this.mockRegister();
+    }
+  }
+
+  // Mock 注册处理
+  private mockRegister() {
+    // 模拟API调用延迟
+    setTimeout(() => {
+      // Mock 注册成功响应
+      const mockResponse = {
+        success: true,
+        message: '注册成功!',
+        user: {
+          id: Math.random().toString(36).substr(2, 9),
+          identity: this.registerForm.identity,
+          account: this.registerForm.account,
+          createdAt: new Date().toISOString()
+        }
+      };
+
+      console.log('Mock 注册响应:', mockResponse);
+      
+      // 显示成功消息
+      alert('注册成功!即将跳转到登录页面。');
+      
+      // 跳转到登录页面
+      this.router.navigate(['/auth/login']);
+    }, 1000);
+  }
+
+  // 返回上一页
+  goBack() {
+    this.router.navigate(['/auth/login']);
+  }
+
+  // 跳转到登录页面
+  goToLogin() {
+    this.router.navigate(['/auth/login']);
+  }
 }

+ 1 - 1
src/app/business/ai-operations-assistant/ai-operations-assistant.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './ai-operations-assistant.html',
   styleUrl: './ai-operations-assistant.scss'
 })
-export class AiOperationsAssistantComponent {
+export class AiOperationsAssistant {
   constructor() {}
 }

+ 1 - 1
src/app/business/dashboard/dashboard.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './dashboard.html',
   styleUrl: './dashboard.scss'
 })
-export class DashboardComponent {
+export class Dashboard {
   constructor() {}
 }

+ 1 - 1
src/app/business/data-reports/data-reports.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './data-reports.html',
   styleUrl: './data-reports.scss'
 })
-export class DataReportsComponent {
+export class DataReports {
   constructor() {}
 }

+ 1 - 1
src/app/business/device-management/device-management.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './device-management.html',
   styleUrl: './device-management.scss'
 })
-export class DeviceManagementComponent {
+export class DeviceManagement {
   constructor() {}
 }

+ 1 - 1
src/app/business/enterprise-center/enterprise-center.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './enterprise-center.html',
   styleUrl: './enterprise-center.scss'
 })
-export class EnterpriseCenterComponent {
+export class EnterpriseCenter {
   constructor() {}
 }

+ 1 - 1
src/app/business/order-management/order-management.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './order-management.html',
   styleUrl: './order-management.scss'
 })
-export class OrderManagementComponent {
+export class OrderManagement {
   constructor() {}
 }

+ 60 - 2
src/app/consumer/ai-assistant/ai-assistant.html

@@ -1,6 +1,64 @@
 <div class="ai-assistant-container">
   <div class="assistant-header">
-    <h1>AI助手</h1>
+    <div class="title">AI回收助手</div>
+    <button class="back-home" (click)="goHome()"><i class="fas fa-home"></i> 返回首页</button>
+  </div>
+
+  <!-- 对话区域 -->
+  <div class="chat-container">
+    <div class="messages">
+      <div class="message" *ngFor="let m of messages" [class.user]="m.role==='user'" [class.assistant]="m.role==='assistant'">
+        <div class="avatar">
+          <i class="fas" [ngClass]="m.role==='user' ? 'fa-user' : 'fa-robot'"></i>
+        </div>
+        <div class="bubble">{{ m.text }}</div>
+      </div>
+    </div>
+    <div class="input-bar">
+      <input [(ngModel)]="inputText" placeholder="请输入问题或上传图片..." />
+      <button class="voice-btn" [class.recording]="isRecording" (mousedown)="startRecording()" (mouseup)="stopRecording()" (touchstart)="startRecording()" (touchend)="stopRecording()">
+        <i class="fas fa-microphone"></i>
+      </button>
+      <button class="send-btn" (click)="sendMessage()">
+        <i class="fas fa-paper-plane"></i>
+      </button>
+    </div>
+  </div>
+
+  <!-- 助手能力导航 -->
+  <div class="section">
+    <div class="section-title">助手能力</div>
+    <div class="abilities-grid">
+      <div class="ability-card" (click)="askQuickQuestion('帮我识别这个物品是否可以回收')">
+        <div class="ability-icon"><i class="fas fa-question-circle"></i></div>
+        <div class="ability-name">识别答疑</div>
+        <div class="ability-desc">物品分类识别</div>
+      </div>
+      <div class="ability-card" (click)="askQuickQuestion('查询当前回收价格')">
+        <div class="ability-icon"><i class="fas fa-tag"></i></div>
+        <div class="ability-name">价格查询</div>
+        <div class="ability-desc">实时价格信息</div>
+      </div>
+      <div class="ability-card" (click)="askQuickQuestion('回收流程指导')">
+        <div class="ability-icon"><i class="fas fa-list-alt"></i></div>
+        <div class="能力-name">流程指导</div>
+        <div class="ability-desc">标准化流程说明</div>
+      </div>
+      <div class="ability-card" (click)="askQuickQuestion('附近投递点查询')">
+        <div class="能力-icon"><i class="fas fa-location-dot"></i></div>
+        <div class="ability-name">投递点</div>
+        <div class="ability-desc">附近站点信息</div>
+      </div>
+      <div class="ability-card" (click)="askQuickQuestion('预约上门时间建议')">
+        <div class="ability-icon"><i class="fas fa-calendar-days"></i></div>
+        <div class="ability-name">时间建议</div>
+        <div class="ability-desc">合适预约时间</div>
+      </div>
+      <div class="ability-card" (click)="askQuickQuestion('环保积分规则说明')">
+        <div class="ability-icon"><i class="fas fa-coins"></i></div>
+        <div class="ability-name">积分规则</div>
+        <div class="ability-desc">获取与使用</div>
+      </div>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
 </div>

+ 77 - 0
src/app/consumer/ai-assistant/ai-assistant.scss

@@ -0,0 +1,77 @@
+/* 容器与头部 */
+.ai-assistant-container {
+  padding-bottom: 88px; /* 预留底部导航空间(若后续添加) */
+}
+
+.assistant-header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 16px;
+  background: linear-gradient(135deg, #2ecc71, #1abc9c);
+  color: #fff;
+}
+.assistant-header .title { font-size: 18px; font-weight: 600; }
+.assistant-header .back-home {
+  background: rgba(255,255,255,0.15);
+  color: #fff;
+  border: none;
+  border-radius: 20px;
+  padding: 6px 12px;
+  display: flex; align-items: center; gap: 6px;
+}
+
+/* 对话区域 */
+.chat-container { padding: 12px 12px 0; }
+.messages { display: flex; flex-direction: column; gap: 10px; }
+.message { display: flex; gap: 8px; align-items: flex-end; }
+.message .avatar {
+  width: 28px; height: 28px; border-radius: 50%;
+  display: flex; align-items: center; justify-content: center;
+  background: #f1f3f4; color: #2e7d32;
+}
+.message .bubble {
+  max-width: 72%;
+  padding: 10px 12px;
+  border-radius: 12px;
+  background: #f8f9fa; color: #333; font-size: 14px;
+}
+.message.user { flex-direction: row-reverse; }
+.message.user .bubble { background: #e8f5e9; }
+.message.user .avatar { background: #e0f2f1; }
+.message.assistant .avatar { background: #e3f2fd; color: #1e88e5; }
+
+/* 输入栏 */
+.input-bar {
+  display: flex; gap: 8px; align-items: center;
+  padding: 10px 12px; background: #fff; border-top: 1px solid #ececec;
+  position: sticky; bottom: 0; left: 0; right: 0;
+}
+.input-bar input {
+  flex: 1; height: 40px; border: 1px solid #e9ecef; border-radius: 8px; padding: 0 10px;
+}
+.voice-btn, .send-btn {
+  width: 40px; height: 40px; border-radius: 50%; border: none; cursor: pointer;
+  display: flex; align-items: center; justify-content: center;
+  background: #f1f3f4; color: #333;
+}
+.voice-btn.recording { animation: pulse 1.2s infinite; background: #ffebee; color: #e53935; }
+@keyframes pulse { 0% { transform: scale(1); } 50% { transform: scale(1.08); } 100% { transform: scale(1); } }
+.send-btn { background: #2e7d32; color: #fff; }
+
+/* 能力导航 */
+.section { padding: 12px; }
+.section-title { font-size: 16px; font-weight: 600; margin-bottom: 10px; }
+.abilities-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
+.ability-card { background: #f8f9fa; border-radius: 12px; padding: 14px 10px; text-align: center; cursor: pointer; transition: all .2s; }
+.ability-card:hover { background: rgba(46, 204, 113, 0.1); transform: translateY(-2px); }
+.ability-icon {
+  width: 48px; height: 48px; margin: 0 auto 8px; border-radius: 50%;
+  background: rgba(46, 204, 113, 0.1); color: #2e7d32; display: flex; align-items: center; justify-content: center;
+}
+.ability-name { font-size: 14px; font-weight: 500; }
+.ability-desc { font-size: 12px; color: #6c757d; }
+
+@media (max-width: 360px) {
+  .abilities-grid { grid-template-columns: repeat(2, 1fr); }
+}

+ 50 - 4
src/app/consumer/ai-assistant/ai-assistant.ts

@@ -1,13 +1,59 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { RouterModule, Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
 
 @Component({
   selector: 'app-ai-assistant',
-  imports: [CommonModule, RouterModule],
+  standalone: true,
+  imports: [CommonModule, RouterModule, FormsModule],
   templateUrl: './ai-assistant.html',
   styleUrl: './ai-assistant.scss'
 })
-export class AiAssistantComponent {
-  constructor() {}
+export class AiAssistant {
+  // 简易对话数据
+  messages: { role: 'user' | 'assistant'; text: string }[] = [
+    { role: 'assistant', text: '你好!我是AI回收助手,很高兴为你服务~' }
+  ];
+
+  inputText = '';
+  isRecording = false;
+
+  constructor(private router: Router) {}
+
+  // 返回首页
+  goHome(): void {
+    this.router.navigate(['/consumer/home']);
+  }
+
+  // 发送消息
+  sendMessage(): void {
+    const text = this.inputText.trim();
+    if (!text) return;
+    this.messages.push({ role: 'user', text });
+    this.inputText = '';
+    // 简易应答,占位逻辑
+    setTimeout(() => {
+      this.messages.push({ role: 'assistant', text: '已收到你的问题:' + text + ',我来帮你处理~' });
+    }, 300);
+  }
+
+  // 快速提问
+  askQuickQuestion(text: string): void {
+    this.messages.push({ role: 'user', text });
+    setTimeout(() => {
+      this.messages.push({ role: 'assistant', text: '这是关于“' + text + '”的建议与说明...' });
+    }, 300);
+  }
+
+  // 语音录制占位
+  startRecording(): void {
+    this.isRecording = true;
+  }
+
+  stopRecording(): void {
+    this.isRecording = false;
+    // 占位:结束录音后填充识别文本
+    this.inputText = this.inputText || '(语音已转换为文本占位)';
+  }
 }

+ 187 - 5
src/app/consumer/booking-recycle/booking-recycle.html

@@ -1,6 +1,188 @@
-<div class="booking-recycle-container">
-  <div class="booking-header">
-    <h1>预约回收</h1>
+<!-- 顶部标题栏 -->
+<div class="header">
+  <div class="back-btn" (click)="goBack()"><i class="fas fa-arrow-left"></i></div>
+  <div class="header-title">预约回收</div>
+</div>
+
+<div class="container">
+  <!-- 废品信息填写 -->
+  <div class="form-section">
+    <div class="section-title">
+      <i class="fas fa-trash-alt"></i> 废品信息
+    </div>
+    
+    <div class="category-select">
+      <div 
+        *ngFor="let category of wasteCategories" 
+        class="category-item" 
+        [class.active]="category.active"
+        (click)="selectCategory(category)">
+        <div class="category-icon"><i [class]="category.icon"></i></div>
+        <div>{{category.name}}</div>
+      </div>
+    </div>
+    
+    <div class="weight-input">
+      <input 
+        type="number" 
+        placeholder="输入预估重量" 
+        [(ngModel)]="weight"
+        (input)="calculateEarnings()">
+      <div class="unit">公斤</div>
+    </div>
+    
+    <div class="photo-upload">
+      <div class="upload-btn" (click)="uploadPhoto()">
+        <i class="fas fa-camera"></i>
+        <div>上传照片</div>
+      </div>
+      <div 
+        *ngFor="let photo of photos; let i = index" 
+        class="photo-preview">
+        <img [src]="photo" alt="废品照片">
+        <div class="remove-photo" (click)="removePhoto(i)">
+          <i class="fas fa-times"></i>
+        </div>
+      </div>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
-</div>
+  
+  <!-- 回收方式选择 -->
+  <div class="form-section">
+    <div class="section-title">
+      <i class="fas fa-truck"></i> 回收方式
+    </div>
+    
+    <div class="recycle-method">
+      <div 
+        *ngFor="let method of recycleMethods"
+        class="method-card" 
+        [class.active]="method.active"
+        (click)="selectMethod(method)">
+        <div class="method-icon"><i [class]="method.icon"></i></div>
+        <div class="method-title">{{method.name}}</div>
+        <div class="method-desc">{{method.description}}</div>
+      </div>
+    </div>
+    
+    <div class="address-select" *ngIf="isPickupMethod">
+      <div class="address-info">
+        <div class="address-text">
+          <div>{{address}}</div>
+          <div style="font-size: 12px; color: #6c757d;">{{contactName}} {{contactPhone}}</div>
+        </div>
+        <div class="change-address" (click)="changeAddress()">更改</div>
+      </div>
+    </div>
+    
+    <div class="point-select" *ngIf="!isPickupMethod">
+      <div class="point-info">
+        <div>
+          <div class="point-name">阳光小区东门回收点</div>
+          <div class="point-detail">350米 | 70% 满箱</div>
+        </div>
+        <button class="navigate-btn" (click)="navigateToPoint()">导航</button>
+      </div>
+    </div>
+  </div>
+  
+  <!-- 时间选择 -->
+  <div class="form-section">
+    <div class="section-title">
+      <i class="far fa-clock"></i> 回收时间
+    </div>
+    
+    <div class="time-options">
+      <div 
+        *ngFor="let option of timeOptions"
+        class="time-option" 
+        [class.active]="option.active"
+        (click)="selectTimeOption(option)">
+        <div class="method-icon"><i [class]="option.icon"></i></div>
+        <div class="method-title">{{option.name}}</div>
+        <div class="method-desc">{{option.description}}</div>
+      </div>
+    </div>
+    
+    <div class="date-selector" *ngIf="isScheduledTime">
+      <div class="date-scroll">
+        <div 
+          *ngFor="let date of dateItems"
+          class="date-item" 
+          [class.active]="date.active"
+          (click)="selectDate(date)">
+          <div class="date-day">{{date.day}}</div>
+          <div class="date-week">{{date.date}}</div>
+        </div>
+      </div>
+      
+      <div class="time-slots">
+        <div 
+          *ngFor="let slot of timeSlots"
+          class="time-slot" 
+          [class.active]="slot.active"
+          (click)="selectTimeSlot(slot)">
+          {{slot.time}}
+        </div>
+      </div>
+    </div>
+  </div>
+  
+  <!-- 附加服务 -->
+  <div class="form-section">
+    <div class="section-title">
+      <i class="fas fa-concierge-bell"></i> 附加服务
+    </div>
+    
+    <div class="additional-services">
+      <div 
+        *ngFor="let service of additionalServices"
+        class="service-item">
+        <div class="service-info">
+          <div class="service-icon"><i [class]="service.icon"></i></div>
+          <div>
+            <div class="service-name">{{service.name}}</div>
+            <div class="service-desc">{{service.description}}</div>
+          </div>
+        </div>
+        <div class="service-price">{{service.price}}</div>
+        <label class="switch">
+          <input 
+            type="checkbox" 
+            [checked]="service.enabled"
+            (change)="toggleService(service)">
+          <span class="slider"></span>
+        </label>
+      </div>
+      
+      <div class="service-item" style="flex-direction: column; align-items: flex-start;">
+        <div class="service-info" style="width: 100%; margin-bottom: 10px;">
+          <div class="service-icon"><i class="fas fa-note-sticky"></i></div>
+          <div>
+            <div class="service-name">备注</div>
+            <div class="service-desc">特殊要求或说明</div>
+          </div>
+        </div>
+        <div style="position: relative; width: 100%;">
+          <textarea 
+            class="notes-input" 
+            placeholder="请输入备注信息..."
+            [(ngModel)]="notes"></textarea>
+          <div class="voice-input"><i class="fas fa-microphone"></i></div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- 确认预约栏 -->
+<div class="confirm-bar">
+  <div class="estimate-earnings">
+    <div class="earnings-title">预估收益</div>
+    <div class="earnings-amount">¥{{estimatedEarnings.toFixed(2)}}</div>
+  </div>
+  <button class="submit-btn" (click)="submitBooking()">确认提交</button>
+</div>
+
+<!-- 底部导航栏 -->
+<app-bottom-nav [activeTab]="'booking'"></app-bottom-nav>

+ 715 - 0
src/app/consumer/booking-recycle/booking-recycle.scss

@@ -0,0 +1,715 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+}
+
+body {
+  background-color: #f8f9fa;
+  color: #333;
+  padding-bottom: 80px;
+}
+
+.header {
+  background: linear-gradient(135deg, #2ecc71, #1abc9c);
+  color: white;
+  padding: 15px 20px;
+  display: flex;
+  align-items: center;
+  position: sticky;
+  top: 0;
+  z-index: 100;
+}
+
+.back-btn {
+  font-size: 20px;
+  margin-right: 15px;
+  cursor: pointer;
+  transition: opacity 0.3s;
+  
+  &:hover {
+    opacity: 0.8;
+  }
+}
+
+.header-title {
+  font-size: 18px;
+  font-weight: 600;
+}
+
+.container {
+  padding: 15px;
+}
+
+.form-section {
+  background: white;
+  margin-bottom: 15px;
+  padding: 20px;
+  border-radius: 16px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
+}
+
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 15px;
+  color: #2c3e50;
+  display: flex;
+  align-items: center;
+  
+  i {
+    margin-right: 8px;
+    color: #2e7d32;
+  }
+}
+
+/* 废品信息填写 */
+.category-select {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.category-item {
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 12px;
+  padding: 12px 8px;
+  text-align: center;
+  font-size: 14px;
+  transition: all 0.3s;
+  cursor: pointer;
+  
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+    border-color: #2ecc71;
+    color: #2e7d32;
+    font-weight: 500;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.category-icon {
+  font-size: 20px;
+  margin-bottom: 5px;
+}
+
+.weight-input {
+  display: flex;
+  align-items: center;
+  margin-bottom: 15px;
+  
+  input {
+    flex: 1;
+    padding: 12px 15px;
+    border: 1px solid #e9ecef;
+    border-radius: 12px;
+    font-size: 16px;
+    margin-right: 10px;
+    transition: border-color 0.3s;
+    
+    &:focus {
+      outline: none;
+      border-color: #2ecc71;
+    }
+  }
+}
+
+.unit {
+  color: #6c757d;
+  font-size: 14px;
+}
+
+.photo-upload {
+  display: flex;
+  gap: 10px;
+  flex-wrap: wrap;
+}
+
+.upload-btn {
+  width: 80px;
+  height: 80px;
+  border: 1px dashed #ced4da;
+  border-radius: 12px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  color: #6c757d;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s;
+  
+  &:hover {
+    border-color: #2ecc71;
+    color: #2e7d32;
+  }
+  
+  i {
+    font-size: 24px;
+    margin-bottom: 5px;
+  }
+}
+
+.photo-preview {
+  width: 80px;
+  height: 80px;
+  border-radius: 12px;
+  background: #f8f9fa;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  position: relative;
+  
+  img {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+    border-radius: 12px;
+  }
+}
+
+.remove-photo {
+  position: absolute;
+  top: -5px;
+  right: -5px;
+  width: 20px;
+  height: 20px;
+  background: #ff4757;
+  color: white;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 12px;
+  cursor: pointer;
+  transition: background-color 0.3s;
+  
+  &:hover {
+    background: #ff3742;
+  }
+}
+
+/* 回收方式选择 */
+.recycle-method {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.method-card {
+  flex: 1;
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 12px;
+  padding: 15px;
+  text-align: center;
+  transition: all 0.3s;
+  cursor: pointer;
+  
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+    border-color: #2ecc71;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.method-icon {
+  font-size: 24px;
+  margin-bottom: 8px;
+  color: #2e7d32;
+}
+
+.method-title {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 5px;
+}
+
+.method-desc {
+  font-size: 12px;
+  color: #6c757d;
+}
+
+.address-select {
+  background: #f8f9fa;
+  border-radius: 12px;
+  padding: 15px;
+  margin-bottom: 15px;
+}
+
+.address-info {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.address-text {
+  font-size: 14px;
+}
+
+.change-address {
+  color: #2e7d32;
+  font-size: 14px;
+  cursor: pointer;
+  transition: color 0.3s;
+  
+  &:hover {
+    color: #1b5e20;
+  }
+}
+
+.point-select {
+  background: #f8f9fa;
+  border-radius: 12px;
+  padding: 15px;
+  margin-bottom: 15px;
+}
+
+.point-info {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.point-name {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 5px;
+}
+
+.point-detail {
+  font-size: 12px;
+  color: #6c757d;
+}
+
+.navigate-btn {
+  background: #2e7d32;
+  color: white;
+  border: none;
+  border-radius: 8px;
+  padding: 8px 12px;
+  font-size: 12px;
+  cursor: pointer;
+  transition: background-color 0.3s;
+  
+  &:hover {
+    background: #1b5e20;
+  }
+}
+
+/* 时间选择 */
+.time-options {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.time-option {
+  flex: 1;
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 12px;
+  padding: 15px;
+  text-align: center;
+  transition: all 0.3s;
+  cursor: pointer;
+  
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+    border-color: #2ecc71;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.date-selector {
+  margin-bottom: 15px;
+}
+
+.date-scroll {
+  display: flex;
+  gap: 10px;
+  overflow-x: auto;
+  padding-bottom: 5px;
+  margin-bottom: 15px;
+  
+  &::-webkit-scrollbar {
+    height: 4px;
+  }
+  
+  &::-webkit-scrollbar-track {
+    background: #f1f1f1;
+    border-radius: 2px;
+  }
+  
+  &::-webkit-scrollbar-thumb {
+    background: #c1c1c1;
+    border-radius: 2px;
+  }
+}
+
+.date-item {
+  min-width: 70px;
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 12px;
+  padding: 12px 8px;
+  text-align: center;
+  font-size: 14px;
+  transition: all 0.3s;
+  cursor: pointer;
+  
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+    border-color: #2ecc71;
+    color: #2e7d32;
+    font-weight: 500;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.date-day {
+  font-size: 16px;
+  font-weight: 500;
+  margin-bottom: 5px;
+}
+
+.date-week {
+  font-size: 12px;
+  color: #6c757d;
+}
+
+.time-slots {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  gap: 10px;
+}
+
+.time-slot {
+  background: #f8f9fa;
+  border: 1px solid #e9ecef;
+  border-radius: 8px;
+  padding: 10px 5px;
+  text-align: center;
+  font-size: 14px;
+  transition: all 0.3s;
+  cursor: pointer;
+  
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+    border-color: #2ecc71;
+    color: #2e7d32;
+    font-weight: 500;
+  }
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
+  }
+}
+
+/* 附加服务 */
+.additional-services {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.service-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 0;
+  border-bottom: 1px solid #f1f3f4;
+  
+  &:last-child {
+    border-bottom: none;
+  }
+}
+
+.service-info {
+  display: flex;
+  align-items: center;
+}
+
+.service-icon {
+  width: 36px;
+  height: 36px;
+  background: rgba(46, 204, 113, 0.1);
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 12px;
+  color: #2e7d32;
+}
+
+.service-name {
+  font-size: 14px;
+  font-weight: 500;
+}
+
+.service-desc {
+  font-size: 12px;
+  color: #6c757d;
+}
+
+.service-price {
+  font-size: 14px;
+  color: #2e7d32;
+  font-weight: 500;
+  margin-right: 10px;
+}
+
+.switch {
+  position: relative;
+  display: inline-block;
+  width: 44px;
+  height: 24px;
+  
+  input {
+    opacity: 0;
+    width: 0;
+    height: 0;
+  }
+}
+
+.slider {
+  position: absolute;
+  cursor: pointer;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background-color: #ccc;
+  transition: .4s;
+  border-radius: 24px;
+  
+  &:before {
+    position: absolute;
+    content: "";
+    height: 18px;
+    width: 18px;
+    left: 3px;
+    bottom: 3px;
+    background-color: white;
+    transition: .4s;
+    border-radius: 50%;
+  }
+}
+
+input:checked + .slider {
+  background-color: #2ecc71;
+}
+
+input:checked + .slider:before {
+  transform: translateX(20px);
+}
+
+.notes-input {
+  width: 100%;
+  padding: 12px 15px;
+  border: 1px solid #e9ecef;
+  border-radius: 12px;
+  font-size: 14px;
+  resize: none;
+  height: 80px;
+  margin-top: 10px;
+  transition: border-color 0.3s;
+  
+  &:focus {
+    outline: none;
+    border-color: #2ecc71;
+  }
+}
+
+.voice-input {
+  position: absolute;
+  right: 15px;
+  bottom: 15px;
+  color: #2e7d32;
+  font-size: 18px;
+  cursor: pointer;
+  transition: color 0.3s;
+  
+  &:hover {
+    color: #1b5e20;
+  }
+}
+
+/* 确认预约栏 */
+.confirm-bar {
+  position: fixed;
+  bottom: 60px; /* 为底部导航栏留出空间 */
+  left: 0;
+  right: 0;
+  background: white;
+  padding: 15px 20px;
+  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  z-index: 1000;
+}
+
+.estimate-earnings {
+  .earnings-title {
+    font-size: 12px;
+    color: #6c757d;
+    margin-bottom: 2px;
+  }
+  
+  .earnings-amount {
+    font-size: 18px;
+    font-weight: bold;
+    color: #28a745;
+  }
+}
+
+.submit-btn {
+  background: linear-gradient(135deg, #28a745, #20c997);
+  color: white;
+  border: none;
+  padding: 12px 30px;
+  border-radius: 25px;
+  font-size: 16px;
+  font-weight: bold;
+  cursor: pointer;
+  transition: all 0.3s ease;
+  
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);
+  }
+  
+  &:active {
+    transform: translateY(0);
+  }
+}
+
+/* 底部导航栏 */
+.bottom-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: white;
+  display: flex;
+  padding: 10px 0 20px;
+  box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
+  z-index: 999;
+  
+  .nav-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    
+    &.active {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: linear-gradient(135deg, #4caf50, #66bb6a);
+        color: white;
+        transform: scale(1.1);
+      }
+    }
+    
+    .nav-icon {
+      width: 35px;
+      height: 35px;
+      background: #f8f9fa;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 5px;
+      transition: all 0.3s ease;
+      
+      i {
+        font-size: 16px;
+      }
+    }
+    
+    div:last-child {
+      font-size: 10px;
+      font-weight: 500;
+    }
+    
+    &:hover:not(.active) {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: #f1f8e9;
+        transform: scale(1.05);
+      }
+    }
+  }
+}
+
+/* 响应式设计 */
+@media (max-width: 768px) {
+  .container {
+    padding: 10px;
+  }
+  
+  .form-section {
+    padding: 15px;
+    margin-bottom: 10px;
+  }
+  
+  .category-select {
+    grid-template-columns: repeat(2, 1fr);
+  }
+  
+  .time-slots {
+    grid-template-columns: repeat(2, 1fr);
+  }
+}
+
+@media (max-width: 480px) {
+  .header {
+    padding: 12px 15px;
+  }
+  
+  .header-title {
+    font-size: 16px;
+  }
+  
+  .recycle-method {
+    flex-direction: column;
+  }
+  
+  .time-options {
+    flex-direction: column;
+  }
+  
+  .confirm-bar {
+    padding: 12px 15px;
+  }
+  
+  .submit-btn {
+    padding: 12px 20px;
+    font-size: 14px;
+  }
+}

+ 264 - 5
src/app/consumer/booking-recycle/booking-recycle.ts

@@ -1,13 +1,272 @@
-import { Component } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { RouterModule, Router } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
+
+interface WasteCategory {
+  id: string;
+  name: string;
+  icon: string;
+  active: boolean;
+}
+
+interface RecycleMethod {
+  id: string;
+  name: string;
+  description: string;
+  icon: string;
+  active: boolean;
+}
+
+interface TimeOption {
+  id: string;
+  name: string;
+  description: string;
+  icon: string;
+  active: boolean;
+}
+
+interface DateItem {
+  date: string;
+  day: string;
+  week: string;
+  active: boolean;
+}
+
+interface TimeSlot {
+  time: string;
+  active: boolean;
+}
+
+interface AdditionalService {
+  id: string;
+  name: string;
+  description: string;
+  price: string;
+  icon: string;
+  enabled: boolean;
+}
 
 @Component({
   selector: 'app-booking-recycle',
-  imports: [CommonModule, RouterModule],
+  standalone: true,
+  imports: [CommonModule, RouterModule, FormsModule, BottomNavComponent],
   templateUrl: './booking-recycle.html',
   styleUrl: './booking-recycle.scss'
 })
-export class BookingRecycleComponent {
-  constructor() {}
+export class BookingRecycle implements OnInit {
+  
+  // 废品分类
+  wasteCategories: WasteCategory[] = [
+    { id: 'paper', name: '纸类', icon: 'fas fa-newspaper', active: true },
+    { id: 'plastic', name: '塑料', icon: 'fas fa-bottle-water', active: false },
+    { id: 'glass', name: '玻璃', icon: 'fas fa-wine-glass', active: false },
+    { id: 'electronic', name: '电子', icon: 'fas fa-microchip', active: false },
+    { id: 'textile', name: '衣物', icon: 'fas fa-shirt', active: false },
+    { id: 'other', name: '其他', icon: 'fas fa-box', active: false }
+  ];
+
+  // 回收方式
+  recycleMethods: RecycleMethod[] = [
+    { id: 'pickup', name: '上门回收', description: '回收员上门收取', icon: 'fas fa-home', active: true },
+    { id: 'dropoff', name: '自助投递', description: '送至自助点', icon: 'fas fa-location-dot', active: false }
+  ];
+
+  // 时间选项
+  timeOptions: TimeOption[] = [
+    { id: 'immediate', name: '立即上门', description: '最快30分钟', icon: 'fas fa-bolt', active: true },
+    { id: 'scheduled', name: '预约时间', description: '选择日期', icon: 'fas fa-calendar-days', active: false }
+  ];
+
+  // 日期选项
+  dateItems: DateItem[] = [
+    { date: '10月12日', day: '今天', week: '', active: true },
+    { date: '10月13日', day: '明天', week: '', active: false },
+    { date: '10月14日', day: '周六', week: '', active: false },
+    { date: '10月15日', day: '周日', week: '', active: false }
+  ];
+
+  // 时间段
+  timeSlots: TimeSlot[] = [
+    { time: '09:00-11:00', active: true },
+    { time: '11:00-13:00', active: false },
+    { time: '13:00-15:00', active: false },
+    { time: '15:00-17:00', active: false },
+    { time: '17:00-19:00', active: false },
+    { time: '19:00-21:00', active: false }
+  ];
+
+  // 附加服务
+  additionalServices: AdditionalService[] = [
+    { id: 'carry', name: '搬运服务', description: '协助搬运重物', price: '免费', icon: 'fas fa-dolly', enabled: false },
+    { id: 'clean', name: '清洁服务', description: '清理回收区域', price: '+5元', icon: 'fas fa-broom', enabled: false },
+    { id: 'sort', name: '分类服务', description: '专业分类指导', price: '免费', icon: 'fas fa-sort', enabled: false }
+  ];
+
+  // 表单数据
+  weight: number = 2.5;
+  address: string = '北京市朝阳区建国路88号SOHO现代城';
+  contactName: string = '张三';
+  contactPhone: string = '138****8888';
+  notes: string = '';
+  photos: string[] = [];
+  estimatedEarnings: number = 12.50;
+
+  // 当前选中的导航标签
+  currentTab: string = 'booking';
+
+  constructor(private router: Router) {}
+
+  ngOnInit(): void {
+    this.calculateEarnings();
+  }
+
+  // 选择废品分类
+  selectCategory(category: WasteCategory): void {
+    this.wasteCategories.forEach(c => c.active = false);
+    category.active = true;
+    this.calculateEarnings();
+  }
+
+  // 选择回收方式
+  selectMethod(method: RecycleMethod): void {
+    this.recycleMethods.forEach(m => m.active = false);
+    method.active = true;
+  }
+
+  // 选择时间选项
+  selectTimeOption(option: TimeOption): void {
+    this.timeOptions.forEach(o => o.active = false);
+    option.active = true;
+  }
+
+  // 选择日期
+  selectDate(date: DateItem): void {
+    this.dateItems.forEach(d => d.active = false);
+    date.active = true;
+  }
+
+  // 选择时间段
+  selectTimeSlot(slot: TimeSlot): void {
+    this.timeSlots.forEach(s => s.active = false);
+    slot.active = true;
+  }
+
+  // 切换附加服务
+  toggleService(service: AdditionalService): void {
+    service.enabled = !service.enabled;
+    this.calculateEarnings();
+  }
+
+  // 计算预估收益
+  calculateEarnings(): void {
+    const activeCategory = this.wasteCategories.find(c => c.active);
+    let basePrice = 0;
+    
+    switch(activeCategory?.id) {
+      case 'paper': basePrice = 2.5; break;
+      case 'plastic': basePrice = 3.0; break;
+      case 'glass': basePrice = 1.5; break;
+      case 'electronic': basePrice = 8.0; break;
+      case 'textile': basePrice = 2.0; break;
+      default: basePrice = 2.0;
+    }
+
+    this.estimatedEarnings = basePrice * this.weight;
+    
+    // 添加附加服务费用
+    this.additionalServices.forEach(service => {
+      if (service.enabled && service.price.includes('+')) {
+        const fee = parseFloat(service.price.replace('+', '').replace('元', ''));
+        this.estimatedEarnings += fee;
+      }
+    });
+  }
+
+  // 上传照片
+  uploadPhoto(): void {
+    // 模拟照片上传
+    if (this.photos.length < 3) {
+      this.photos.push('https://via.placeholder.com/80');
+    }
+  }
+
+  // 删除照片
+  removePhoto(index: number): void {
+    this.photos.splice(index, 1);
+  }
+
+  // 更改地址
+  changeAddress(): void {
+    // 跳转到地址选择页面
+    console.log('更改地址');
+  }
+
+  // 导航到投递点
+  navigateToPoint(): void {
+    console.log('导航到投递点');
+  }
+
+  // 返回上一页
+  goBack(): void {
+    this.router.navigate(['/consumer/home']);
+  }
+
+  // 提交预约
+  submitBooking(): void {
+    const bookingData = {
+      category: this.wasteCategories.find(c => c.active),
+      weight: this.weight,
+      method: this.recycleMethods.find(m => m.active),
+      timeOption: this.timeOptions.find(o => o.active),
+      selectedDate: this.dateItems.find(d => d.active),
+      selectedTime: this.timeSlots.find(s => s.active),
+      address: this.address,
+      contact: { name: this.contactName, phone: this.contactPhone },
+      services: this.additionalServices.filter(s => s.enabled),
+      notes: this.notes,
+      photos: this.photos,
+      estimatedEarnings: this.estimatedEarnings
+    };
+
+    console.log('预约数据:', bookingData);
+    
+    // 这里可以调用API提交数据
+    // 提交成功后跳转到确认页面
+    alert('预约提交成功!');
+    this.router.navigate(['/consumer/home']);
+  }
+
+  // 获取当前选中的回收方式
+  get isPickupMethod(): boolean {
+    return this.recycleMethods.find(m => m.active)?.id === 'pickup';
+  }
+
+  // 获取当前选中的时间选项
+  get isScheduledTime(): boolean {
+    return this.timeOptions.find(o => o.active)?.id === 'scheduled';
+  }
+
+  // 底部导航栏切换
+  switchTab(tab: string): void {
+    this.currentTab = tab;
+    switch (tab) {
+      case 'home':
+        this.router.navigate(['/consumer/home']);
+        break;
+      case 'booking':
+        // 当前页面,不需要跳转
+        break;
+      case 'earnings':
+        this.router.navigate(['/consumer/earnings']);
+        break;
+      case 'mall':
+        this.router.navigate(['/consumer/points-mall']);
+        break;
+      case 'profile':
+        this.router.navigate(['/consumer/profile']);
+        break;
+    }
+  }
 }

+ 19 - 3
src/app/consumer/consumer-module.ts

@@ -1,14 +1,30 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
 
 import { ConsumerRoutingModule } from './consumer-routing-module';
-
+import { HomeComponent } from './home/home';
+import { BookingRecycle } from './booking-recycle/booking-recycle';
+import { EarningsComponent } from './earnings/earnings';
+import { PointsMall } from './points-mall/points-mall';
+import { EcoKnowledge } from './eco-knowledge/eco-knowledge';
+import { AiAssistant } from './ai-assistant/ai-assistant';
+import { Profile } from './profile/profile';
 
 @NgModule({
-  declarations: [],
+  declarations: [
+  ],
   imports: [
     CommonModule,
-    ConsumerRoutingModule
+    FormsModule,
+    ConsumerRoutingModule,
+    HomeComponent,
+    BookingRecycle,
+    EarningsComponent,
+    PointsMall,
+    EcoKnowledge,
+    AiAssistant,
+    Profile
   ]
 })
 export class ConsumerModule { }

+ 7 - 4
src/app/consumer/consumer-routing-module.ts

@@ -1,8 +1,8 @@
 import { NgModule } from '@angular/core';
 import { RouterModule, Routes } from '@angular/router';
-import { Home } from './home/home';
+import { HomeComponent } from './home/home';
 import { BookingRecycle } from './booking-recycle/booking-recycle';
-import { Earnings } from './earnings/earnings';
+import { EarningsComponent } from './earnings/earnings';
 import { PointsMall } from './points-mall/points-mall';
 import { EcoKnowledge } from './eco-knowledge/eco-knowledge';
 import { AiAssistant } from './ai-assistant/ai-assistant';
@@ -10,11 +10,14 @@ import { Profile } from './profile/profile';
 
 const routes: Routes = [
   { path: '', redirectTo: 'home', pathMatch: 'full' },
-  { path: 'home', component: Home },
+  { path: 'home', component: HomeComponent },
+  { path: 'booking', component: BookingRecycle },
   { path: 'booking-recycle', component: BookingRecycle },
-  { path: 'earnings', component: Earnings },
+  { path: 'earnings', component: EarningsComponent },
+  { path: 'mall', component: PointsMall },
   { path: 'points-mall', component: PointsMall },
   { path: 'eco-knowledge', component: EcoKnowledge },
+  { path: 'points-mall/eco-knowledge', component: EcoKnowledge },
   { path: 'ai-assistant', component: AiAssistant },
   { path: 'profile', component: Profile }
 ];

+ 241 - 5
src/app/consumer/earnings/earnings.html

@@ -1,6 +1,242 @@
-<div class="earnings-container">
-  <div class="earnings-header">
-    <h1>收益管理</h1>
+<!-- 顶部标题栏 -->
+<div class="header">
+  <div class="back-btn" (click)="goBack()"><i class="fas fa-arrow-left"></i></div>
+  <div class="header-title">我的收益</div>
+</div>
+
+<div class="container">
+  <!-- 收益总览卡片 -->
+  <div class="earnings-overview">
+    <div class="earnings-stats">
+      <div class="stat-item">
+        <div class="stat-value">¥{{totalCashEarnings.toFixed(2)}}</div>
+        <div class="stat-label">累计现金收益</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">{{totalPointsEarnings}}</div>
+        <div class="stat-label">累计积分收益</div>
+      </div>
+    </div>
+    
+    <div class="carbon-section">
+      <div class="carbon-header">
+        <div class="carbon-title">累计碳减排量</div>
+        <div class="carbon-value">{{totalCarbonReduction}} kg</div>
+      </div>
+      <div class="chart-container">
+        <canvas #carbonChart></canvas>
+      </div>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
-</div>
+  
+  <!-- 收益明细 -->
+  <div class="section">
+    <div class="section-title">
+      <span>收益明细</span>
+      <span style="font-size: 14px; color: #6c757d;">最近30天</span>
+    </div>
+    
+    <!-- 筛选栏 -->
+    <div class="filter-bar">
+      <div 
+        *ngFor="let filter of filterOptions"
+        class="filter-btn" 
+        [class.active]="filter.active"
+        (click)="selectFilter(filter)">
+        {{filter.name}}
+      </div>
+    </div>
+    
+    <div class="date-filter">
+      <input 
+        type="date" 
+        class="date-input" 
+        [(ngModel)]="startDate"
+        (change)="filterByDate()">
+      <span>至</span>
+      <input 
+        type="date" 
+        class="date-input" 
+        [(ngModel)]="endDate"
+        (change)="filterByDate()">
+    </div>
+    
+    <!-- 收益列表 -->
+    <div class="earnings-list" *ngIf="filteredEarnings.length > 0">
+      <div 
+        *ngFor="let earning of filteredEarnings"
+        class="earning-item" 
+        (click)="showOrderDetail(earning)">
+        <div class="earning-info">
+          <div class="earning-icon"><i [class]="earning.icon"></i></div>
+          <div class="earning-details">
+            <div class="earning-category">{{earning.category}}</div>
+            <div class="earning-time">{{earning.time}} | 订单号: {{earning.orderNo}}</div>
+          </div>
+        </div>
+        <div class="earning-amount">
+          <div class="cash-amount">¥{{earning.cashAmount.toFixed(2)}}</div>
+          <div class="points-amount">+{{earning.pointsAmount}}积分</div>
+        </div>
+      </div>
+    </div>
+    
+    <!-- 空状态 -->
+    <div class="empty-state" *ngIf="filteredEarnings.length === 0">
+      <div class="empty-icon"><i class="fas fa-inbox"></i></div>
+      <div>暂无收益记录</div>
+    </div>
+  </div>
+  
+  <!-- 收益管理功能区 -->
+  <div class="section">
+    <div class="section-title">收益管理</div>
+    <div class="action-buttons">
+      <div class="action-btn" (click)="showWithdrawModal()">
+        <i class="fas fa-money-bill-wave"></i>
+        <div>提现</div>
+      </div>
+      <div class="action-btn" (click)="goToMall()">
+        <i class="fas fa-shopping-cart"></i>
+        <div>积分兑换</div>
+      </div>
+      <div class="action-btn" (click)="showDonationModal()">
+        <i class="fas fa-hand-holding-heart"></i>
+        <div>公益捐赠</div>
+      </div>
+      <div class="action-btn" (click)="exportBill()">
+        <i class="fas fa-file-export"></i>
+        <div>导出账单</div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- 提现模态框 -->
+<div class="modal" [style.display]="showWithdraw ? 'flex' : 'none'">
+  <div class="modal-content">
+    <div class="modal-title">提现到账</div>
+    <p style="margin-bottom: 15px; color: #6c757d;">选择提现方式,预计1-3个工作日到账</p>
+    
+    <div class="withdraw-options">
+      <div 
+        *ngFor="let option of withdrawOptions"
+        class="withdraw-option" 
+        [class.active]="option.active"
+        (click)="selectWithdrawOption(option)">
+        <div class="withdraw-icon"><i [class]="option.icon"></i></div>
+        <div>{{option.name}}</div>
+      </div>
+    </div>
+    
+    <div style="margin: 15px 0;">
+      <input 
+        type="number" 
+        placeholder="输入提现金额" 
+        [(ngModel)]="withdrawAmount"
+        style="width: 100%; padding: 12px 15px; border: 1px solid #e9ecef; border-radius: 8px; font-size: 16px;">
+      <div style="text-align: left; font-size: 12px; color: #6c757d; margin-top: 5px;">
+        可提现金额: ¥{{totalCashEarnings.toFixed(2)}}
+      </div>
+    </div>
+    
+    <div class="modal-buttons">
+      <button class="modal-btn cancel" (click)="closeModal('withdraw')">取消</button>
+      <button class="modal-btn confirm" (click)="confirmWithdraw()">确认提现</button>
+    </div>
+  </div>
+</div>
+
+<!-- 捐赠模态框 -->
+<div class="modal" [style.display]="showDonation ? 'flex' : 'none'">
+  <div class="modal-content">
+    <div class="modal-title">公益捐赠</div>
+    <p style="margin-bottom: 15px; color: #6c757d;">选择您想支持的环保公益项目</p>
+    
+    <div style="text-align: left; margin-bottom: 15px;">
+      <div 
+        *ngFor="let project of donationProjects"
+        style="padding: 12px; background: #f8f9fa; border-radius: 8px; margin-bottom: 10px; cursor: pointer;"
+        [style.border]="selectedProject?.id === project.id ? '2px solid #2e7d32' : '1px solid #e9ecef'"
+        (click)="selectDonationProject(project)">
+        <div style="font-weight: 500; margin-bottom: 5px;">{{project.name}}</div>
+        <div style="font-size: 12px; color: #6c757d;">{{project.description}}</div>
+      </div>
+    </div>
+    
+    <div style="margin: 15px 0;">
+      <input 
+        type="number" 
+        placeholder="输入捐赠金额" 
+        [(ngModel)]="donationAmount"
+        style="width: 100%; padding: 12px 15px; border: 1px solid #e9ecef; border-radius: 8px; font-size: 16px;">
+    </div>
+    
+    <div class="modal-buttons">
+      <button class="modal-btn cancel" (click)="closeModal('donation')">取消</button>
+      <button class="modal-btn confirm" (click)="confirmDonation()">确认捐赠</button>
+    </div>
+  </div>
+</div>
+
+<!-- 订单详情模态框 -->
+<div class="modal" [style.display]="showOrderDetailModal ? 'flex' : 'none'">
+  <div class="modal-content">
+    <div class="modal-title">订单详情</div>
+    <div style="text-align: left;" *ngIf="selectedOrder">
+      <div style="margin-bottom: 15px;">
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">品类:</span>
+          <span>{{selectedOrder.category}}</span>
+        </div>
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">时间:</span>
+          <span>{{selectedOrder.time}}</span>
+        </div>
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">订单号:</span>
+          <span>{{selectedOrder.orderNo}}</span>
+        </div>
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">重量:</span>
+          <span>{{selectedOrder.weight}}</span>
+        </div>
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">单价:</span>
+          <span>{{selectedOrder.price}}</span>
+        </div>
+      </div>
+      
+      <div style="background: #f8f9fa; padding: 12px; border-radius: 8px; margin-bottom: 15px;">
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">现金收益:</span>
+          <span style="color: #2e7d32; font-weight: 600;">¥{{selectedOrder.cashAmount.toFixed(2)}}</span>
+        </div>
+        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
+          <span style="color: #6c757d;">积分收益:</span>
+          <span style="color: #ff9800; font-weight: 600;">{{selectedOrder.pointsAmount}}积分</span>
+        </div>
+        <div style="display: flex; justify-content: space-between;">
+          <span style="color: #6c757d;">碳减排:</span>
+          <span style="color: #1abc9c; font-weight: 600;">{{selectedOrder.carbonReduction}}kg</span>
+        </div>
+      </div>
+      
+      <div style="margin-bottom: 15px;">
+        <div style="color: #6c757d; margin-bottom: 5px;">回收地址:</div>
+        <div>{{selectedOrder.address}}</div>
+      </div>
+      
+      <div>
+        <div style="color: #6c757d; margin-bottom: 5px;">回收员:</div>
+        <div>{{selectedOrder.collector}}</div>
+      </div>
+    </div>
+    <div class="modal-buttons">
+      <button class="modal-btn confirm" (click)="closeModal('orderDetail')">关闭</button>
+    </div>
+  </div>
+</div>
+
+<!-- 底部导航栏 -->
+<app-bottom-nav [activeTab]="'earnings'"></app-bottom-nav>

+ 491 - 0
src/app/consumer/earnings/earnings.scss

@@ -0,0 +1,491 @@
+// 全局样式重置
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+// 顶部标题栏
+.header {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  height: 60px;
+  background: linear-gradient(135deg, #2e7d32, #4caf50);
+  color: white;
+  display: flex;
+  align-items: center;
+  padding: 0 20px;
+  z-index: 1000;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+
+  .back-btn {
+    font-size: 20px;
+    cursor: pointer;
+    padding: 8px;
+    border-radius: 50%;
+    transition: background-color 0.3s;
+
+    &:hover {
+      background-color: rgba(255, 255, 255, 0.1);
+    }
+  }
+
+  .header-title {
+    flex: 1;
+    text-align: center;
+    font-size: 18px;
+    font-weight: 600;
+    margin-right: 36px; // 平衡返回按钮的宽度
+  }
+}
+
+// 主容器
+.container {
+  padding: 80px 20px 100px; // 顶部留出header空间,底部留出导航栏空间
+  background: #f5f5f5;
+  min-height: 100vh;
+}
+
+// 收益总览卡片
+.earnings-overview {
+  background: white;
+  border-radius: 15px;
+  padding: 20px;
+  margin-bottom: 20px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+
+  .earnings-stats {
+    display: flex;
+    justify-content: space-around;
+    margin-bottom: 25px;
+
+    .stat-item {
+      text-align: center;
+
+      .stat-value {
+        font-size: 28px;
+        font-weight: bold;
+        color: #2e7d32;
+        margin-bottom: 5px;
+      }
+
+      .stat-label {
+        font-size: 14px;
+        color: #6c757d;
+      }
+    }
+  }
+
+  .carbon-section {
+    border-top: 1px solid #e9ecef;
+    padding-top: 20px;
+
+    .carbon-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+
+      .carbon-title {
+        font-size: 16px;
+        color: #333;
+      }
+
+      .carbon-value {
+        font-size: 20px;
+        font-weight: bold;
+        color: #1abc9c;
+      }
+    }
+
+    .chart-container {
+      height: 200px;
+      position: relative;
+    }
+  }
+}
+
+// 通用区块样式
+.section {
+  background: white;
+  border-radius: 15px;
+  padding: 20px;
+  margin-bottom: 20px;
+  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
+
+  .section-title {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333;
+    margin-bottom: 20px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+  }
+}
+
+// 筛选栏
+.filter-bar {
+  display: flex;
+  gap: 10px;
+  margin-bottom: 15px;
+  overflow-x: auto;
+
+  .filter-btn {
+    padding: 8px 16px;
+    background: #f8f9fa;
+    border: 1px solid #e9ecef;
+    border-radius: 20px;
+    font-size: 14px;
+    color: #6c757d;
+    cursor: pointer;
+    white-space: nowrap;
+    transition: all 0.3s;
+
+    &.active {
+      background: #2e7d32;
+      color: white;
+      border-color: #2e7d32;
+    }
+
+    &:hover:not(.active) {
+      background: #e9ecef;
+    }
+  }
+}
+
+// 日期筛选
+.date-filter {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-bottom: 20px;
+
+  .date-input {
+    flex: 1;
+    padding: 10px 12px;
+    border: 1px solid #e9ecef;
+    border-radius: 8px;
+    font-size: 14px;
+  }
+
+  span {
+    color: #6c757d;
+    font-size: 14px;
+  }
+}
+
+// 收益列表
+.earnings-list {
+  .earning-item {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 15px 0;
+    border-bottom: 1px solid #f0f0f0;
+    cursor: pointer;
+    transition: background-color 0.3s;
+
+    &:hover {
+      background-color: #f8f9fa;
+      margin: 0 -20px;
+      padding-left: 20px;
+      padding-right: 20px;
+    }
+
+    &:last-child {
+      border-bottom: none;
+    }
+
+    .earning-info {
+      display: flex;
+      align-items: center;
+      flex: 1;
+
+      .earning-icon {
+        width: 40px;
+        height: 40px;
+        background: #e8f5e8;
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin-right: 15px;
+        color: #2e7d32;
+        font-size: 18px;
+      }
+
+      .earning-details {
+        .earning-category {
+          font-size: 16px;
+          font-weight: 500;
+          color: #333;
+          margin-bottom: 4px;
+        }
+
+        .earning-time {
+          font-size: 12px;
+          color: #6c757d;
+        }
+      }
+    }
+
+    .earning-amount {
+      text-align: right;
+
+      .cash-amount {
+        font-size: 16px;
+        font-weight: 600;
+        color: #2e7d32;
+        margin-bottom: 2px;
+      }
+
+      .points-amount {
+        font-size: 12px;
+        color: #ff9800;
+      }
+    }
+  }
+}
+
+// 空状态
+.empty-state {
+  text-align: center;
+  padding: 40px 20px;
+  color: #6c757d;
+
+  .empty-icon {
+    font-size: 48px;
+    margin-bottom: 15px;
+    opacity: 0.5;
+  }
+}
+
+// 功能按钮区
+.action-buttons {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 15px;
+
+  .action-btn {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 20px;
+    background: #f8f9fa;
+    border-radius: 12px;
+    cursor: pointer;
+    transition: all 0.3s;
+    border: 1px solid #e9ecef;
+
+    &:hover {
+      background: #e9ecef;
+      transform: translateY(-2px);
+      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+    }
+
+    i {
+      font-size: 24px;
+      color: #2e7d32;
+      margin-bottom: 8px;
+    }
+
+    div {
+      font-size: 14px;
+      color: #333;
+      font-weight: 500;
+    }
+  }
+}
+
+// 模态框样式
+.modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 2000;
+  padding: 20px;
+
+  .modal-content {
+    background: white;
+    border-radius: 15px;
+    padding: 25px;
+    width: 100%;
+    max-width: 400px;
+    max-height: 80vh;
+    overflow-y: auto;
+
+    .modal-title {
+      font-size: 20px;
+      font-weight: 600;
+      text-align: center;
+      margin-bottom: 20px;
+      color: #333;
+    }
+
+    .modal-buttons {
+      display: flex;
+      gap: 15px;
+      margin-top: 25px;
+
+      .modal-btn {
+        flex: 1;
+        padding: 12px 20px;
+        border: none;
+        border-radius: 8px;
+        font-size: 16px;
+        font-weight: 500;
+        cursor: pointer;
+        transition: all 0.3s;
+
+        &.cancel {
+          background: #f8f9fa;
+          color: #6c757d;
+          border: 1px solid #e9ecef;
+
+          &:hover {
+            background: #e9ecef;
+          }
+        }
+
+        &.confirm {
+          background: #2e7d32;
+          color: white;
+
+          &:hover {
+            background: #1b5e20;
+          }
+        }
+      }
+    }
+  }
+}
+
+// 提现选项
+.withdraw-options {
+  display: flex;
+  gap: 15px;
+  margin-bottom: 20px;
+
+  .withdraw-option {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    padding: 15px;
+    border: 2px solid #e9ecef;
+    border-radius: 12px;
+    cursor: pointer;
+    transition: all 0.3s;
+
+    &.active {
+      border-color: #2e7d32;
+      background: #e8f5e8;
+    }
+
+    .withdraw-icon {
+      font-size: 24px;
+      color: #2e7d32;
+      margin-bottom: 8px;
+    }
+
+    div {
+      font-size: 14px;
+      color: #333;
+    }
+  }
+}
+
+// 底部导航栏
+.bottom-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: white;
+  display: flex;
+  padding: 10px 0 20px;
+  box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
+  z-index: 999;
+  
+  .nav-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    
+    &.active {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: linear-gradient(135deg, #4caf50, #66bb6a);
+        color: white;
+        transform: scale(1.1);
+      }
+    }
+    
+    .nav-icon {
+      width: 35px;
+      height: 35px;
+      background: #f8f9fa;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 5px;
+      transition: all 0.3s ease;
+      
+      i {
+        font-size: 16px;
+      }
+    }
+    
+    div:last-child {
+      font-size: 10px;
+      font-weight: 500;
+    }
+    
+    &:hover:not(.active) {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: #f1f8e9;
+        transform: scale(1.05);
+      }
+    }
+  }
+}
+
+// 响应式设计
+@media (max-width: 768px) {
+  .container {
+    padding: 80px 15px 100px;
+  }
+
+  .earnings-overview .earnings-stats {
+    flex-direction: column;
+    gap: 20px;
+  }
+
+  .action-buttons {
+    grid-template-columns: 1fr;
+  }
+
+  .modal {
+    padding: 15px;
+
+    .modal-content {
+      padding: 20px;
+    }
+  }
+}

+ 458 - 6
src/app/consumer/earnings/earnings.ts

@@ -1,13 +1,465 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, ViewChild, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
+import { Router } from '@angular/router';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
+import { Chart, ChartConfiguration, registerables } from 'chart.js';
+
+// 注册Chart.js组件
+Chart.register(...registerables);
+
+// 数据接口定义
+interface EarningRecord {
+  id: string;
+  category: string;
+  time: string;
+  orderNo: string;
+  cashAmount: number;
+  pointsAmount: number;
+  carbonReduction: number;
+  icon: string;
+  weight?: string;
+  price?: string;
+  address?: string;
+  collector?: string;
+}
+
+interface FilterOption {
+  id: string;
+  name: string;
+  active: boolean;
+}
+
+interface WithdrawOption {
+  id: string;
+  name: string;
+  icon: string;
+  active: boolean;
+}
+
+interface DonationProject {
+  id: string;
+  name: string;
+  description: string;
+}
 
 @Component({
   selector: 'app-earnings',
-  imports: [CommonModule, RouterModule],
+  standalone: true,
+  imports: [CommonModule, FormsModule, BottomNavComponent],
   templateUrl: './earnings.html',
-  styleUrl: './earnings.scss'
+  styleUrls: ['./earnings.scss']
 })
-export class EarningsComponent {
-  constructor() {}
+export class EarningsComponent implements OnInit, AfterViewInit {
+  @ViewChild('carbonChart') carbonChartRef!: ElementRef<HTMLCanvasElement>;
+  
+  // 当前选中的导航标签
+  currentTab = 'earnings';
+  
+  // 收益统计数据
+  totalCashEarnings = 1256.80;
+  totalPointsEarnings = 8420;
+  totalCarbonReduction = 125.6;
+  
+  // 筛选选项
+  filterOptions: FilterOption[] = [
+    { id: 'all', name: '全部', active: true },
+    { id: 'cash', name: '现金收益', active: false },
+    { id: 'points', name: '积分收益', active: false },
+    { id: 'carbon', name: '碳减排', active: false }
+  ];
+  
+  // 日期筛选
+  startDate = '';
+  endDate = '';
+  
+  // 收益记录数据
+  earningsData: EarningRecord[] = [
+    {
+      id: '1',
+      category: '废纸回收',
+      time: '2024-01-15 14:30',
+      orderNo: 'RC202401150001',
+      cashAmount: 25.60,
+      pointsAmount: 128,
+      carbonReduction: 2.5,
+      icon: 'fas fa-newspaper',
+      weight: '5.2kg',
+      price: '¥4.92/kg',
+      address: '北京市朝阳区建国路88号',
+      collector: '张师傅'
+    },
+    {
+      id: '2',
+      category: '塑料瓶回收',
+      time: '2024-01-14 10:15',
+      orderNo: 'RC202401140002',
+      cashAmount: 18.40,
+      pointsAmount: 92,
+      carbonReduction: 1.8,
+      icon: 'fas fa-wine-bottle',
+      weight: '3.7kg',
+      price: '¥4.97/kg',
+      address: '北京市朝阳区建国路88号',
+      collector: '李师傅'
+    },
+    {
+      id: '3',
+      category: '金属回收',
+      time: '2024-01-13 16:45',
+      orderNo: 'RC202401130003',
+      cashAmount: 45.20,
+      pointsAmount: 226,
+      carbonReduction: 4.5,
+      icon: 'fas fa-cog',
+      weight: '2.8kg',
+      price: '¥16.14/kg',
+      address: '北京市朝阳区建国路88号',
+      collector: '王师傅'
+    },
+    {
+      id: '4',
+      category: '电子设备回收',
+      time: '2024-01-12 09:20',
+      orderNo: 'RC202401120004',
+      cashAmount: 120.00,
+      pointsAmount: 600,
+      carbonReduction: 12.0,
+      icon: 'fas fa-mobile-alt',
+      weight: '1.5kg',
+      price: '¥80.00/kg',
+      address: '北京市朝阳区建国路88号',
+      collector: '赵师傅'
+    },
+    {
+      id: '5',
+      category: '纺织品回收',
+      time: '2024-01-11 13:10',
+      orderNo: 'RC202401110005',
+      cashAmount: 32.80,
+      pointsAmount: 164,
+      carbonReduction: 3.3,
+      icon: 'fas fa-tshirt',
+      weight: '4.1kg',
+      price: '¥8.00/kg',
+      address: '北京市朝阳区建国路88号',
+      collector: '孙师傅'
+    }
+  ];
+  
+  // 筛选后的收益数据
+  filteredEarnings: EarningRecord[] = [];
+  
+  // 模态框显示状态
+  showWithdraw = false;
+  showDonation = false;
+  showOrderDetailModal = false;
+  
+  // 提现相关
+  withdrawOptions: WithdrawOption[] = [
+    { id: 'wechat', name: '微信', icon: 'fab fa-weixin', active: true },
+    { id: 'alipay', name: '支付宝', icon: 'fab fa-alipay', active: false },
+    { id: 'bank', name: '银行卡', icon: 'fas fa-credit-card', active: false }
+  ];
+  withdrawAmount = 0;
+  
+  // 捐赠相关
+  donationProjects: DonationProject[] = [
+    {
+      id: '1',
+      name: '绿色地球计划',
+      description: '支持全球环保项目,减少碳排放'
+    },
+    {
+      id: '2',
+      name: '海洋清洁行动',
+      description: '清理海洋垃圾,保护海洋生态'
+    },
+    {
+      id: '3',
+      name: '森林保护基金',
+      description: '保护森林资源,维护生态平衡'
+    }
+  ];
+  selectedProject: DonationProject | null = null;
+  donationAmount = 0;
+  
+  // 选中的订单详情
+  selectedOrder: EarningRecord | null = null;
+  
+  // Chart.js实例
+  carbonChart: Chart | null = null;
+
+  constructor(private router: Router) {}
+
+  ngOnInit() {
+    this.initializeData();
+  }
+
+  ngAfterViewInit() {
+    this.initCarbonChart();
+  }
+
+  // 初始化数据
+  initializeData() {
+    this.filteredEarnings = [...this.earningsData];
+    
+    // 设置默认日期范围(最近30天)
+    const today = new Date();
+    const thirtyDaysAgo = new Date(today.getTime() - 30 * 24 * 60 * 60 * 1000);
+    
+    this.endDate = today.toISOString().split('T')[0];
+    this.startDate = thirtyDaysAgo.toISOString().split('T')[0];
+  }
+
+  // 初始化碳减排图表
+  initCarbonChart() {
+    if (!this.carbonChartRef?.nativeElement) return;
+
+    const ctx = this.carbonChartRef.nativeElement.getContext('2d');
+    if (!ctx) return;
+
+    // 生成最近7天的碳减排数据
+    const labels = [];
+    const data = [];
+    const today = new Date();
+    
+    for (let i = 6; i >= 0; i--) {
+      const date = new Date(today.getTime() - i * 24 * 60 * 60 * 1000);
+      labels.push(`${date.getMonth() + 1}/${date.getDate()}`);
+      data.push(Math.random() * 20 + 5); // 模拟数据
+    }
+
+    const config: ChartConfiguration = {
+      type: 'line',
+      data: {
+        labels: labels,
+        datasets: [{
+          label: '碳减排量 (kg)',
+          data: data,
+          borderColor: '#1abc9c',
+          backgroundColor: 'rgba(26, 188, 156, 0.1)',
+          borderWidth: 3,
+          fill: true,
+          tension: 0.4,
+          pointBackgroundColor: '#1abc9c',
+          pointBorderColor: '#ffffff',
+          pointBorderWidth: 2,
+          pointRadius: 6
+        }]
+      },
+      options: {
+        responsive: true,
+        maintainAspectRatio: false,
+        plugins: {
+          legend: {
+            display: false
+          }
+        },
+        scales: {
+          x: {
+            grid: {
+              display: false
+            },
+            ticks: {
+              color: '#6c757d',
+              font: {
+                size: 12
+              }
+            }
+          },
+          y: {
+            grid: {
+              color: '#f0f0f0'
+            },
+            ticks: {
+              color: '#6c757d',
+              font: {
+                size: 12
+              }
+            }
+          }
+        }
+      }
+    };
+
+    this.carbonChart = new Chart(ctx, config);
+  }
+
+  // 返回上一页
+  goBack() {
+    this.router.navigate(['/consumer/home']);
+  }
+
+  // 切换底部导航
+  switchTab(tab: string) {
+    this.currentTab = tab;
+    
+    switch (tab) {
+      case 'home':
+        this.router.navigate(['/consumer/home']);
+        break;
+      case 'booking':
+        this.router.navigate(['/consumer/booking-recycle']);
+        break;
+      case 'earnings':
+        // 当前页面,不需要跳转
+        break;
+      case 'mall':
+        this.router.navigate(['/consumer/points-mall']);
+        break;
+      case 'profile':
+        this.router.navigate(['/consumer/profile']);
+        break;
+    }
+  }
+
+  // 选择筛选条件
+  selectFilter(selectedFilter: FilterOption) {
+    this.filterOptions.forEach(filter => {
+      filter.active = filter.id === selectedFilter.id;
+    });
+    
+    this.applyFilter();
+  }
+
+  // 应用筛选条件
+  applyFilter() {
+    const activeFilter = this.filterOptions.find(f => f.active);
+    if (!activeFilter) return;
+
+    switch (activeFilter.id) {
+      case 'all':
+        this.filteredEarnings = [...this.earningsData];
+        break;
+      case 'cash':
+        this.filteredEarnings = this.earningsData.filter(e => e.cashAmount > 0);
+        break;
+      case 'points':
+        this.filteredEarnings = this.earningsData.filter(e => e.pointsAmount > 0);
+        break;
+      case 'carbon':
+        this.filteredEarnings = this.earningsData.filter(e => e.carbonReduction > 0);
+        break;
+    }
+  }
+
+  // 按日期筛选
+  filterByDate() {
+    if (!this.startDate || !this.endDate) return;
+
+    const start = new Date(this.startDate);
+    const end = new Date(this.endDate);
+    
+    this.filteredEarnings = this.earningsData.filter(earning => {
+      const earningDate = new Date(earning.time);
+      return earningDate >= start && earningDate <= end;
+    });
+  }
+
+  // 显示订单详情
+  showOrderDetail(earning: EarningRecord) {
+    this.selectedOrder = earning;
+    this.showOrderDetailModal = true;
+  }
+
+  // 显示提现模态框
+  showWithdrawModal() {
+    this.showWithdraw = true;
+  }
+
+  // 显示捐赠模态框
+  showDonationModal() {
+    this.showDonation = true;
+  }
+
+  // 选择提现方式
+  selectWithdrawOption(selectedOption: WithdrawOption) {
+    this.withdrawOptions.forEach(option => {
+      option.active = option.id === selectedOption.id;
+    });
+  }
+
+  // 选择捐赠项目
+  selectDonationProject(project: DonationProject) {
+    this.selectedProject = project;
+  }
+
+  // 确认提现
+  confirmWithdraw() {
+    if (this.withdrawAmount <= 0) {
+      alert('请输入有效的提现金额');
+      return;
+    }
+    
+    if (this.withdrawAmount > this.totalCashEarnings) {
+      alert('提现金额不能超过可用余额');
+      return;
+    }
+
+    const selectedOption = this.withdrawOptions.find(o => o.active);
+    console.log(`提现 ¥${this.withdrawAmount} 到 ${selectedOption?.name}`);
+    
+    // 这里应该调用实际的提现API
+    alert(`提现申请已提交,将通过${selectedOption?.name}到账`);
+    this.closeModal('withdraw');
+  }
+
+  // 确认捐赠
+  confirmDonation() {
+    if (!this.selectedProject) {
+      alert('请选择捐赠项目');
+      return;
+    }
+    
+    if (this.donationAmount <= 0) {
+      alert('请输入有效的捐赠金额');
+      return;
+    }
+
+    console.log(`捐赠 ¥${this.donationAmount} 到 ${this.selectedProject.name}`);
+    
+    // 这里应该调用实际的捐赠API
+    alert(`感谢您的爱心捐赠!已向${this.selectedProject.name}捐赠 ¥${this.donationAmount}`);
+    this.closeModal('donation');
+  }
+
+  // 关闭模态框
+  closeModal(type: string) {
+    switch (type) {
+      case 'withdraw':
+        this.showWithdraw = false;
+        this.withdrawAmount = 0;
+        break;
+      case 'donation':
+        this.showDonation = false;
+        this.donationAmount = 0;
+        this.selectedProject = null;
+        break;
+      case 'orderDetail':
+        this.showOrderDetailModal = false;
+        this.selectedOrder = null;
+        break;
+    }
+  }
+
+  // 跳转到商城
+  goToMall() {
+    console.log('跳转到积分商城');
+    // 这里应该跳转到实际的商城页面
+  }
+
+  // 导出账单
+  exportBill() {
+    console.log('导出收益账单');
+    // 这里应该实现实际的账单导出功能
+    alert('账单导出功能开发中...');
+  }
+
+  // 组件销毁时清理图表
+  ngOnDestroy() {
+    if (this.carbonChart) {
+      this.carbonChart.destroy();
+    }
+  }
 }

+ 95 - 3
src/app/consumer/eco-knowledge/eco-knowledge.html

@@ -1,6 +1,98 @@
 <div class="eco-knowledge-container">
-  <div class="knowledge-header">
-    <h1>环保知识</h1>
+  <!-- 顶部标题栏 -->
+  <div class="header">
+    <div class="back-btn" (click)="goBack()"><i class="fas fa-arrow-left"></i></div>
+    <div class="header-title">环保知识</div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
+
+  <div class="container">
+    <!-- 搜索栏 -->
+    <div class="search-bar">
+      <i class="fas fa-magnifying-glass"></i>
+      <input [(ngModel)]="searchText" type="text" placeholder="搜索环保知识...">
+    </div>
+
+    <!-- 知识分类导航 -->
+    <div class="section">
+      <div class="knowledge-categories">
+        <div 
+          class="knowledge-category"
+          *ngFor="let cat of categories"
+          [class.active]="cat.active"
+          (click)="selectCategory(cat.id)"
+        >
+          <div class="category-icon"><i [class]="cat.icon"></i></div>
+          <div class="category-name">{{cat.name}}</div>
+        </div>
+      </div>
+
+      <!-- 内容列表 -->
+      <div class="content-list">
+        <div class="content-item" *ngFor="let item of contents" (click)="openContent(item)">
+          <div class="content-image" [ngClass]="item.imageClass">
+            <i [class]="item.icon + ' fa-2x'"></i>
+            <div class="content-tag">{{ item.tag }}</div>
+          </div>
+          <div class="content-details">
+            <div class="content-title">{{ item.title }}</div>
+            <div class="content-desc">{{ item.desc }}</div>
+            <div class="content-meta">
+              <span>{{ item.time }}</span>
+              <div class="content-actions">
+                <div class="action-btn" [class.active]="item.favorited" (click)="$event.stopPropagation(); toggleFavorite(item)">
+                  <i [class]="(item.favorited ? 'fas' : 'far') + ' fa-bookmark'"></i>
+                  <span>收藏</span>
+                </div>
+                <div class="action-btn" [class.active]="item.liked" (click)="$event.stopPropagation(); toggleLike(item)">
+                  <i [class]="(item.liked ? 'fas' : 'far') + ' fa-thumbs-up'"></i>
+                  <span>{{ item.likes }}</span>
+                </div>
+                <div class="action-btn" (click)="$event.stopPropagation()">
+                  <i class="far fa-share-from-square"></i>
+                  <span>分享</span>
+                </div>
+              </div>
+            </div>
+            <div class="learning-progress" *ngIf="item.progress">
+              <span>学习进度</span>
+              <div class="progress-bar">
+                <div class="progress-fill" [style.width.%]="item.progress"></div>
+              </div>
+              <span>{{ item.progress }}%</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 内容详情模态框 -->
+  <div class="modal" [style.display]="showModal ? 'flex' : 'none'">
+    <div class="modal-content">
+      <div class="modal-header">
+        <div class="modal-title">{{ modalTitle }}</div>
+        <div class="close-btn" (click)="closeModal()">
+          <i class="fas fa-xmark"></i>
+        </div>
+      </div>
+      <div class="modal-tag">{{ modalTag }}</div>
+      <div class="modal-image">
+        <i [class]="modalIcon + ' fa-3x'"></i>
+      </div>
+      <div class="modal-content-text">
+        这里展示内容详情,占位文本。可对接后端返回详细文章或视频信息。
+      </div>
+      <div class="modal-actions">
+        <div class="modal-action-buttons">
+          <div class="modal-action-btn"><i class="far fa-bookmark"></i> 收藏</div>
+          <div class="modal-action-btn"><i class="far fa-thumbs-up"></i> 点赞</div>
+          <div class="modal-action-btn"><i class="far fa-share-from-square"></i> 分享</div>
+        </div>
+        <button class="continue-btn" (click)="closeModal()">继续学习</button>
+      </div>
+    </div>
+  </div>
+
+  <!-- 底部统一导航 -->
+  <app-bottom-nav [activeTab]="'mall'"></app-bottom-nav>
 </div>

+ 160 - 0
src/app/consumer/eco-knowledge/eco-knowledge.scss

@@ -0,0 +1,160 @@
+/* 页面基础布局 */
+.eco-knowledge-container {
+  display: flex;
+  flex-direction: column;
+  min-height: 100vh;
+  background: #f7f8fa;
+  color: #1f2a37;
+}
+
+/* 顶部标题栏 */
+.header {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  padding: 14px 16px;
+  background: #fff;
+  box-shadow: 0 1px 8px rgba(0,0,0,0.06);
+  position: sticky;
+  top: 0;
+  z-index: 10;
+}
+.back-btn {
+  width: 36px;
+  height: 36px;
+  display: grid;
+  place-items: center;
+  border-radius: 10px;
+  background: #f0f2f5;
+  color: #374151;
+}
+.header-title {
+  font-size: 18px;
+  font-weight: 600;
+}
+
+.container {
+  padding: 14px 12px 88px;
+}
+
+/* 搜索栏 */
+.search-bar {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  padding: 10px 12px;
+  background: #fff;
+  border-radius: 12px;
+  box-shadow: 0 1px 6px rgba(0,0,0,0.05);
+}
+.search-bar i { color: #6b7280; }
+.search-bar input {
+  flex: 1;
+  border: none;
+  outline: none;
+  font-size: 14px;
+  color: #111827;
+}
+
+.section { margin-top: 14px; }
+
+/* 分类导航 */
+.knowledge-categories {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 12px;
+}
+.knowledge-category {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  gap: 8px;
+  padding: 12px;
+  background: #fff;
+  border-radius: 12px;
+  box-shadow: 0 1px 6px rgba(0,0,0,0.05);
+  cursor: pointer;
+}
+.knowledge-category .category-icon i {
+  color: #10b981;
+}
+.knowledge-category .category-name {
+  font-size: 13px;
+  color: #374151;
+}
+.knowledge-category.active {
+  outline: 2px solid #10b981;
+}
+
+/* 内容列表 */
+.content-list { margin-top: 16px; display: flex; flex-direction: column; gap: 12px; }
+.content-item {
+  display: flex;
+  gap: 12px;
+  background: #fff;
+  border-radius: 14px;
+  box-shadow: 0 1px 6px rgba(0,0,0,0.05);
+  overflow: hidden;
+}
+.content-image {
+  width: 92px;
+  min-width: 92px;
+  height: 92px;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  gap: 6px;
+  background: linear-gradient(135deg, #e6fdf4, #f3fbf7);
+}
+.content-tag {
+  padding: 2px 6px;
+  border-radius: 10px;
+  font-size: 11px;
+  color: #065f46;
+  background: #d1fae5;
+}
+.content-details { flex: 1; padding: 12px 12px 10px 0; }
+.content-title { font-size: 15px; font-weight: 600; }
+.content-desc { font-size: 13px; color: #6b7280; margin-top: 6px; }
+.content-meta { margin-top: 8px; display: flex; align-items: center; justify-content: space-between; }
+.content-actions { display: flex; gap: 10px; }
+.action-btn { display: flex; align-items: center; gap: 6px; font-size: 13px; color: #4b5563; }
+.action-btn i { color: #6b7280; }
+.action-btn.active i, .action-btn.active span { color: #10b981; }
+
+.learning-progress { margin-top: 10px; display: flex; align-items: center; gap: 8px; font-size: 12px; color: #6b7280; }
+.progress-bar { flex: 1; height: 6px; background: #e5e7eb; border-radius: 999px; overflow: hidden; }
+.progress-fill { height: 100%; background: #10b981; }
+
+/* 模态框 */
+.modal {
+  position: fixed;
+  inset: 0;
+  display: none;
+  align-items: center;
+  justify-content: center;
+  background: rgba(0,0,0,0.35);
+  z-index: 40;
+}
+.modal-content {
+  width: calc(100% - 28px);
+  max-width: 560px;
+  background: #fff;
+  border-radius: 16px;
+  box-shadow: 0 10px 30px rgba(0,0,0,0.12);
+  padding: 14px;
+}
+.modal-header { display: flex; align-items: center; justify-content: space-between; }
+.modal-title { font-size: 16px; font-weight: 600; }
+.close-btn { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 8px; background: #f3f4f6; color: #111827; }
+.modal-tag { margin-top: 8px; color: #065f46; background: #d1fae5; display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 12px; }
+.modal-image { margin-top: 12px; display: grid; place-items: center; color: #10b981; }
+.modal-content-text { margin-top: 8px; font-size: 14px; color: #374151; line-height: 1.6; }
+.modal-actions { margin-top: 12px; display: flex; align-items: center; justify-content: space-between; }
+.modal-action-buttons { display: flex; gap: 8px; }
+.modal-action-btn { padding: 8px 10px; border-radius: 10px; background: #f3f4f6; color: #374151; font-size: 13px; }
+.continue-btn { padding: 10px 14px; border: none; border-radius: 10px; background: #10b981; color: #fff; font-size: 14px; }
+
+/* 底部导航占位,避免内容被遮挡 */
+app-bottom-nav { position: fixed; bottom: 0; left: 0; right: 0; }

+ 107 - 4
src/app/consumer/eco-knowledge/eco-knowledge.ts

@@ -1,13 +1,116 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { Router, RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
 
 @Component({
   selector: 'app-eco-knowledge',
-  imports: [CommonModule, RouterModule],
+  standalone: true,
+  imports: [CommonModule, RouterModule, FormsModule, BottomNavComponent],
   templateUrl: './eco-knowledge.html',
   styleUrl: './eco-knowledge.scss'
 })
-export class EcoKnowledgeComponent {
-  constructor() {}
+export class EcoKnowledge {
+  // 顶部导航返回
+  constructor(private router: Router) {}
+
+  goBack(): void {
+    this.router.navigate(['/consumer/points-mall']);
+  }
+
+  // 搜索与分类
+  searchText = '';
+  categories = [
+    { id: 'all', name: '全部', icon: 'fas fa-th-large', active: true },
+    { id: 'ar', name: 'AR分类教程', icon: 'fas fa-cube', active: false },
+    { id: 'policy', name: '政策解读', icon: 'fas fa-file-alt', active: false },
+    { id: 'share', name: '达人分享', icon: 'fas fa-users', active: false },
+    { id: 'ranking', name: '环保榜单', icon: 'fas fa-trophy', active: false }
+  ];
+
+  selectCategory(catId: string): void {
+    this.categories.forEach(c => (c.active = c.id === catId));
+    this.selectedCategory = catId;
+  }
+
+  selectedCategory = 'all';
+
+  // 内容列表(示例数据)
+  contents = [
+    {
+      id: 1,
+      title: 'AR智能分类教程:如何正确区分可回收物与干垃圾',
+      desc: '使用AR功能快速识别各类可回收物品,提高分类准确率,避免错误投放...',
+      tag: 'AR教程',
+      time: '15分钟前',
+      icon: 'fas fa-play-circle',
+      imageClass: 'image-1 video',
+      liked: false,
+      likes: 86,
+      favorited: false
+    },
+    {
+      id: 2,
+      title: '最新环保政策解读:以旧换新补贴标准与申请流程',
+      desc: '了解国家最新出台的以旧换新政策,掌握补贴申请流程,享受政策红利...',
+      tag: '政策解读',
+      time: '1天前',
+      icon: 'fas fa-newspaper',
+      imageClass: 'image-2',
+      liked: false,
+      likes: 142,
+      favorited: false
+    },
+    {
+      id: 3,
+      title: '环保达人分享:我是如何月赚500元回收金的经验技巧',
+      desc: '听听环保达人的经验分享,学习高效回收的小技巧,让废品变废为宝...',
+      tag: '达人分享',
+      time: '3天前',
+      icon: 'fas fa-user',
+      imageClass: 'image-3',
+      liked: false,
+      likes: 328,
+      favorited: false,
+      progress: 75
+    },
+    {
+      id: 4,
+      title: '2023年度环保达人榜单发布,看看谁是最强回收王',
+      desc: '年度环保达人榜单新鲜出炉,学习榜样的回收经验,提升自己的环保贡献...',
+      tag: '环保榜单',
+      time: '1周前',
+      icon: 'fas fa-trophy',
+      imageClass: 'image-4',
+      liked: false,
+      likes: 528,
+      favorited: false
+    }
+  ];
+
+  // 交互方法
+  toggleFavorite(item: any): void {
+    item.favorited = !item.favorited;
+  }
+
+  toggleLike(item: any): void {
+    item.liked = !item.liked;
+    item.likes += item.liked ? 1 : -1;
+  }
+
+  // 模态框
+  showModal = false;
+  modalTitle = '';
+  modalTag = '';
+  modalIcon = '';
+  openContent(item: any): void {
+    this.modalTitle = item.title;
+    this.modalTag = item.tag;
+    this.modalIcon = item.icon;
+    this.showModal = true;
+  }
+  closeModal(): void {
+    this.showModal = false;
+  }
 }

+ 92 - 5
src/app/consumer/home/home.html

@@ -1,6 +1,93 @@
-<div class="home-container">
-  <div class="home-header">
-    <h1>首页</h1>
+<!-- 顶部状态栏 -->
+<div class="status-bar">
+  <div class="user-level">
+    <div class="level-badge">环保达人 LV.{{ userLevel }}</div>
+    <div class="level-progress">
+      <div class="progress-bar" [style.width.%]="levelProgress"></div>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
-</div>
+  <div class="points-cash">
+    <div>积分: {{ userPoints | number }}</div>
+    <div>现金: ¥{{ userCash | number:'1.2-2' }}</div>
+  </div>
+  <div class="notification-icon" (click)="openNotifications()">
+    <i class="far fa-bell"></i>
+  </div>
+</div>
+
+<!-- 核心功能入口区 -->
+<div class="core-functions">
+  <div class="function-title">核心功能</div>
+  <div class="quick-booking" (click)="quickBooking()">
+    <i class="fas fa-recycle"></i> 一键预约回收
+  </div>
+  <div class="function-buttons">
+    <div class="func-btn" (click)="openARRecognition()">
+      <div class="func-icon"><i class="fas fa-camera"></i></div>
+      <div>AR识废品</div>
+    </div>
+    <div class="func-btn" (click)="findDropPoints()">
+      <div class="func-icon"><i class="fas fa-map-marker-alt"></i></div>
+      <div>自助投递点</div>
+    </div>
+  </div>
+</div>
+
+<!-- 动态信息区 -->
+<div class="dynamic-info">
+  <!-- 附近回收员动态 -->
+  <div class="info-section">
+    <div class="section-title">
+      <h3>附近回收员</h3>
+      <a (click)="viewMoreCollectors()" class="more-link">查看更多</a>
+    </div>
+    <div class="collector-list">
+      <div class="collector-card" *ngFor="let collector of nearbyCollectors">
+        <div class="collector-avatar"><i class="fas fa-user"></i></div>
+        <div class="collector-name">{{ collector.name }}</div>
+        <div class="collector-status">{{ collector.distance }} · {{ collector.status }}</div>
+      </div>
+    </div>
+  </div>
+  
+  <!-- 自助投递点状态 -->
+  <div class="info-section">
+    <div class="section-title">
+      <h3>自助投递点</h3>
+      <a (click)="viewMoreDropPoints()" class="more-link">查看更多</a>
+    </div>
+    <div class="drop-points">
+      <div class="point-card" *ngFor="let point of dropPoints">
+        <div class="point-name">{{ point.name }}</div>
+        <div class="point-distance">{{ point.distance }}</div>
+        <div class="capacity-bar">
+          <div class="capacity-fill" [style.width.%]="point.capacity"></div>
+        </div>
+        <div class="capacity-text">{{ point.capacity }}% 满箱</div>
+      </div>
+    </div>
+  </div>
+  
+  <!-- 环保活动/政策公告轮播 -->
+  <div class="info-section">
+    <div class="section-title">
+      <h3>环保活动</h3>
+      <a (click)="viewMoreActivities()" class="more-link">查看更多</a>
+    </div>
+    <div class="activity-carousel">
+      <div class="activity-card" *ngFor="let activity of activities">
+        <div class="activity-tag">{{ activity.tag }}</div>
+        <div class="activity-title">{{ activity.title }}</div>
+        <div class="activity-desc">{{ activity.description }}</div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- AI助手入口 -->
+<div class="ai-assistant" (click)="openAIAssistant()">
+  <i class="fas fa-robot"></i>
+</div>
+
+<!-- 底部导航栏 -->
+<app-bottom-nav [activeTab]="'home'"></app-bottom-nav>

+ 416 - 424
src/app/consumer/home/home.scss

@@ -1,521 +1,513 @@
-.home-container {
+// 全局重置和基础样式
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+:host {
+  display: block;
+  width: 100%;
   min-height: 100vh;
-  background: #f5f7fa;
-  padding-bottom: 80px; // 为底部导航留空间
+  background: linear-gradient(135deg, #e8f5e8 0%, #f0f8f0 100%);
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+  color: #333;
+  overflow-x: hidden;
 }
 
-// 顶部导航栏
-.top-header {
-  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+// 顶部状态栏
+.status-bar {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 15px 20px;
+  background: linear-gradient(135deg, #2e7d32 0%, #4caf50 100%);
   color: white;
-  padding: 20px;
-  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-
-  .header-content {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    max-width: 1200px;
-    margin: 0 auto;
+  box-shadow: 0 2px 10px rgba(46, 125, 50, 0.3);
+  
+  .user-level {
+    flex: 1;
+    
+    .level-badge {
+      font-size: 14px;
+      font-weight: 600;
+      margin-bottom: 5px;
+    }
+    
+    .level-progress {
+      width: 120px;
+      height: 6px;
+      background: rgba(255, 255, 255, 0.3);
+      border-radius: 3px;
+      overflow: hidden;
+      
+      .progress-bar {
+        height: 100%;
+        background: linear-gradient(90deg, #81c784, #a5d6a7);
+        border-radius: 3px;
+        transition: width 0.3s ease;
+      }
+    }
   }
-
-  .user-info {
+  
+  .points-cash {
     display: flex;
+    flex-direction: column;
     align-items: center;
-    gap: 12px;
-
-    .avatar {
-      width: 48px;
-      height: 48px;
+    font-size: 12px;
+    gap: 2px;
+    
+    div {
       background: rgba(255, 255, 255, 0.2);
-      border-radius: 50%;
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      font-size: 20px;
-      font-weight: bold;
-    }
-
-    .user-details {
-      h3 {
-        margin: 0;
-        font-size: 18px;
-        font-weight: 600;
-      }
-
-      p {
-        margin: 4px 0 0 0;
-        font-size: 14px;
-        opacity: 0.9;
-      }
+      padding: 2px 8px;
+      border-radius: 10px;
+      font-weight: 500;
     }
   }
-
-  .logout-btn {
+  
+  .notification-icon {
+    width: 40px;
+    height: 40px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
     background: rgba(255, 255, 255, 0.2);
-    color: white;
-    border: 1px solid rgba(255, 255, 255, 0.3);
-    padding: 8px 16px;
-    border-radius: 20px;
+    border-radius: 50%;
     cursor: pointer;
     transition: all 0.3s ease;
-
+    
     &:hover {
       background: rgba(255, 255, 255, 0.3);
+      transform: scale(1.1);
+    }
+    
+    i {
+      font-size: 18px;
     }
   }
 }
 
-// 数据概览卡片
-.stats-section {
+// 核心功能入口区
+.core-functions {
   padding: 20px;
-  max-width: 1200px;
-  margin: 0 auto;
-
-  .stats-grid {
-    display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
-    gap: 16px;
+  background: white;
+  margin: 15px 20px;
+  border-radius: 15px;
+  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+  
+  .function-title {
+    font-size: 18px;
+    font-weight: 600;
+    color: #2e7d32;
+    margin-bottom: 15px;
+    text-align: center;
   }
-
-  .stat-card {
-    background: white;
+  
+  .quick-booking {
+    background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%);
+    color: white;
+    padding: 15px 20px;
     border-radius: 12px;
-    padding: 20px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    display: flex;
-    align-items: center;
-    gap: 16px;
-    transition: transform 0.3s ease;
-
+    text-align: center;
+    font-size: 16px;
+    font-weight: 600;
+    cursor: pointer;
+    margin-bottom: 15px;
+    box-shadow: 0 4px 15px rgba(76, 175, 80, 0.3);
+    transition: all 0.3s ease;
+    
     &:hover {
       transform: translateY(-2px);
+      box-shadow: 0 6px 20px rgba(76, 175, 80, 0.4);
     }
-
-    .stat-icon {
-      font-size: 32px;
+    
+    i {
+      margin-right: 8px;
+      font-size: 18px;
     }
-
-    .stat-content {
-      h4 {
-        margin: 0 0 4px 0;
+  }
+  
+  .function-buttons {
+    display: flex;
+    gap: 15px;
+    
+    .func-btn {
+      flex: 1;
+      background: #f8f9fa;
+      border: 2px solid #e9ecef;
+      border-radius: 12px;
+      padding: 15px 10px;
+      text-align: center;
+      cursor: pointer;
+      transition: all 0.3s ease;
+      
+      &:hover {
+        border-color: #4caf50;
+        background: #f1f8e9;
+        transform: translateY(-2px);
+      }
+      
+      .func-icon {
+        width: 40px;
+        height: 40px;
+        background: linear-gradient(135deg, #4caf50, #66bb6a);
+        border-radius: 50%;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        margin: 0 auto 8px;
+        color: white;
+        
+        i {
+          font-size: 18px;
+        }
+      }
+      
+      div:last-child {
+        font-size: 12px;
         color: #666;
-        font-size: 14px;
         font-weight: 500;
       }
-
-      .stat-value {
-        margin: 0;
-        font-size: 24px;
-        font-weight: bold;
-        color: #2d3748;
-      }
-    }
-
-    &.earnings .stat-value {
-      color: #4CAF50;
-    }
-
-    &.points .stat-value {
-      color: #2196F3;
-    }
-
-    &.monthly .stat-value {
-      color: #FF9800;
     }
   }
 }
 
-// 快捷功能
-.quick-actions-section {
-  padding: 0 20px 20px;
-  max-width: 1200px;
-  margin: 0 auto;
-
-  h2 {
-    margin: 0 0 16px 0;
-    color: #2d3748;
-    font-size: 20px;
-    font-weight: 600;
-  }
-
-  .actions-grid {
-    display: grid;
-    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
-    gap: 16px;
-  }
-
-  .action-card {
+// 动态信息区
+.dynamic-info {
+  padding: 0 20px 100px;
+  
+  .info-section {
     background: white;
-    border-radius: 12px;
+    border-radius: 15px;
     padding: 20px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    display: flex;
-    align-items: center;
-    gap: 16px;
-    text-decoration: none;
-    color: inherit;
-    transition: all 0.3s ease;
-    border-left: 4px solid #e2e8f0;
-
-    &:hover {
-      transform: translateY(-2px);
-      box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
-    }
-
-    .action-icon {
-      font-size: 32px;
-    }
-
-    .action-content {
-      flex: 1;
-
-      h4 {
-        margin: 0 0 4px 0;
-        color: #2d3748;
+    margin-bottom: 15px;
+    box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08);
+    
+    .section-title {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      margin-bottom: 15px;
+      
+      h3 {
         font-size: 16px;
         font-weight: 600;
+        color: #2e7d32;
       }
-
-      p {
-        margin: 0;
-        color: #718096;
-        font-size: 14px;
+      
+      .more-link {
+        font-size: 12px;
+        color: #4caf50;
+        cursor: pointer;
+        text-decoration: none;
+        
+        &:hover {
+          text-decoration: underline;
+        }
       }
     }
-
-    .action-arrow {
-      font-size: 20px;
-      color: #a0aec0;
-    }
-  }
-}
-
-// 最近订单
-.recent-orders-section {
-  padding: 0 20px 20px;
-  max-width: 1200px;
-  margin: 0 auto;
-
-  .section-header {
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-    margin-bottom: 16px;
-
-    h2 {
-      margin: 0;
-      color: #2d3748;
-      font-size: 20px;
-      font-weight: 600;
-    }
-
-    .view-all-link {
-      color: #667eea;
-      text-decoration: none;
-      font-size: 14px;
-      font-weight: 500;
-
-      &:hover {
-        text-decoration: underline;
+    
+    // 附近回收员样式
+    .collector-list {
+      display: flex;
+      gap: 10px;
+      overflow-x: auto;
+      padding-bottom: 5px;
+      
+      .collector-card {
+        min-width: 80px;
+        text-align: center;
+        
+        .collector-avatar {
+          width: 50px;
+          height: 50px;
+          background: linear-gradient(135deg, #4caf50, #66bb6a);
+          border-radius: 50%;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          margin: 0 auto 8px;
+          color: white;
+          
+          i {
+            font-size: 20px;
+          }
+        }
+        
+        .collector-name {
+          font-size: 12px;
+          font-weight: 500;
+          margin-bottom: 4px;
+        }
+        
+        .collector-status {
+          font-size: 10px;
+          color: #666;
+        }
       }
     }
-  }
-
-  .orders-list {
-    display: flex;
-    flex-direction: column;
-    gap: 12px;
-  }
-
-  .order-card {
-    background: white;
-    border-radius: 12px;
-    padding: 16px;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-    display: flex;
-    justify-content: space-between;
-    align-items: center;
-
-    .order-info {
-      flex: 1;
-
-      .order-header {
+    
+    // 自助投递点样式
+    .drop-points {
+      .point-card {
         display: flex;
         align-items: center;
-        gap: 12px;
-        margin-bottom: 8px;
-
-        .order-id {
-          font-weight: 600;
-          color: #2d3748;
+        padding: 10px 0;
+        border-bottom: 1px solid #f0f0f0;
+        
+        &:last-child {
+          border-bottom: none;
         }
-
-        .order-status {
-          padding: 4px 8px;
-          border-radius: 12px;
-          font-size: 12px;
+        
+        .point-name {
+          flex: 1;
+          font-size: 14px;
           font-weight: 500;
-
-          &.status-pending {
-            background: #fff3cd;
-            color: #856404;
-          }
-
-          &.status-processing {
-            background: #d1ecf1;
-            color: #0c5460;
-          }
-
-          &.status-completed {
-            background: #d4edda;
-            color: #155724;
-          }
-
-          &.status-cancelled {
-            background: #f8d7da;
-            color: #721c24;
+        }
+        
+        .point-distance {
+          font-size: 12px;
+          color: #666;
+          margin-right: 15px;
+        }
+        
+        .capacity-bar {
+          width: 60px;
+          height: 6px;
+          background: #f0f0f0;
+          border-radius: 3px;
+          overflow: hidden;
+          margin-right: 8px;
+          
+          .capacity-fill {
+            height: 100%;
+            background: linear-gradient(90deg, #4caf50, #66bb6a);
+            border-radius: 3px;
+            transition: width 0.3s ease;
           }
         }
+        
+        .capacity-text {
+          font-size: 10px;
+          color: #666;
+          min-width: 40px;
+        }
       }
-
-      .order-type {
-        margin: 0 0 4px 0;
-        color: #4a5568;
-        font-size: 14px;
-      }
-
-      .order-date {
-        margin: 0;
-        color: #718096;
-        font-size: 12px;
-      }
-    }
-
-    .order-amount {
-      .amount {
-        font-size: 18px;
-        font-weight: bold;
-        color: #4CAF50;
-      }
-    }
-  }
-
-  .no-orders {
-    background: white;
-    border-radius: 12px;
-    padding: 40px 20px;
-    text-align: center;
-    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
-
-    .no-orders-icon {
-      font-size: 48px;
-      margin-bottom: 16px;
     }
-
-    p {
-      margin: 0 0 20px 0;
-      color: #718096;
-      font-size: 16px;
-    }
-
-    .create-order-btn {
-      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-      color: white;
-      padding: 12px 24px;
-      border-radius: 8px;
-      text-decoration: none;
-      font-weight: 600;
-      transition: transform 0.3s ease;
-
-      &:hover {
-        transform: translateY(-2px);
+    
+    // 环保活动样式
+    .activity-carousel {
+      .activity-card {
+        border: 1px solid #e9ecef;
+        border-radius: 10px;
+        padding: 15px;
+        margin-bottom: 10px;
+        
+        &:last-child {
+          margin-bottom: 0;
+        }
+        
+        .activity-tag {
+          display: inline-block;
+          background: linear-gradient(135deg, #4caf50, #66bb6a);
+          color: white;
+          padding: 2px 8px;
+          border-radius: 10px;
+          font-size: 10px;
+          margin-bottom: 8px;
+        }
+        
+        .activity-title {
+          font-size: 14px;
+          font-weight: 600;
+          margin-bottom: 5px;
+          color: #333;
+        }
+        
+        .activity-desc {
+          font-size: 12px;
+          color: #666;
+          line-height: 1.4;
+        }
       }
     }
   }
 }
 
-// 环保提示
-.eco-tip-section {
-  padding: 0 20px 20px;
-  max-width: 1200px;
-  margin: 0 auto;
-
-  .eco-tip-card {
-    background: linear-gradient(135deg, #8BC34A 0%, #4CAF50 100%);
-    color: white;
-    border-radius: 12px;
-    padding: 20px;
-    display: flex;
-    align-items: center;
-    gap: 16px;
-
-    .tip-icon {
-      font-size: 32px;
-    }
-
-    .tip-content {
-      h4 {
-        margin: 0 0 8px 0;
-        font-size: 16px;
-        font-weight: 600;
-      }
-
-      p {
-        margin: 0;
-        font-size: 14px;
-        opacity: 0.9;
-        line-height: 1.5;
-      }
-    }
+// AI助手入口
+.ai-assistant {
+  position: fixed;
+  right: 20px;
+  bottom: 100px;
+  width: 60px;
+  height: 60px;
+  background: linear-gradient(135deg, #4caf50 0%, #66bb6a 100%);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: white;
+  cursor: pointer;
+  box-shadow: 0 4px 20px rgba(76, 175, 80, 0.4);
+  transition: all 0.3s ease;
+  z-index: 1000;
+  
+  &:hover {
+    transform: scale(1.1);
+    box-shadow: 0 6px 25px rgba(76, 175, 80, 0.5);
+  }
+  
+  i {
+    font-size: 24px;
   }
 }
 
-// 底部导航
+// 底部导航栏
 .bottom-nav {
   position: fixed;
   bottom: 0;
   left: 0;
   right: 0;
   background: white;
-  border-top: 1px solid #e2e8f0;
   display: flex;
-  justify-content: space-around;
-  padding: 8px 0;
-  box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
-
+  padding: 10px 0 20px;
+  box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
+  z-index: 999;
+  
   .nav-item {
+    flex: 1;
     display: flex;
     flex-direction: column;
     align-items: center;
-    text-decoration: none;
-    color: #a0aec0;
-    transition: color 0.3s ease;
-    padding: 8px;
-
+    cursor: pointer;
+    transition: all 0.3s ease;
+    
     &.active {
-      color: #667eea;
-    }
-
-    &:hover {
-      color: #667eea;
+      color: #4caf50;
+      
+      .nav-icon {
+        background: linear-gradient(135deg, #4caf50, #66bb6a);
+        color: white;
+        transform: scale(1.1);
+      }
     }
-
+    
     .nav-icon {
-      font-size: 20px;
-      margin-bottom: 4px;
+      width: 35px;
+      height: 35px;
+      background: #f8f9fa;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 5px;
+      transition: all 0.3s ease;
+      
+      i {
+        font-size: 16px;
+      }
     }
-
-    .nav-label {
-      font-size: 12px;
+    
+    div:last-child {
+      font-size: 10px;
       font-weight: 500;
     }
+    
+    &:hover:not(.active) {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: #f1f8e9;
+        transform: scale(1.05);
+      }
+    }
   }
 }
 
 // 响应式设计
-@media (max-width: 768px) {
-  .top-header {
-    padding: 16px;
-
-    .user-info {
-      .avatar {
-        width: 40px;
-        height: 40px;
-        font-size: 18px;
-      }
-
-      .user-details {
-        h3 {
-          font-size: 16px;
-        }
-
-        p {
-          font-size: 12px;
-        }
-      }
+@media (max-width: 480px) {
+  .status-bar {
+    padding: 12px 15px;
+    
+    .user-level .level-progress {
+      width: 100px;
     }
-
-    .logout-btn {
-      padding: 6px 12px;
-      font-size: 14px;
+    
+    .points-cash {
+      font-size: 11px;
     }
   }
-
-  .stats-section {
-    padding: 16px;
-
-    .stats-grid {
-      grid-template-columns: 1fr;
-      gap: 12px;
-    }
-
-    .stat-card {
-      padding: 16px;
-
-      .stat-icon {
-        font-size: 28px;
-      }
-
-      .stat-content {
-        .stat-value {
-          font-size: 20px;
+  
+  .core-functions {
+    margin: 10px 15px;
+    padding: 15px;
+    
+    .function-buttons .func-btn {
+      padding: 12px 8px;
+      
+      .func-icon {
+        width: 35px;
+        height: 35px;
+        
+        i {
+          font-size: 16px;
         }
       }
     }
   }
-
-  .quick-actions-section {
-    padding: 0 16px 16px;
-
-    .actions-grid {
-      grid-template-columns: 1fr;
-      gap: 12px;
+  
+  .dynamic-info {
+    padding: 0 15px 100px;
+    
+    .info-section {
+      padding: 15px;
     }
-
-    .action-card {
-      padding: 16px;
-
-      .action-icon {
-        font-size: 28px;
-      }
+  }
+  
+  .ai-assistant {
+    width: 50px;
+    height: 50px;
+    right: 15px;
+    bottom: 90px;
+    
+    i {
+      font-size: 20px;
     }
   }
+}
 
-  .recent-orders-section {
-    padding: 0 16px 16px;
-
-    .order-card {
-      padding: 12px;
-      flex-direction: column;
-      align-items: flex-start;
-      gap: 12px;
-
-      .order-amount {
-        align-self: flex-end;
-      }
-    }
+// 动画效果
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translateY(20px);
   }
+  to {
+    opacity: 1;
+    transform: translateY(0);
+  }
+}
 
-  .eco-tip-section {
-    padding: 0 16px 16px;
+.info-section {
+  animation: fadeInUp 0.6s ease-out;
+}
 
-    .eco-tip-card {
-      padding: 16px;
+// 滚动条样式
+::-webkit-scrollbar {
+  width: 4px;
+  height: 4px;
+}
 
-      .tip-icon {
-        font-size: 28px;
-      }
+::-webkit-scrollbar-track {
+  background: #f1f1f1;
+  border-radius: 2px;
+}
 
-      .tip-content {
-        h4 {
-          font-size: 14px;
-        }
+::-webkit-scrollbar-thumb {
+  background: #4caf50;
+  border-radius: 2px;
+}
 
-        p {
-          font-size: 12px;
-        }
-      }
-    }
-  }
+::-webkit-scrollbar-thumb:hover {
+  background: #2e7d32;
 }

+ 6 - 6
src/app/consumer/home/home.spec.ts

@@ -1,18 +1,18 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { Home } from './home';
+import { HomeComponent } from './home';
 
-describe('Home', () => {
-  let component: Home;
-  let fixture: ComponentFixture<Home>;
+describe('HomeComponent', () => {
+  let component: HomeComponent;
+  let fixture: ComponentFixture<HomeComponent>;
 
   beforeEach(async () => {
     await TestBed.configureTestingModule({
-      imports: [Home]
+      imports: [HomeComponent]
     })
     .compileComponents();
 
-    fixture = TestBed.createComponent(Home);
+    fixture = TestBed.createComponent(HomeComponent);
     component = fixture.componentInstance;
     fixture.detectChanges();
   });

+ 244 - 7
src/app/consumer/home/home.ts

@@ -1,13 +1,250 @@
-import { Component } from '@angular/core';
-import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { Component, OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+import { CommonModule, DecimalPipe } from '@angular/common';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
+
+interface Collector {
+  id: string;
+  name: string;
+  distance: string;
+  status: string;
+}
+
+interface DropPoint {
+  id: string;
+  name: string;
+  distance: string;
+  capacity: number;
+}
+
+interface Activity {
+  id: string;
+  tag: string;
+  title: string;
+  description: string;
+}
 
 @Component({
   selector: 'app-home',
-  imports: [CommonModule, RouterModule],
+  standalone: true,
+  imports: [CommonModule, BottomNavComponent],
   templateUrl: './home.html',
-  styleUrl: './home.scss'
+  styleUrls: ['./home.scss']
 })
-export class HomeComponent {
-  constructor() {}
+export class HomeComponent implements OnInit {
+  // 用户状态数据
+  userLevel: number = 5;
+  levelProgress: number = 68;
+  userPoints: number = 2580;
+  userCash: number = 156.80;
+  
+  // 当前选中的底部导航标签
+  currentTab: string = 'home';
+  
+  // 附近回收员数据
+  nearbyCollectors: Collector[] = [
+    {
+      id: '1',
+      name: '张师傅',
+      distance: '0.5km',
+      status: '在线'
+    },
+    {
+      id: '2',
+      name: '李师傅',
+      distance: '0.8km',
+      status: '忙碌'
+    },
+    {
+      id: '3',
+      name: '王师傅',
+      distance: '1.2km',
+      status: '在线'
+    },
+    {
+      id: '4',
+      name: '赵师傅',
+      distance: '1.5km',
+      status: '在线'
+    }
+  ];
+  
+  // 自助投递点数据
+  dropPoints: DropPoint[] = [
+    {
+      id: '1',
+      name: '万达广场投递点',
+      distance: '0.3km',
+      capacity: 25
+    },
+    {
+      id: '2',
+      name: '社区服务中心',
+      distance: '0.7km',
+      capacity: 68
+    },
+    {
+      id: '3',
+      name: '地铁站投递点',
+      distance: '1.1km',
+      capacity: 92
+    }
+  ];
+  
+  // 环保活动数据
+  activities: Activity[] = [
+    {
+      id: '1',
+      tag: '政策公告',
+      title: '新版垃圾分类标准发布',
+      description: '了解最新的垃圾分类要求,正确投放获得更多积分奖励'
+    },
+    {
+      id: '2',
+      tag: '环保活动',
+      title: '地球日特别活动',
+      description: '参与环保知识竞答,赢取丰厚奖品和现金红包'
+    },
+    {
+      id: '3',
+      tag: '积分兑换',
+      title: '积分商城新品上架',
+      description: '环保购物袋、保温杯等实用商品,积分兑换更优惠'
+    }
+  ];
+
+  constructor(private router: Router) {}
+
+  ngOnInit(): void {
+    // 组件初始化时的逻辑
+    this.loadUserData();
+    this.loadDynamicData();
+  }
+
+  // 加载用户数据
+  private loadUserData(): void {
+    // 模拟从服务获取用户数据
+    // 实际项目中这里会调用用户服务
+    console.log('Loading user data...');
+  }
+
+  // 加载动态数据
+  private loadDynamicData(): void {
+    // 模拟从服务获取动态数据
+    // 实际项目中这里会调用相关服务
+    console.log('Loading dynamic data...');
+  }
+
+  // 打开通知页面
+  openNotifications(): void {
+    console.log('Opening notifications...');
+    // 实际项目中会导航到通知页面
+    // this.router.navigate(['/consumer/notifications']);
+  }
+
+  // 一键预约回收
+  quickBooking(): void {
+    console.log('Quick booking initiated...');
+    // 实际项目中会导航到预约页面或打开预约弹窗
+    this.router.navigate(['/consumer/booking-recycle']);
+  }
+
+  // 打开AR识废品功能
+  openARRecognition(): void {
+    console.log('Opening AR recognition...');
+    // 实际项目中会导航到AR识别页面
+    // this.router.navigate(['/consumer/ar-recognition']);
+  }
+
+  // 查找自助投递点
+  findDropPoints(): void {
+    console.log('Finding drop points...');
+    // 实际项目中会导航到地图页面
+    // this.router.navigate(['/consumer/drop-points']);
+  }
+
+  // 查看更多回收员
+  viewMoreCollectors(): void {
+    console.log('Viewing more collectors...');
+    // 实际项目中会导航到回收员列表页面
+    // this.router.navigate(['/consumer/collectors']);
+  }
+
+  // 查看更多投递点
+  viewMoreDropPoints(): void {
+    console.log('Viewing more drop points...');
+    // 实际项目中会导航到投递点列表页面
+    // this.router.navigate(['/consumer/drop-points']);
+  }
+
+  // 查看更多活动
+  viewMoreActivities(): void {
+    console.log('Viewing more activities...');
+    // 实际项目中会导航到活动列表页面
+    // this.router.navigate(['/consumer/activities']);
+  }
+
+  // 打开AI助手
+  openAIAssistant(): void {
+    console.log('Opening AI assistant...');
+    // 打开AI助手对话界面
+    this.router.navigate(['/consumer/ai-assistant']);
+  }
+
+  // 切换底部导航标签
+  switchTab(tab: string): void {
+    this.currentTab = tab;
+    console.log(`Switching to tab: ${tab}`);
+    
+    // 根据选中的标签导航到对应页面
+    switch (tab) {
+      case 'home':
+        // 已经在首页,不需要导航
+        break;
+      case 'booking':
+        this.router.navigate(['/consumer/booking-recycle']);
+        break;
+      case 'earnings':
+        this.router.navigate(['/consumer/earnings']);
+        break;
+      case 'mall':
+        this.router.navigate(['/consumer/points-mall']);
+        break;
+      case 'profile':
+        this.router.navigate(['/consumer/profile']);
+        break;
+      default:
+        console.warn(`Unknown tab: ${tab}`);
+    }
+  }
+
+  // 刷新页面数据
+  refreshData(): void {
+    console.log('Refreshing data...');
+    this.loadUserData();
+    this.loadDynamicData();
+  }
+
+  // 处理用户等级进度更新
+  updateLevelProgress(): void {
+    // 模拟等级进度更新
+    if (this.levelProgress < 100) {
+      this.levelProgress += 5;
+    } else {
+      this.userLevel += 1;
+      this.levelProgress = 0;
+    }
+  }
+
+  // 处理积分更新
+  updatePoints(points: number): void {
+    this.userPoints += points;
+    console.log(`Points updated: +${points}, Total: ${this.userPoints}`);
+  }
+
+  // 处理现金更新
+  updateCash(amount: number): void {
+    this.userCash += amount;
+    console.log(`Cash updated: +${amount}, Total: ${this.userCash}`);
+  }
 }

+ 166 - 5
src/app/consumer/points-mall/points-mall.html

@@ -1,6 +1,167 @@
-<div class="points-mall-container">
-  <div class="mall-header">
-    <h1>积分商城</h1>
+<!-- 顶部标题栏 -->
+<div class="header">
+  <div class="back-btn" (click)="goBack()"><i class="fas fa-arrow-left"></i></div>
+  <div class="header-title">积分商城</div>
+</div>
+
+<div class="container">
+  <!-- 积分余额显示区 -->
+  <div class="points-header">
+    <div class="points-balance">{{userPoints}}</div>
+    <div class="points-label">我的积分</div>
+    <div class="points-actions">
+      <div class="points-action-btn" (click)="showPointsRules()">积分规则</div>
+      <div class="points-action-btn" (click)="showPointsHistory()">积分记录</div>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
-</div>
+  
+  <!-- 活动专区轮播 -->
+  <div class="section">
+    <div class="section-title">
+      <span>活动专区</span>
+      <span style="font-size: 14px; color: #6c757d;">限时优惠</span>
+    </div>
+    
+    <div class="carousel">
+      <div class="carousel-inner" #carouselInner>
+        <div class="carousel-item" *ngFor="let activity of activities; let i = index" [class.active]="i === currentActivityIndex">
+          <div class="carousel-tag">{{activity.tag}}</div>
+          <div class="carousel-title">{{activity.title}}</div>
+          <div class="carousel-desc">{{activity.description}}</div>
+          <div class="carousel-time">{{activity.time}}</div>
+        </div>
+      </div>
+      <div class="carousel-indicators">
+        <div 
+          *ngFor="let activity of activities; let i = index"
+          class="carousel-indicator" 
+          [class.active]="i === currentActivityIndex"
+          (click)="setActiveActivity(i)"></div>
+      </div>
+    </div>
+    
+    <!-- 商品分类导航 -->
+    <div class="section-title">商品分类</div>
+    <div class="category-nav">
+      <div 
+        *ngFor="let category of categories"
+        class="category-item" 
+        [class.active]="category.active"
+        (click)="selectCategory(category)">
+        <div class="category-icon"><i [class]="category.icon"></i></div>
+        <div class="category-name">{{category.name}}</div>
+      </div>
+    </div>
+    
+    <!-- 商品列表 -->
+    <div class="section-title">热门商品</div>
+    <div class="products-grid">
+      <div 
+        *ngFor="let product of filteredProducts"
+        class="product-card" 
+        (click)="showProductDetail(product)">
+        <div class="product-image">
+          <img *ngIf="product.image" [src]="product.image" [alt]="product.name" class="product-img">
+          <i *ngIf="!product.image" [class]="product.icon + ' fa-2x'"></i>
+          <div class="product-tag" *ngIf="product.tag">{{product.tag}}</div>
+        </div>
+        <div class="product-info">
+          <div class="product-name">{{product.name}}</div>
+          <div class="product-price">
+            <div class="price-info">
+              <div class="points-price">{{product.pointsPrice}}积分</div>
+              <div class="cash-price">市场价: ¥{{product.marketPrice}}</div>
+            </div>
+            <button 
+              class="exchange-btn" 
+              [disabled]="userPoints < product.pointsPrice"
+              (click)="exchangeProduct(product, $event)">兑换</button>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- 积分任务中心 -->
+<div class="container">
+  <div class="section tasks-section">
+    <div class="section-title">
+      <span>积分任务</span>
+      <span style="font-size: 14px; color: #6c757d;">赚取更多积分</span>
+    </div>
+    
+    <div class="task-list">
+      <div 
+        *ngFor="let task of tasks"
+        class="task-item">
+        <div class="task-info">
+          <div class="task-icon"><i [class]="task.icon"></i></div>
+          <div class="task-details">
+            <div class="task-name">{{task.name}}</div>
+            <div class="task-desc">{{task.description}}</div>
+            <div class="task-progress" *ngIf="task.progress">{{task.progress}}</div>
+          </div>
+        </div>
+        <div class="task-reward">+{{task.reward}}积分</div>
+        <button 
+          class="task-btn" 
+          [class.completed]="task.completed"
+          (click)="doTask(task)">
+          {{task.completed ? '已完成' : task.buttonText}}
+        </button>
+      </div>
+    </div>
+  </div>
+</div>
+
+<!-- 商品详情模态框 -->
+<div class="modal" [style.display]="showProductModal ? 'flex' : 'none'" (click)="closeProductModal()">
+  <div class="modal-content" (click)="$event.stopPropagation()" *ngIf="selectedProduct">
+    <div class="modal-title">{{selectedProduct.name}}</div>
+    <div class="product-detail-image">
+      <img *ngIf="selectedProduct.image" [src]="selectedProduct.image" [alt]="selectedProduct.name" class="product-detail-img">
+      <i *ngIf="!selectedProduct.image" [class]="selectedProduct.icon + ' fa-4x'"></i>
+    </div>
+    <div class="product-detail-info">
+      <div class="detail-price">
+        <span class="points-price">{{selectedProduct.pointsPrice}}积分</span>
+        <span class="cash-price">市场价: ¥{{selectedProduct.marketPrice}}</span>
+      </div>
+      <div class="product-description">{{selectedProduct.description}}</div>
+    </div>
+    <div class="modal-buttons">
+      <button class="modal-btn cancel" (click)="closeProductModal()">取消</button>
+      <button 
+        class="modal-btn confirm" 
+        [disabled]="userPoints < selectedProduct.pointsPrice"
+        (click)="confirmExchange()">确认兑换</button>
+    </div>
+  </div>
+</div>
+
+<!-- 签到模态框 -->
+<div class="modal" [style.display]="showCheckinModal ? 'flex' : 'none'" (click)="closeCheckinModal()">
+  <div class="modal-content" (click)="$event.stopPropagation()">
+    <div class="modal-title">每日签到</div>
+    <div class="checkin-calendar">
+      <div 
+        *ngFor="let day of checkinDays"
+        class="checkin-day" 
+        [class.checked]="day.checked"
+        [class.today]="day.isToday">
+        {{day.day}}
+      </div>
+    </div>
+    <div style="text-align: center; margin: 15px 0;">
+      <div style="color: #2e7d32; font-weight: 600;">签到成功!</div>
+      <div style="color: #ff9800; font-size: 18px; margin-top: 5px;">+{{dailyCheckinReward}}积分</div>
+    </div>
+    <div class="modal-buttons">
+      <button class="modal-btn confirm" (click)="closeCheckinModal()">确定</button>
+    </div>
+  </div>
+</div>
+
+<!-- 底部导航栏 -->
+<app-bottom-nav [activeTab]="'mall'"></app-bottom-nav>

+ 639 - 0
src/app/consumer/points-mall/points-mall.scss

@@ -0,0 +1,639 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+  font-family: 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
+}
+
+body {
+  background-color: #f8f9fa;
+  color: #333;
+  padding-bottom: 20px;
+}
+
+.header {
+  background: linear-gradient(135deg, #2ecc71, #1abc9c);
+  color: white;
+  padding: 15px 20px;
+  display: flex;
+  align-items: center;
+  position: sticky;
+  top: 0;
+  z-index: 100;
+}
+
+.back-btn {
+  font-size: 20px;
+  margin-right: 15px;
+  cursor: pointer;
+}
+
+.header-title {
+  font-size: 18px;
+  font-weight: 600;
+}
+
+.container {
+  padding: 15px;
+}
+
+.section {
+  background: white;
+  margin-bottom: 15px;
+  padding: 20px;
+  border-radius: 16px;
+  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
+}
+
+.section-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 15px;
+  color: #2c3e50;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+}
+
+/* 积分余额显示区 */
+.points-header {
+  background: linear-gradient(135deg, #ff9800, #ff5722);
+  color: white;
+  padding: 20px;
+  border-radius: 16px;
+  margin-bottom: 15px;
+  text-align: center;
+  position: relative;
+  overflow: hidden;
+
+  &::before {
+    content: "";
+    position: absolute;
+    top: -50%;
+    right: -50%;
+    width: 100%;
+    height: 100%;
+    background: rgba(255, 255, 255, 0.1);
+    border-radius: 50%;
+  }
+}
+
+.points-balance {
+  font-size: 32px;
+  font-weight: 600;
+  margin-bottom: 5px;
+  position: relative;
+  z-index: 1;
+}
+
+.points-label {
+  font-size: 14px;
+  opacity: 0.9;
+  position: relative;
+  z-index: 1;
+}
+
+.points-actions {
+  display: flex;
+  gap: 10px;
+  margin-top: 15px;
+  position: relative;
+  z-index: 1;
+}
+
+.points-action-btn {
+  flex: 1;
+  background: rgba(255, 255, 255, 0.2);
+  border: 1px solid rgba(255, 255, 255, 0.3);
+  border-radius: 20px;
+  padding: 8px 15px;
+  color: white;
+  font-size: 14px;
+  text-align: center;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &:hover {
+    background: rgba(255, 255, 255, 0.3);
+  }
+}
+
+/* 活动专区轮播 */
+.carousel {
+  position: relative;
+  border-radius: 12px;
+  overflow: hidden;
+  margin-bottom: 15px;
+  height: 140px;
+}
+
+.carousel-inner {
+  display: flex;
+  transition: transform 0.3s ease;
+  height: 100%;
+}
+
+.carousel-item {
+  min-width: 100%;
+  height: 100%;
+  background: linear-gradient(135deg, #e8f5e9, #c8e6c9);
+  padding: 20px;
+  position: relative;
+
+  &:nth-child(2) {
+    background: linear-gradient(135deg, #fff3e0, #ffcc02);
+  }
+
+  &:nth-child(3) {
+    background: linear-gradient(135deg, #e3f2fd, #2196f3);
+  }
+}
+
+.carousel-tag {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  background: #ff9800;
+  color: white;
+  font-size: 10px;
+  padding: 4px 8px;
+  border-radius: 10px;
+}
+
+.carousel-title {
+  font-size: 16px;
+  font-weight: 600;
+  margin-bottom: 5px;
+}
+
+.carousel-desc {
+  font-size: 12px;
+  color: #6c757d;
+  margin-bottom: 10px;
+}
+
+.carousel-time {
+  font-size: 12px;
+  color: #ff9800;
+}
+
+.carousel-indicators {
+  position: absolute;
+  bottom: 10px;
+  left: 0;
+  right: 0;
+  display: flex;
+  justify-content: center;
+  gap: 6px;
+}
+
+.carousel-indicator {
+  width: 6px;
+  height: 6px;
+  background: rgba(255, 255, 255, 0.5);
+  border-radius: 50%;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &.active {
+    background: white;
+  }
+}
+
+/* 商品分类导航 */
+.category-nav {
+  display: grid;
+  grid-template-columns: repeat(4, 1fr);
+  gap: 10px;
+  margin-bottom: 15px;
+}
+
+.category-item {
+  text-align: center;
+  padding: 12px 5px;
+  border-radius: 12px;
+  transition: all 0.3s;
+  cursor: pointer;
+
+  &.active {
+    background: rgba(46, 204, 113, 0.1);
+
+    .category-icon {
+      background: #2e7d32;
+      color: white;
+    }
+  }
+}
+
+.category-icon {
+  width: 40px;
+  height: 40px;
+  background: rgba(46, 204, 113, 0.1);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0 auto 8px;
+  color: #2e7d32;
+  font-size: 18px;
+  transition: all 0.3s;
+}
+
+.category-name {
+  font-size: 12px;
+}
+
+/* 商品列表 */
+.products-grid {
+  display: grid;
+  grid-template-columns: repeat(2, 1fr);
+  gap: 12px;
+}
+
+.product-card {
+  background: #f8f9fa;
+  border-radius: 12px;
+  overflow: hidden;
+  transition: all 0.3s;
+  cursor: pointer;
+
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+  }
+}
+
+.product-image {
+  height: 120px;
+  background: #e9ecef;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #6c757d;
+  position: relative;
+}
+
+.product-img {
+  width: 100%;
+  height: 100%;
+  object-fit: cover;
+  border-radius: 8px 8px 0 0;
+}
+
+.product-tag {
+  position: absolute;
+  top: 8px;
+  left: 8px;
+  background: #ff4757;
+  color: white;
+  font-size: 10px;
+  padding: 2px 6px;
+  border-radius: 8px;
+}
+
+.product-info {
+  padding: 12px;
+}
+
+.product-name {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 8px;
+  height: 40px;
+  overflow: hidden;
+  line-height: 1.4;
+}
+
+.product-price {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.price-info {
+  display: flex;
+  flex-direction: column;
+}
+
+.points-price {
+  color: #ff9800;
+  font-weight: 600;
+  font-size: 16px;
+}
+
+.cash-price {
+  font-size: 11px;
+  color: #6c757d;
+  text-decoration: line-through;
+}
+
+.exchange-btn {
+  background: #2e7d32;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  padding: 6px 12px;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &:hover {
+    background: #1b5e20;
+  }
+
+  &:disabled {
+    background: #ccc;
+    cursor: not-allowed;
+  }
+}
+
+/* 积分任务中心 */
+.tasks-section {
+  margin-top: 20px;
+}
+
+.task-list {
+  display: flex;
+  flex-direction: column;
+  gap: 12px;
+}
+
+.task-item {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  padding: 12px 0;
+  border-bottom: 1px solid #f1f3f4;
+
+  &:last-child {
+    border-bottom: none;
+  }
+}
+
+.task-info {
+  display: flex;
+  align-items: center;
+  flex: 1;
+}
+
+.task-icon {
+  width: 36px;
+  height: 36px;
+  background: rgba(46, 204, 113, 0.1);
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-right: 12px;
+  color: #2e7d32;
+}
+
+.task-details {
+  flex: 1;
+}
+
+.task-name {
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 4px;
+}
+
+.task-desc {
+  font-size: 12px;
+  color: #6c757d;
+}
+
+.task-progress {
+  font-size: 11px;
+  color: #2e7d32;
+  margin-top: 2px;
+}
+
+.task-reward {
+  color: #ff9800;
+  font-weight: 500;
+  margin-right: 10px;
+}
+
+.task-btn {
+  background: #2e7d32;
+  color: white;
+  border: none;
+  border-radius: 6px;
+  padding: 6px 12px;
+  font-size: 12px;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &.completed {
+    background: #6c757d;
+  }
+
+  &:hover:not(.completed) {
+    background: #1b5e20;
+  }
+}
+
+/* 模态框 */
+.modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0, 0, 0, 0.5);
+  z-index: 1000;
+  align-items: center;
+  justify-content: center;
+  padding: 20px;
+}
+
+.modal-content {
+  background: white;
+  width: 100%;
+  max-width: 400px;
+  border-radius: 16px;
+  padding: 20px;
+  text-align: center;
+}
+
+.modal-title {
+  font-size: 18px;
+  font-weight: 600;
+  margin-bottom: 15px;
+}
+
+.product-detail-image {
+  margin: 20px 0;
+  color: #6c757d;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  height: 200px;
+}
+
+.product-detail-img {
+  max-width: 100%;
+  max-height: 100%;
+  object-fit: contain;
+  border-radius: 8px;
+}
+
+.product-detail-info {
+  margin: 20px 0;
+}
+
+.detail-price {
+  margin-bottom: 15px;
+
+  .points-price {
+    font-size: 20px;
+    color: #ff9800;
+    font-weight: 600;
+    margin-right: 10px;
+  }
+
+  .cash-price {
+    font-size: 14px;
+    color: #6c757d;
+    text-decoration: line-through;
+  }
+}
+
+.product-description {
+  font-size: 14px;
+  color: #6c757d;
+  line-height: 1.5;
+}
+
+.modal-buttons {
+  display: flex;
+  gap: 10px;
+  margin-top: 20px;
+}
+
+.modal-btn {
+  flex: 1;
+  padding: 12px;
+  border-radius: 8px;
+  font-size: 14px;
+  font-weight: 500;
+  cursor: pointer;
+  transition: all 0.3s;
+
+  &.cancel {
+    background: #f8f9fa;
+    border: 1px solid #e9ecef;
+    color: #6c757d;
+
+    &:hover {
+      background: #e9ecef;
+    }
+  }
+
+  &.confirm {
+    background: #2e7d32;
+    color: white;
+    border: none;
+
+    &:hover:not(:disabled) {
+      background: #1b5e20;
+    }
+
+    &:disabled {
+      background: #ccc;
+      cursor: not-allowed;
+    }
+  }
+}
+
+/* 签到模态框 */
+.checkin-calendar {
+  display: grid;
+  grid-template-columns: repeat(7, 1fr);
+  gap: 8px;
+  margin: 15px 0;
+}
+
+.checkin-day {
+  width: 36px;
+  height: 36px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-size: 14px;
+  background: #f8f9fa;
+  margin: 0 auto;
+
+  &.checked {
+    background: #2e7d32;
+    color: white;
+  }
+
+  &.today {
+    border: 2px solid #2e7d32;
+  }
+}
+
+/* 底部导航栏 */
+.bottom-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: white;
+  display: flex;
+  padding: 10px 0 20px;
+  box-shadow: 0 -2px 20px rgba(0, 0, 0, 0.1);
+  z-index: 999;
+  
+  .nav-item {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    cursor: pointer;
+    transition: all 0.3s ease;
+    
+    &.active {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: linear-gradient(135deg, #4caf50, #66bb6a);
+        color: white;
+        transform: scale(1.1);
+      }
+    }
+    
+    .nav-icon {
+      width: 35px;
+      height: 35px;
+      background: #f8f9fa;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-bottom: 5px;
+      transition: all 0.3s ease;
+      
+      i {
+        font-size: 16px;
+      }
+    }
+    
+    div:last-child {
+      font-size: 10px;
+      font-weight: 500;
+    }
+    
+    &:hover:not(.active) {
+      color: #4caf50;
+      
+      .nav-icon {
+        background: #f1f8e9;
+        transform: scale(1.05);
+      }
+    }
+  }
+}

+ 419 - 4
src/app/consumer/points-mall/points-mall.ts

@@ -1,13 +1,428 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { RouterModule, Router } from '@angular/router';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
+
+interface Product {
+  id: number;
+  name: string;
+  pointsPrice: number;
+  cashPrice: number;
+  marketPrice?: number;
+  category: string;
+  image: string;
+  description: string;
+  stock: number;
+  tag?: string;
+  icon?: string;
+}
+
+interface Category {
+  id: string;
+  name: string;
+  icon: string;
+  active?: boolean;
+}
+
+interface Activity {
+  id: number;
+  title: string;
+  description: string;
+  time: string;
+  timeInfo?: string;
+  tag: string;
+}
+
+interface Task {
+  id: number;
+  name: string;
+  description: string;
+  progress: string;
+  reward: number;
+  icon: string;
+  completed: boolean;
+  buttonText?: string;
+}
 
 @Component({
   selector: 'app-points-mall',
-  imports: [CommonModule, RouterModule],
+  imports: [CommonModule, RouterModule, BottomNavComponent],
   templateUrl: './points-mall.html',
   styleUrl: './points-mall.scss'
 })
-export class PointsMallComponent {
-  constructor() {}
+export class PointsMall {
+  // 用户积分余额
+  userPoints = 2580;
+  
+  // 当前选中的分类
+  selectedCategory = 'all';
+  
+  // 当前选中的标签页
+  currentTab = 'mall';
+  
+  // 轮播当前索引
+  currentCarouselIndex = 0;
+  
+  // 每日签到奖励积分
+  dailyCheckinReward = 10;
+  
+  // 模态框状态
+  showProductModal = false;
+  showCheckinModal = false;
+  selectedProduct: Product | null = null;
+  
+  // 商品分类
+  categories: Category[] = [
+    { id: 'all', name: '全部', icon: 'fas fa-th-large', active: true },
+    { id: 'electronics', name: '数码', icon: 'fas fa-mobile-alt', active: false },
+    { id: 'home', name: '家居', icon: 'fas fa-home', active: false },
+    { id: 'food', name: '食品', icon: 'fas fa-utensils', active: false }
+  ];
+  
+  // 活动轮播数据
+  activities: Activity[] = [
+    {
+      id: 1,
+      title: '新用户专享',
+      description: '注册即送500积分',
+      time: '2024.01.01-2024.01.31',
+      timeInfo: '2024.01.01-2024.01.31',
+      tag: '限时'
+    },
+    {
+      id: 2,
+      title: '积分翻倍',
+      description: '回收积分双倍奖励',
+      time: '2024.01.15-2024.01.20',
+      timeInfo: '2024.01.15-2024.01.20',
+      tag: '热门'
+    },
+    {
+      id: 3,
+      title: '签到有礼',
+      description: '连续签到7天送大礼',
+      time: '每日签到',
+      timeInfo: '每日签到',
+      tag: '每日'
+    }
+  ];
+  
+  // 商品列表
+  products: Product[] = [
+    {
+      id: 1,
+      name: '小米无线充电器',
+      pointsPrice: 800,
+      cashPrice: 99,
+      marketPrice: 129,
+      category: 'electronics',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><rect x="20" y="30" width="60" height="40" rx="5" fill="%23333"/><circle cx="50" cy="50" r="15" fill="%23fff"/><circle cx="50" cy="50" r="8" fill="%2300aaff"/></svg>',
+      description: '支持10W快充,兼容多种设备',
+      stock: 50,
+      tag: '热销',
+      icon: 'fas fa-mobile-alt'
+    },
+    {
+      id: 2,
+      name: '环保购物袋',
+      pointsPrice: 200,
+      cashPrice: 25,
+      marketPrice: 35,
+      category: 'home',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><path d="M25 35h50v45c0 5-5 10-10 10H35c-5 0-10-5-10-10V35z" fill="%234caf50"/><path d="M35 35V25c0-5 5-10 10-10h10c5 0 10 5 10 10v10" stroke="%234caf50" stroke-width="3" fill="none"/></svg>',
+      description: '可重复使用,环保材质',
+      stock: 100,
+      icon: 'fas fa-shopping-bag'
+    },
+    {
+      id: 3,
+      name: '有机燕麦片',
+      pointsPrice: 300,
+      cashPrice: 38,
+      marketPrice: 48,
+      category: 'food',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><rect x="20" y="20" width="60" height="60" rx="5" fill="%23fff" stroke="%23ddd" stroke-width="2"/><circle cx="35" cy="35" r="4" fill="%23ffc107"/><circle cx="50" cy="40" r="3" fill="%23ffc107"/><circle cx="65" cy="45" r="4" fill="%23ffc107"/><circle cx="40" cy="55" r="3" fill="%23ffc107"/><circle cx="60" cy="60" r="4" fill="%23ffc107"/></svg>',
+      description: '营养丰富,健康早餐首选',
+      stock: 30,
+      icon: 'fas fa-seedling'
+    },
+    {
+      id: 4,
+      name: '蓝牙耳机',
+      pointsPrice: 1200,
+      cashPrice: 149,
+      marketPrice: 199,
+      category: 'electronics',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><ellipse cx="30" cy="40" rx="12" ry="15" fill="%23333"/><ellipse cx="70" cy="40" rx="12" ry="15" fill="%23333"/><path d="M42 40c0-10 8-18 18-18s18 8 18 18" stroke="%23333" stroke-width="3" fill="none"/><circle cx="30" cy="40" r="5" fill="%2300aaff"/><circle cx="70" cy="40" r="5" fill="%2300aaff"/></svg>',
+      description: '高品质音效,长续航',
+      stock: 25,
+      tag: '新品',
+      icon: 'fas fa-headphones'
+    },
+    {
+      id: 5,
+      name: '竹纤维毛巾',
+      pointsPrice: 150,
+      cashPrice: 19,
+      marketPrice: 29,
+      category: 'home',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><rect x="20" y="30" width="60" height="40" rx="5" fill="%2387ceeb"/><line x1="25" y1="35" x2="75" y2="35" stroke="%235f9ea0" stroke-width="2"/><line x1="25" y1="45" x2="75" y2="45" stroke="%235f9ea0" stroke-width="2"/><line x1="25" y1="55" x2="75" y2="55" stroke="%235f9ea0" stroke-width="2"/><line x1="25" y1="65" x2="75" y2="65" stroke="%235f9ea0" stroke-width="2"/></svg>',
+      description: '天然抗菌,柔软舒适',
+      stock: 80,
+      icon: 'fas fa-bath'
+    },
+    {
+      id: 6,
+      name: '坚果礼盒',
+      pointsPrice: 400,
+      cashPrice: 50,
+      marketPrice: 68,
+      category: 'food',
+      image: 'data:image/svg+xml;charset=utf-8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" rx="10" fill="%23f5f5f5"/><rect x="20" y="30" width="60" height="40" rx="5" fill="%23dd6b20"/><rect x="20" y="25" width="60" height="10" rx="5" fill="%23ffd700"/><circle cx="35" cy="45" r="4" fill="%238b4513"/><circle cx="50" cy="50" r="3" fill="%238b4513"/><circle cx="65" cy="55" r="4" fill="%238b4513"/><circle cx="40" cy="60" r="3" fill="%238b4513"/><circle cx="60" cy="40" r="3" fill="%238b4513"/></svg>',
+      description: '精选坚果,营养健康',
+      stock: 40,
+      icon: 'fas fa-gift'
+    }
+  ];
+  
+  // 积分任务
+  tasks: Task[] = [
+    {
+      id: 1,
+      name: '每日签到',
+      description: '连续签到获得积分奖励',
+      progress: '今日未签到',
+      reward: 10,
+      icon: 'fas fa-calendar-check',
+      completed: false,
+      buttonText: '签到'
+    },
+    {
+      id: 2,
+      name: '完成回收',
+      description: '完成一次废品回收',
+      progress: '0/1',
+      reward: 50,
+      icon: 'fas fa-recycle',
+      completed: false,
+      buttonText: '去回收'
+    },
+    {
+      id: 3,
+      name: '邀请好友',
+      description: '邀请好友注册使用',
+      progress: '0/3',
+      reward: 100,
+      icon: 'fas fa-user-friends',
+      completed: false,
+      buttonText: '邀请'
+    },
+    {
+      id: 4,
+      name: '分享应用',
+      description: '分享应用给朋友',
+      progress: '已完成',
+      reward: 20,
+      icon: 'fas fa-share-alt',
+      completed: true,
+      buttonText: '分享'
+    }
+  ];
+  
+  // 签到日历数据
+  checkinDays = Array.from({ length: 7 }, (_, i) => ({
+    day: i + 1,
+    checked: i < 3, // 前3天已签到
+    isToday: i === 3 // 第4天是今天
+  }));
+
+  constructor(private router: Router) {
+    // 启动轮播自动切换
+    this.startCarousel();
+  }
+
+  // 获取过滤后的商品列表
+  get filteredProducts(): Product[] {
+    if (this.selectedCategory === 'all') {
+      return this.products;
+    }
+    return this.products.filter(product => product.category === this.selectedCategory);
+  }
+
+  // 切换商品分类
+  selectCategory(category: Category): void {
+    // 重置所有分类的active状态
+    this.categories.forEach(cat => cat.active = false);
+    // 设置选中分类的active状态
+    category.active = true;
+    // 更新选中的分类ID
+    this.selectedCategory = category.id;
+  }
+
+  // 启动轮播自动切换
+  startCarousel(): void {
+    setInterval(() => {
+      this.currentCarouselIndex = (this.currentCarouselIndex + 1) % this.activities.length;
+    }, 3000);
+  }
+
+  // 手动切换轮播
+  goToSlide(index: number): void {
+    this.currentCarouselIndex = index;
+  }
+
+  // 获取轮播样式
+  getCarouselTransform(): string {
+    return `translateX(-${this.currentCarouselIndex * 100}%)`;
+  }
+
+  // 显示商品详情
+  showProductDetail(product: Product): void {
+    this.selectedProduct = product;
+    this.showProductModal = true;
+  }
+
+  // 关闭商品详情模态框
+  closeProductModal(): void {
+    this.showProductModal = false;
+    this.selectedProduct = null;
+  }
+
+  // 兑换商品
+  exchangeProduct(product: Product, event?: Event): void {
+    if (event) {
+      event.stopPropagation();
+    }
+    if (this.userPoints >= product.pointsPrice && product.stock > 0) {
+      this.userPoints -= product.pointsPrice;
+      product.stock--;
+      alert(`成功兑换 ${product.name}!`);
+    } else if (this.userPoints < product.pointsPrice) {
+      alert('积分不足,无法兑换!');
+    } else {
+      alert('商品库存不足!');
+    }
+  }
+
+  // 确认兑换商品
+  confirmExchange(): void {
+    if (this.selectedProduct && this.userPoints >= this.selectedProduct.pointsPrice) {
+      this.userPoints -= this.selectedProduct.pointsPrice;
+      this.selectedProduct.stock--;
+      this.showProductModal = false;
+      this.selectedProduct = null;
+      alert('兑换成功!');
+    } else {
+      alert('积分不足!');
+    }
+  }
+
+  // 显示签到模态框
+  showCheckin(): void {
+    this.showCheckinModal = true;
+  }
+
+  // 关闭签到模态框
+  closeCheckinModal(): void {
+    this.showCheckinModal = false;
+  }
+
+  // 执行签到
+  doCheckin(): void {
+    const todayIndex = this.checkinDays.findIndex(day => day.isToday);
+    if (todayIndex !== -1 && !this.checkinDays[todayIndex].checked) {
+      this.checkinDays[todayIndex].checked = true;
+      this.userPoints += 10;
+      
+      // 更新签到任务状态
+      const checkinTask = this.tasks.find(task => task.id === 1);
+      if (checkinTask) {
+        checkinTask.progress = '今日已签到';
+        checkinTask.completed = true;
+      }
+      
+      alert('签到成功!获得10积分');
+    } else {
+      alert('今日已签到或签到时间未到!');
+    }
+    this.closeCheckinModal();
+  }
+
+  // 执行任务
+  doTask(task: Task): void {
+    if (task.completed) {
+      return;
+    }
+
+    switch (task.id) {
+      case 1: // 签到任务
+        this.showCheckin();
+        break;
+      case 2: // 回收任务
+        alert('请前往预约页面完成回收任务');
+        break;
+      case 3: // 邀请任务
+        alert('邀请功能开发中...');
+        break;
+      default:
+        break;
+    }
+  }
+
+  // 查看积分记录
+  viewPointsHistory(): void {
+    alert('积分记录功能开发中...');
+  }
+
+  // 充值积分
+  rechargePoints(): void {
+    alert('积分充值功能开发中...');
+  }
+
+  // 返回上一页
+  goBack(): void {
+    window.history.back();
+  }
+
+  // 显示积分规则
+  showPointsRules(): void {
+    alert('积分规则:\n1. 完成回收任务获得积分\n2. 每日签到获得积分\n3. 邀请好友获得积分\n4. 积分可兑换商品');
+  }
+
+  // 显示积分记录(重命名方法以匹配HTML中的调用)
+  showPointsHistory(): void {
+    this.viewPointsHistory();
+  }
+
+  // 设置活动轮播的当前索引(重命名属性以匹配HTML中的引用)
+  get currentActivityIndex(): number {
+    return this.currentCarouselIndex;
+  }
+
+  // 设置活动轮播
+  setActiveActivity(index: number): void {
+    this.goToSlide(index);
+  }
+
+  // 底部导航切换
+  switchTab(tab: string): void {
+    this.currentTab = tab;
+    switch (tab) {
+      case 'home':
+        this.router.navigate(['/consumer/home']);
+        break;
+      case 'booking':
+        this.router.navigate(['/consumer/booking-recycle']);
+        break;
+      case 'earnings':
+        this.router.navigate(['/consumer/earnings']);
+        break;
+      case 'mall':
+        // 当前页面,无需操作
+        break;
+      case 'profile':
+        this.router.navigate(['/consumer/profile']);
+        break;
+    }
+  }
 }

+ 212 - 5
src/app/consumer/profile/profile.html

@@ -1,6 +1,213 @@
-<div class="profile-container">
-  <div class="profile-header">
-    <h1>个人中心</h1>
+<!-- 顶部标题栏 -->
+<div class="header">
+  <div class="back-btn" (click)="goBack()"><i class="fas fa-arrow-left"></i></div>
+  <div class="header-title">个人中心</div>
+  <div class="edit-profile" (click)="openEditModal()"><i class="fas fa-cog"></i></div>
+  
+  <div class="avatar-container">
+    <div class="avatar" id="userAvatar">
+      <i class="fas fa-user"></i>
+    </div>
+    <div class="avatar-edit" (click)="openEditModal()">
+      <i class="fas fa-pencil-alt"></i>
+    </div>
   </div>
-  <!-- 页面内容已清理,保留基本结构 -->
-</div>
+  
+  <div class="user-name">{{ userName }}</div>
+  <div class="user-level">{{ userLevel }}</div>
+</div>
+
+<div class="container">
+  <!-- 统计数据 -->
+  <div class="section">
+    <div class="stats-container">
+      <div class="stat-item">
+        <div class="stat-value">{{ statRecycleCount }}</div>
+        <div class="stat-label">回收次数</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">{{ statCashTotal }}</div>
+        <div class="stat-label">累计收益(元)</div>
+      </div>
+      <div class="stat-item">
+        <div class="stat-value">{{ statCarbonTotal }}</div>
+        <div class="stat-label">碳减排(kg)</div>
+      </div>
+    </div>
+    
+    <div class="badges-container">
+      <div class="badges-title">成就徽章</div>
+      <div class="badges">
+        <div class="badge-item">
+          <div class="badge recycling"><i class="fas fa-recycle"></i></div>
+          <div class="badge-label">回收达人 · 完成20次回收</div>
+        </div>
+        <div class="badge-item">
+          <div class="badge environment"><i class="fas fa-leaf"></i></div>
+          <div class="badge-label">环保先锋 · 减排超100kg</div>
+        </div>
+        <div class="badge-item">
+          <div class="badge achievement"><i class="fas fa-trophy"></i></div>
+          <div class="badge-label">月度之星 · 本月排名前10</div>
+        </div>
+        <div class="badge-item">
+          <div class="badge community"><i class="fas fa-users"></i></div>
+          <div class="badge-label">社区贡献 · 邀请3位好友</div>
+        </div>
+        <div class="badge-item more" (click)="showAllBadges()">
+          <div class="badge-more">+2</div>
+          <div class="badge-label">更多徽章</div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 功能列表 -->
+  <div class="section">
+    <div class="menu-list">
+      <div class="menu-item" (click)="goToPage('orders')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-list-alt"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">我的订单</div>
+            <div class="menu-desc">查看回收订单记录</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('address')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-map-marker-alt"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">我的地址</div>
+            <div class="menu-desc">管理收货地址</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('favorites')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-heart"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">我的收藏</div>
+            <div class="menu-desc">商品和知识收藏</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('invite')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-user-plus"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">邀请好友</div>
+            <div class="menu-desc">邀请好友得奖励</div>
+          </div>
+        </div>
+        <div class="menu-badge">+100积分</div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('customerService')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-headset"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">客服与反馈</div>
+            <div class="menu-desc">问题咨询与建议</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('settings')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-cog"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">设置</div>
+            <div class="menu-desc">账号与隐私设置</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+    </div>
+  </div>
+
+  <!-- 通用入口 -->
+  <div class="section general-menu">
+    <div class="menu-list">
+      <div class="menu-item" (click)="goToPage('about')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-info-circle"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">关于我们</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('agreement')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-file-contract"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">用户协议</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+      
+      <div class="menu-item" (click)="goToPage('privacy')">
+        <div class="menu-info">
+          <div class="menu-icon"><i class="fas fa-shield-alt"></i></div>
+          <div class="menu-text">
+            <div class="menu-name">隐私政策</div>
+          </div>
+        </div>
+        <div class="menu-arrow"><i class="fas fa-chevron-right"></i></div>
+      </div>
+    </div>
+    
+    <button class="logout-btn" (click)="openLogoutModal()">退出登录</button>
+  </div>
+</div>
+
+<!-- 退出登录模态框 -->
+<div class="modal" [style.display]="showLogout ? 'flex' : 'none'" (click)="closeLogoutModal($event)">
+  <div class="modal-content">
+    <div class="modal-title">确认退出登录?</div>
+    <div class="modal-buttons">
+      <button class="modal-btn cancel" (click)="showLogout = false">取消</button>
+      <button class="modal-btn confirm" (click)="confirmLogout()">退出</button>
+    </div>
+  </div>
+</div>
+
+<!-- 编辑资料模态框 -->
+<div class="modal" [style.display]="showEdit ? 'flex' : 'none'" (click)="closeEditModal($event)">
+  <div class="modal-content">
+    <div class="modal-title">编辑资料</div>
+    <div class="edit-form">
+      <div class="form-group">
+        <label class="form-label">昵称</label>
+        <input class="form-input" [(ngModel)]="userName" placeholder="请输入昵称" />
+      </div>
+      <div class="form-group">
+        <label class="form-label">头像</label>
+        <div class="avatar-options">
+          <div class="avatar-option avatar-1" [class.active]="selectedAvatar === 1" (click)="selectAvatar(1)"><i class="fas fa-user"></i></div>
+          <div class="avatar-option avatar-2" [class.active]="selectedAvatar === 2" (click)="selectAvatar(2)"><i class="fas fa-user"></i></div>
+          <div class="avatar-option avatar-3" [class.active]="selectedAvatar === 3" (click)="selectAvatar(3)"><i class="fas fa-user"></i></div>
+          <div class="avatar-option avatar-4" [class.active]="selectedAvatar === 4" (click)="selectAvatar(4)"><i class="fas fa-user"></i></div>
+        </div>
+      </div>
+    </div>
+    <div class="modal-buttons">
+      <button class="modal-btn cancel" (click)="showEdit = false">取消</button>
+      <button class="modal-btn confirm" (click)="saveProfile()">保存</button>
+    </div>
+  </div>
+</div>
+
+<!-- 底部统一导航 -->
+<app-bottom-nav [activeTab]="'profile'"></app-bottom-nav>

+ 243 - 0
src/app/consumer/profile/profile.scss

@@ -0,0 +1,243 @@
+/* 页面基础布局 */
+.container {
+  padding: 16px;
+  padding-bottom: 88px; /* 为底部导航留空 */
+}
+
+/* 顶部标题与头像区域 */
+.header {
+  position: relative;
+  text-align: center;
+  padding: 20px 0 12px;
+}
+
+.back-btn,
+.edit-profile {
+  position: absolute;
+  top: 16px;
+  font-size: 18px;
+  color: #2e7d32;
+}
+
+.back-btn { left: 12px; }
+.edit-profile { right: 12px; }
+
+.avatar-container {
+  position: relative;
+  display: inline-block;
+  margin: 8px 0 12px;
+}
+
+.avatar {
+  width: 80px;
+  height: 80px;
+  background: linear-gradient(135deg, #2ecc71, #1abc9c);
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  font-size: 32px;
+  border: 3px solid #fff;
+  box-shadow: 0 4px 12px rgba(46, 204, 113, 0.3);
+}
+
+.avatar-edit {
+  position: absolute;
+  bottom: 0;
+  right: 0;
+  width: 28px;
+  height: 28px;
+  background: #2e7d32;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  font-size: 12px;
+  border: 2px solid #fff;
+}
+
+.user-name {
+  font-size: 20px;
+  font-weight: 600;
+  margin-bottom: 6px;
+}
+
+.user-level {
+  display: inline-block;
+  background: linear-gradient(135deg, #ff9800, #ff5722);
+  color: #fff;
+  padding: 6px 16px;
+  border-radius: 20px;
+  font-size: 14px;
+  font-weight: 500;
+  margin-bottom: 12px;
+  box-shadow: 0 2px 8px rgba(255, 152, 0, 0.3);
+}
+
+/* 统计与徽章 */
+.section { margin-top: 10px; }
+
+.stats-container {
+  display: flex;
+  justify-content: space-around;
+  padding-top: 16px;
+  border-top: 1px solid #f1f3f4;
+}
+
+.stat-item { text-align: center; }
+.stat-value { font-size: 18px; font-weight: 600; color: #2e7d32; margin-bottom: 4px; }
+.stat-label { font-size: 12px; color: #6c757d; }
+
+.badges-container { margin-top: 18px; }
+.badges-title { font-size: 14px; color: #6c757d; margin-bottom: 10px; text-align: left; }
+
+.badges {
+  display: flex;
+  justify-content: center;
+  gap: 16px;
+  flex-wrap: wrap;
+}
+
+.badge-item {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 84px;
+}
+
+.badge {
+  width: 44px;
+  height: 44px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #fff;
+  font-size: 18px;
+  position: relative;
+}
+
+.badge.recycling { background: linear-gradient(135deg, #2ecc71, #1abc9c); }
+.badge.environment { background: linear-gradient(135deg, #66bb6a, #43a047); }
+.badge.achievement { background: linear-gradient(135deg, #ffa726, #fb8c00); }
+.badge.community { background: linear-gradient(135deg, #42a5f5, #1e88e5); }
+
+.badge-tooltip {
+  position: absolute;
+  bottom: -28px;
+  left: 50%;
+  transform: translateX(-50%);
+  background: rgba(0,0,0,0.75);
+  color: #fff;
+  font-size: 11px;
+  padding: 4px 8px;
+  border-radius: 6px;
+  white-space: nowrap;
+}
+
+.badge-label {
+  margin-top: 6px;
+  font-size: 11px;
+  color: #6c757d;
+  text-align: center;
+  line-height: 1.2;
+}
+
+.badge-more {
+  width: 44px;
+  height: 44px;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  background: #f5f5f5;
+  color: #666;
+  font-size: 14px;
+}
+
+/* 菜单列表 */
+.menu-list { margin-top: 8px; }
+.menu-item {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 12px 6px;
+  border-bottom: 1px solid #eee;
+}
+
+.menu-info { display: flex; align-items: center; gap: 10px; }
+.menu-icon {
+  width: 36px;
+  height: 36px;
+  border-radius: 10px;
+  background: #f8f9fa;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #2e7d32;
+}
+.menu-text { display: flex; flex-direction: column; }
+.menu-name { font-size: 14px; font-weight: 500; color: #495057; }
+.menu-desc { font-size: 12px; color: #6c757d; }
+.menu-arrow { color: #999; }
+.menu-badge { font-size: 12px; color: #ff5722; margin-right: 8px; }
+
+/* 退出登录按钮样式优化 */
+.logout-btn {
+  width: 100%;
+  margin-top: 14px;
+  padding: 12px 16px;
+  background: linear-gradient(135deg, #2ecc71, #1abc9c);
+  color: #fff;
+  border: none;
+  border-radius: 10px;
+  font-size: 16px;
+  font-weight: 600;
+  box-shadow: 0 4px 12px rgba(46, 204, 113, 0.3);
+}
+
+/* 模态框 */
+.modal {
+  position: fixed;
+  left: 0; right: 0; top: 0; bottom: 0;
+  background: rgba(0, 0, 0, 0.4);
+  display: none;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+}
+
+.modal-content {
+  width: 86%;
+  max-width: 420px;
+  background: #fff;
+  border-radius: 12px;
+  padding: 16px 14px;
+}
+
+.modal-title { font-size: 16px; font-weight: 600; margin-bottom: 10px; }
+.modal-buttons { display: flex; gap: 10px; justify-content: flex-end; margin-top: 12px; }
+.modal-btn { padding: 8px 14px; border-radius: 8px; border: none; }
+.modal-btn.cancel { background: #f5f5f5; color: #666; }
+.modal-btn.confirm { background: #2e7d32; color: #fff; }
+
+.edit-form { margin-top: 8px; }
+.form-group { margin-bottom: 10px; }
+.form-label { margin-bottom: 6px; font-size: 14px; font-weight: 500; color: #495057; }
+.form-input { width: 100%; padding: 10px 12px; border: 1px solid #e9ecef; border-radius: 8px; font-size: 14px; }
+.avatar-options { display: flex; gap: 10px; margin-top: 10px; }
+.avatar-option { width: 60px; height: 60px; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 24px; cursor: pointer; border: 2px solid transparent; }
+.avatar-option.active { border-color: #2e7d32; }
+.avatar-1 { background: linear-gradient(135deg, #2ecc71, #1abc9c); }
+.avatar-2 { background: linear-gradient(135deg, #3498db, #2980b9); }
+.avatar-3 { background: linear-gradient(135deg, #9b59b6, #8e44ad); }
+.avatar-4 { background: linear-gradient(135deg, #e74c3c, #c0392b); }
+
+/* 响应式优化,防止底部导航截断 */
+@media (max-width: 360px) {
+  .menu-item { padding: 10px 4px; }
+  .menu-name { font-size: 13px; }
+  .menu-desc { font-size: 11px; }
+}

+ 117 - 4
src/app/consumer/profile/profile.ts

@@ -1,13 +1,126 @@
 import { Component } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { RouterModule } from '@angular/router';
+import { FormsModule } from '@angular/forms';
+import { RouterModule, Router } from '@angular/router';
+import { BottomNavComponent } from '../../shared/bottom-nav/bottom-nav.component';
 
 @Component({
   selector: 'app-profile',
-  imports: [CommonModule, RouterModule],
+  imports: [CommonModule, FormsModule, RouterModule, BottomNavComponent],
   templateUrl: './profile.html',
   styleUrl: './profile.scss'
 })
-export class ProfileComponent {
-  constructor() {}
+export class Profile {
+  currentTab = 'profile';
+
+  // 用户信息与状态(参考 personal.html)
+  userName = '环保达人';
+  userLevel = 'LV5 环保先锋';
+  selectedAvatar = 1;
+
+  // 统计数据
+  statRecycleCount = 28;
+  statCashTotal = 386.5;
+  statCarbonTotal = 128.6;
+
+  // 模态框状态
+  showLogout = false;
+  showEdit = false;
+
+  constructor(private router: Router) {}
+
+  // 返回上一页
+  goBack(): void {
+    this.router.navigate(['/consumer/home']);
+  }
+
+  // 打开/关闭编辑资料
+  openEditModal(): void {
+    this.showEdit = true;
+  }
+
+  closeEditModal(event?: MouseEvent): void {
+    // 仅点击遮罩关闭
+    if (!event || event.target === event.currentTarget) {
+      this.showEdit = false;
+    }
+  }
+
+  // 选择头像
+  selectAvatar(index: number): void {
+    this.selectedAvatar = index;
+  }
+
+  // 保存资料
+  saveProfile(): void {
+    // 可扩展为实际保存逻辑
+    alert('资料已保存');
+    this.showEdit = false;
+  }
+
+  // 打开/关闭退出登录
+  openLogoutModal(): void {
+    this.showLogout = true;
+  }
+
+  closeLogoutModal(event?: MouseEvent): void {
+    if (!event || event.target === event.currentTarget) {
+      this.showLogout = false;
+    }
+  }
+
+  // 确认退出登录
+  confirmLogout(): void {
+    alert('已退出登录');
+    this.showLogout = false;
+    this.router.navigate(['/auth/login']);
+  }
+
+  // 菜单跳转(示例占位)
+  goToPage(page: string): void {
+    const pageNames: Record<string, string> = {
+      orders: '我的订单',
+      address: '我的地址',
+      favorites: '我的收藏',
+      invite: '邀请好友',
+      customerService: '客服与反馈',
+      settings: '设置',
+      about: '关于我们',
+      agreement: '用户协议',
+      privacy: '隐私政策'
+    };
+    alert(`跳转到${pageNames[page] || page}页面`);
+  }
+
+  // 显示所有徽章
+  showAllBadges(): void {
+    alert('查看所有成就徽章');
+  }
+
+  // 切换底部导航标签
+  switchTab(tab: string): void {
+    this.currentTab = tab;
+    console.log(`Switching to tab: ${tab}`);
+    
+    // 根据选中的标签导航到对应页面
+    switch (tab) {
+      case 'home':
+        this.router.navigate(['/consumer/home']);
+        break;
+      case 'booking':
+        this.router.navigate(['/consumer/booking-recycle']);
+        break;
+      case 'earnings':
+        this.router.navigate(['/consumer/earnings']);
+        break;
+      case 'mall':
+        this.router.navigate(['/consumer/points-mall']);
+        break;
+      case 'profile':
+        // 已经在个人中心页面,不需要导航
+        break;
+      default:
+        console.warn(`Unknown tab: ${tab}`);
+    }
+  }
 }

+ 1 - 1
src/app/government/ai-decision-assistant/ai-decision-assistant.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './ai-decision-assistant.html',
   styleUrl: './ai-decision-assistant.scss'
 })
-export class AiDecisionAssistantComponent {
+export class AiDecisionAssistant {
   constructor() {}
 }

+ 1 - 1
src/app/government/government-center/government-center.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './government-center.html',
   styleUrl: './government-center.scss'
 })
-export class GovernmentCenterComponent {
+export class GovernmentCenter {
   constructor() {}
 }

+ 1 - 1
src/app/government/industry-analysis/industry-analysis.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './industry-analysis.html',
   styleUrl: './industry-analysis.scss'
 })
-export class IndustryAnalysisComponent {
+export class IndustryAnalysis {
   constructor() {}
 }

+ 1 - 1
src/app/government/subsidy-management/subsidy-management.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './subsidy-management.html',
   styleUrl: './subsidy-management.scss'
 })
-export class SubsidyManagementComponent {
+export class SubsidyManagement {
   constructor() {}
 }

+ 1 - 1
src/app/government/supervision-overview/supervision-overview.ts

@@ -8,6 +8,6 @@ import { RouterModule } from '@angular/router';
   templateUrl: './supervision-overview.html',
   styleUrl: './supervision-overview.scss'
 })
-export class SupervisionOverviewComponent {
+export class SupervisionOverview {
   constructor() {}
 }

+ 22 - 0
src/app/shared/bottom-nav/bottom-nav.component.html

@@ -0,0 +1,22 @@
+<div class="bottom-nav">
+  <div class="nav-item" [class.active]="activeTab === 'home'" (click)="navigate('home')">
+    <div class="nav-icon"><i class="fas fa-home"></i></div>
+    <div>首页</div>
+  </div>
+  <div class="nav-item" [class.active]="activeTab === 'booking'" (click)="navigate('booking')">
+    <div class="nav-icon"><i class="fas fa-calendar-alt"></i></div>
+    <div>预约</div>
+  </div>
+  <div class="nav-item" [class.active]="activeTab === 'earnings'" (click)="navigate('earnings')">
+    <div class="nav-icon"><i class="fas fa-coins"></i></div>
+    <div>收益</div>
+  </div>
+  <div class="nav-item" [class.active]="activeTab === 'mall'" (click)="navigate('mall')">
+    <div class="nav-icon"><i class="fas fa-store"></i></div>
+    <div>商城</div>
+  </div>
+  <div class="nav-item" [class.active]="activeTab === 'profile'" (click)="navigate('profile')">
+    <div class="nav-icon"><i class="fas fa-user"></i></div>
+    <div>我的</div>
+  </div>
+</div>

+ 56 - 0
src/app/shared/bottom-nav/bottom-nav.component.scss

@@ -0,0 +1,56 @@
+.bottom-nav {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background: #fff;
+  display: grid;
+  grid-template-columns: repeat(5, 1fr);
+  align-items: center;
+  padding: 8px env(safe-area-inset-bottom) 10px;
+  box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
+  z-index: 1000;
+}
+
+.nav-item {
+  text-align: center;
+  color: #6c757d;
+  font-size: 12px;
+  user-select: none;
+}
+
+.nav-icon {
+  width: 34px;
+  height: 34px;
+  background: #f8f9fa;
+  border-radius: 50%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin: 0 auto 4px auto;
+  transition: transform 0.2s ease, background 0.2s ease, color 0.2s ease;
+
+  i {
+    font-size: 16px;
+  }
+}
+
+.nav-item.active {
+  color: #2e7d32;
+}
+
+.nav-item.active .nav-icon {
+  background: linear-gradient(135deg, #2e7d32, #43a047);
+  color: #fff;
+  transform: scale(1.06);
+}
+
+@media (max-width: 360px) {
+  .nav-icon {
+    width: 30px;
+    height: 30px;
+  }
+  .nav-item div:last-child {
+    font-size: 10px;
+  }
+}

+ 37 - 0
src/app/shared/bottom-nav/bottom-nav.component.ts

@@ -0,0 +1,37 @@
+import { Component, Input } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Router, RouterModule } from '@angular/router';
+
+@Component({
+  selector: 'app-bottom-nav',
+  standalone: true,
+  imports: [CommonModule, RouterModule],
+  templateUrl: './bottom-nav.component.html',
+  styleUrls: ['./bottom-nav.component.scss']
+})
+export class BottomNavComponent {
+  @Input() activeTab: 'home' | 'booking' | 'earnings' | 'mall' | 'profile' = 'home';
+
+  constructor(private router: Router) {}
+
+  navigate(tab: 'home' | 'booking' | 'earnings' | 'mall' | 'profile') {
+    if (this.activeTab === tab) return;
+    switch (tab) {
+      case 'home':
+        this.router.navigate(['/consumer/home']);
+        break;
+      case 'booking':
+        this.router.navigate(['/consumer/booking-recycle']);
+        break;
+      case 'earnings':
+        this.router.navigate(['/consumer/earnings']);
+        break;
+      case 'mall':
+        this.router.navigate(['/consumer/points-mall']);
+        break;
+      case 'profile':
+        this.router.navigate(['/consumer/profile']);
+        break;
+    }
+  }
+}

+ 1 - 0
src/index.html

@@ -6,6 +6,7 @@
   <base href="/">
   <meta name="viewport" content="width=device-width, initial-scale=1">
   <link rel="icon" type="image/x-icon" href="favicon.ico">
+  <!-- 使用本地依赖的Font Awesome,避免CDN字体加载错误 -->
 </head>
 <body>
   <app-root></app-root>

+ 2 - 1
src/styles.scss

@@ -1 +1,2 @@
-/* You can add global styles to this file, and also import other style files */
+/* 全局样式与第三方库导入 */
+@import '@fortawesome/fontawesome-free/css/all.min.css';

部分文件因文件數量過多而無法顯示