# 前端链接访问示例

## 概述
当用户访问链接页面时（如 `https://你的域名/ABC12345`），前端需要自动请求后端获取链接的详细信息，并根据状态显示相应的内容。

## 接口说明

### 1. 获取链接状态（主要接口）
```
GET /api/link/{codeNo}/status
```

**响应示例：**
```json
{
    "codeNo": "ABC12345",
    "batchId": 123,
    "status": "NEW",
    "statusDesc": "新建",
    "expireAt": "2024-01-15T16:30:00",
    "isExpired": false,
    "remainingSeconds": 3600,
    "quantity": 50,
    "times": 10,
    "totalPoints": 500,
    "region": null,
    "machineId": null,
    "loginAt": null,
    "createdAt": "2024-01-15T12:00:00",
    "updatedAt": "2024-01-15T12:00:00"
}
```

### 2. 检查链接是否存在
```
GET /api/link/{codeNo}/exists
```

**响应：** `true` 或 `false`

### 3. 检查链接是否有效
```
GET /api/link/{codeNo}/valid
```

**响应：** `true` 或 `false`

## 前端实现示例

### React 组件示例

```jsx
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';

const LinkPage = () => {
    const { codeNo } = useParams();
    const [linkStatus, setLinkStatus] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        fetchLinkStatus();
    }, [codeNo]);

    const fetchLinkStatus = async () => {
        try {
            setLoading(true);
            const response = await fetch(`/api/link/${codeNo}/status`);
            
            if (!response.ok) {
                if (response.status === 404) {
                    setError('链接不存在');
                } else {
                    setError('获取链接信息失败');
                }
                return;
            }

            const data = await response.json();
            setLinkStatus(data);
        } catch (err) {
            setError('网络错误');
            console.error('获取链接状态失败:', err);
        } finally {
            setLoading(false);
        }
    };

    const formatTime = (seconds) => {
        if (seconds <= 0) return '已过期';
        
        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        const secs = seconds % 60;
        
        if (hours > 0) {
            return `${hours}小时${minutes}分钟`;
        } else if (minutes > 0) {
            return `${minutes}分钟${secs}秒`;
        } else {
            return `${secs}秒`;
        }
    };

    if (loading) {
        return <div className="loading">加载中...</div>;
    }

    if (error) {
        return (
            <div className="error">
                <h2>链接错误</h2>
                <p>{error}</p>
                <p>链接编号: {codeNo}</p>
            </div>
        );
    }

    if (!linkStatus) {
        return <div>未找到链接信息</div>;
    }

    return (
        <div className="link-page">
            <div className="link-header">
                <h1>游戏任务链接</h1>
                <div className="link-code">链接编号: {linkStatus.codeNo}</div>
            </div>

            <div className="link-status">
                <div className="status-item">
                    <span className="label">状态:</span>
                    <span className={`value status-${linkStatus.status.toLowerCase()}`}>
                        {linkStatus.statusDesc}
                    </span>
                </div>

                <div className="status-item">
                    <span className="label">任务信息:</span>
                    <span className="value">
                        打{linkStatus.times}次副本，每次{linkStatus.quantity}点
                        （总计{linkStatus.totalPoints}点）
                    </span>
                </div>

                <div className="status-item">
                    <span className="label">过期时间:</span>
                    <span className="value">
                        {linkStatus.expireAt}
                    </span>
                </div>

                <div className="status-item">
                    <span className="label">剩余时间:</span>
                    <span className={`value ${linkStatus.isExpired ? 'expired' : ''}`}>
                        {formatTime(linkStatus.remainingSeconds)}
                    </span>
                </div>
            </div>

            {linkStatus.isExpired && (
                <div className="expired-notice">
                    <p>⚠️ 此链接已过期，无法使用</p>
                </div>
            )}

            {!linkStatus.isExpired && linkStatus.status === 'NEW' && (
                <div className="action-section">
                    <h3>开始任务</h3>
                    <p>点击下方按钮开始执行任务</p>
                    <button className="start-btn" onClick={() => startTask()}>
                        开始任务
                    </button>
                </div>
            )}

            {linkStatus.status === 'USING' && (
                <div className="task-progress">
                    <h3>任务进行中</h3>
                    <p>请按照提示完成游戏任务</p>
                    <div className="progress-bar">
                        <div className="progress-fill" style={{width: '50%'}}></div>
                    </div>
                </div>
            )}

            {linkStatus.status === 'LOGGED_IN' && (
                <div className="task-complete">
                    <h3>任务完成</h3>
                    <p>恭喜！任务已完成，奖励点数已发放</p>
                    <div className="reward-info">
                        获得奖励: {linkStatus.totalPoints} 点
                    </div>
                </div>
            )}

            <div className="qr-section">
                <h3>扫码访问</h3>
                <img 
                    src={`/api/link/${codeNo}/qr.png`} 
                    alt="二维码"
                    className="qr-code"
                />
                <p>使用手机扫描二维码访问</p>
            </div>
        </div>
    );
};

const startTask = () => {
    // 实现开始任务的逻辑
    console.log('开始任务');
};

export default LinkPage;
```

