# 租户登录使用指南

## 概述

系统已完整支持多租户登录功能，每个租户可以独立访问系统，数据完全隔离。

## 租户识别方式

系统支持以下方式识别租户：

### 1. URL参数方式（推荐）

在登录页面URL中添加 `tenant` 参数：

```
http://your-domain.com/login?tenant=tenant-a
```

登录页面会自动识别租户编码，并在登录时自动发送。

### 2. 登录表单输入

如果URL中没有租户参数，登录页面会显示租户编码输入框，用户可以手动输入。

### 3. 请求头方式

前端会自动将租户信息添加到所有API请求的请求头中：
- `X-Tenant-Code`: 租户编码
- `X-Tenant-Id`: 租户ID

## 使用流程

### 方式一：通过URL参数访问（推荐）

1. **访问租户登录页面**
   ```
   http://your-domain.com/login?tenant=tenant-a
   ```

2. **输入用户名和密码**
   - 用户名：租户内的用户名
   - 密码：用户密码
   - 租户编码：已自动填充（从URL参数）

3. **登录成功**
   - 系统自动保存租户信息到 localStorage
   - 后续所有API请求都会自动携带租户信息
   - 用户只能看到和操作自己租户的数据

### 方式二：手动输入租户编码

1. **访问登录页面**
   ```
   http://your-domain.com/login
   ```

2. **输入租户信息**
   - 租户编码：输入租户编码（如：`tenant-a`）
   - 用户名：租户内的用户名
   - 密码：用户密码

3. **登录成功**
   - 系统保存租户信息
   - 后续请求自动携带租户信息

## 后端API使用

### 登录接口

**请求：**
```bash
POST /api/auth/login
Content-Type: application/json

{
  "username": "user1",
  "password": "password123",
  "tenantCode": "tenant-a"  // 可选，也可以从请求头获取
}
```

**或者通过请求头：**
```bash
POST /api/auth/login
X-Tenant-Code: tenant-a
Content-Type: application/json

{
  "username": "user1",
  "password": "password123"
}
```

**响应：**
```json
{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "user": {
    "id": 1,
    "username": "user1",
    "nickname": "用户1",
    "email": "user1@example.com",
    "tenantId": 2,
    "tenantCode": "tenant-a",
    "roles": ["admin"],
    "permissions": ["user:read", "user:create", ...]
  }
}
```

### 其他API请求

登录后，所有API请求都会自动携带租户信息（通过JWT Token或请求头），后端会自动过滤数据：

```bash
GET /api/users
Authorization: Bearer <token>
X-Tenant-Code: tenant-a  # 自动添加
```

返回的数据只会包含该租户的用户。

## 前端实现细节

### 1. 登录页面自动识别租户

登录页面 (`Login.vue`) 会：
- 从URL参数 `?tenant=xxx` 获取租户编码
- 如果URL中没有，从 localStorage 读取之前保存的租户编码
- 如果都没有，显示租户输入框

### 2. 请求拦截器自动添加租户信息

所有API请求都会自动添加租户信息到请求头：

```typescript
// utils/request.ts
service.interceptors.request.use((config) => {
  const tenantCode = getTenantCode();
  const tenantId = getTenantId();
  
  if (tenantCode) {
    config.headers['X-Tenant-Code'] = tenantCode;
  }
  if (tenantId) {
    config.headers['X-Tenant-Id'] = tenantId;
  }
  
  return config;
});
```

### 3. 登录后保存租户信息

登录成功后，系统会自动保存：
- Token
- 租户编码 (tenantCode)
- 租户ID (tenantId)

这些信息保存在 localStorage 中，页面刷新后仍然有效。

## 示例场景

### 场景1：租户A的用户登录

1. 访问：`http://your-domain.com/login?tenant=tenant-a`
2. 输入用户名和密码
3. 登录后只能看到租户A的数据

### 场景2：租户B的用户登录

1. 访问：`http://your-domain.com/login?tenant=tenant-b`
2. 输入用户名和密码
3. 登录后只能看到租户B的数据
4. 租户A的数据完全不可见

### 场景3：超级租户管理员登录

1. 访问：`http://your-domain.com/login?tenant=super`
2. 使用超级管理员账号登录
3. 可以管理所有租户

## 注意事项

1. **租户编码必须唯一**：每个租户都有唯一的编码（code）
2. **用户属于特定租户**：用户只能登录到自己所属的租户
3. **数据完全隔离**：不同租户的数据完全隔离，无法互相访问
4. **租户信息持久化**：登录后租户信息保存在 localStorage，刷新页面不会丢失
5. **切换租户**：如果需要切换租户，需要先登出，然后使用新的租户编码登录

## 故障排查

### 问题1：登录时提示"无法确定租户信息"

**原因**：没有提供租户编码或租户ID

**解决**：
- 在URL中添加 `?tenant=xxx` 参数
- 或者在登录表单中输入租户编码
- 或者通过请求头 `X-Tenant-Code` 提供

### 问题2：登录时提示"用户不属于该租户"

**原因**：用户不属于指定的租户

**解决**：
- 确认租户编码是否正确
- 确认用户是否属于该租户
- 联系管理员检查用户和租户的关联关系

### 问题3：登录后看不到数据

**原因**：可能是租户信息没有正确传递

**解决**：
- 检查浏览器控制台的网络请求，确认请求头中是否包含 `X-Tenant-Code`
- 检查 localStorage 中是否保存了租户信息
- 确认后端是否正确识别了租户

## 开发建议

1. **使用URL参数方式**：这是最用户友好的方式，用户只需要记住租户的访问链接
2. **提供租户选择器**：如果系统需要支持租户切换，可以在前端添加租户选择器
3. **错误提示优化**：当租户信息缺失时，提供清晰的错误提示
4. **租户信息显示**：在用户界面显示当前租户信息，让用户知道自己在哪个租户下操作