### Vue 组件示例

```vue
<template>
  <div class="link-page">
    <div v-if="loading" class="loading">加载中...</div>
    
    <div v-else-if="error" class="error">
      <h2>链接错误</h2>
      <p>{{ error }}</p>
      <p>链接编号: {{ codeNo }}</p>
    </div>
    
    <div v-else-if="linkStatus" class="link-content">
      <div class="link-header">
        <h1>游戏任务链接</h1>
        <div class="link-code">链接编号: {{ linkStatus.codeNo }}</div>
      </div>

      <div class="link-status">
        <div class="status-item">
          <span class="label">状态:</span>
          <span :class="['value', `status-${linkStatus.status.toLowerCase()}`]">
            {{ linkStatus.statusDesc }}
          </span>
        </div>

        <div class="status-item">
          <span class="label">任务信息:</span>
          <span class="value">
            打{{ linkStatus.times }}次副本，每次{{ linkStatus.quantity }}点
            （总计{{ linkStatus.totalPoints }}点）
          </span>
        </div>

        <div class="status-item">
          <span class="label">剩余时间:</span>
          <span :class="['value', { 'expired': linkStatus.isExpired }]">
            {{ formatTime(linkStatus.remainingSeconds) }}
          </span>
        </div>
      </div>

      <div v-if="linkStatus.isExpired" class="expired-notice">
        <p>⚠️ 此链接已过期，无法使用</p>
      </div>

      <div v-if="!linkStatus.isExpired && linkStatus.status === 'NEW'" class="action-section">
        <h3>开始任务</h3>
        <button class="start-btn" @click="startTask">开始任务</button>
      </div>

      <div class="qr-section">
        <h3>扫码访问</h3>
        <img 
          :src="`/api/link/${codeNo}/qr.png`" 
          alt="二维码"
          class="qr-code"
        />
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'LinkPage',
  data() {
    return {
      codeNo: '',
      linkStatus: null,
      loading: true,
      error: null
    };
  },
  
  async mounted() {
    this.codeNo = this.$route.params.codeNo;
    await this.fetchLinkStatus();
  },
  
  methods: {
    async fetchLinkStatus() {
      try {
        this.loading = true;
        const response = await fetch(`/api/link/${this.codeNo}/status`);
        
        if (!response.ok) {
          if (response.status === 404) {
            this.error = '链接不存在';
          } else {
            this.error = '获取链接信息失败';
          }
          return;
        }
        
        this.linkStatus = await response.json();
      } catch (err) {
        this.error = '网络错误';
        console.error('获取链接状态失败:', err);
      } finally {
        this.loading = false;
      }
    },
    
    formatTime(seconds) {
      if (seconds <= 0) return '已过期';
      
      const hours = Math.floor(seconds / 3600);
      const minutes = Math.floor((seconds % 3600) / 60);
      const secs = seconds % 60;
      
      if (hours > 0) {
        return `${hours}小时${minutes}分钟`;
      } else if (minutes > 0) {
        return `${minutes}分钟${secs}秒`;
      } else {
        return `${secs}秒`;
      }
    },
    
    startTask() {
      // 实现开始任务的逻辑
      console.log('开始任务');
    }
  }
};
</script>
```

## 路由配置

### React Router
```jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import LinkPage from './components/LinkPage';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/:codeNo" element={<LinkPage />} />
        {/* 其他路由 */}
      </Routes>
    </BrowserRouter>
  );
}
```

### Vue Router
```javascript
import { createRouter, createWebHistory } from 'vue-router';
import LinkPage from '@/components/LinkPage.vue';

const routes = [
  {
    path: '/:codeNo',
    name: 'LinkPage',
    component: LinkPage
  }
];

const router = createRouter({
  history: createWebHistory(),
  routes
});

export default router;
```

## 使用流程

1. **用户访问链接**：`https://你的域名/ABC12345`
2. **前端自动请求**：调用 `/api/link/ABC12345/status` 获取链接信息
3. **显示相应内容**：根据链接状态显示不同的界面
4. **实时更新**：可以定时刷新状态，显示剩余时间等

## 注意事项

1. **错误处理**：处理链接不存在、已过期等情况
2. **加载状态**：显示加载中的状态，提升用户体验
3. **响应式设计**：确保在不同设备上都能正常显示
4. **缓存策略**：可以适当缓存链接状态，减少请求次数
5. **实时更新**：对于进行中的任务，可以定时刷新状态
