283 lines
13 KiB
PHP
283 lines
13 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/app.php';
|
|
|
|
$user = current_user();
|
|
$taskSlug = (string) ($_GET['task'] ?? '');
|
|
$selectedCategory = (string) ($_GET['category'] ?? 'all');
|
|
$categories = task_category_options();
|
|
if (!isset($categories[$selectedCategory])) {
|
|
$selectedCategory = 'all';
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
try {
|
|
verify_csrf_or_fail();
|
|
$user = require_user();
|
|
$task = task_by_slug((string) ($_POST['task_slug'] ?? $taskSlug));
|
|
if (!$task) {
|
|
throw new RuntimeException('任务不存在,请返回任务大厅重试。');
|
|
}
|
|
|
|
$action = (string) ($_POST['action'] ?? '');
|
|
if ($action === 'claim_task') {
|
|
$order = create_task_order((int) $user['id'], $task);
|
|
flash('success', '任务已领取,倒计时已开始。订单 #' . ($order['id'] ?? '') . ' 已创建。');
|
|
redirect('task.php?task=' . urlencode((string) $task['slug']));
|
|
}
|
|
|
|
if ($action === 'submit_order') {
|
|
$orderId = (int) ($_POST['order_id'] ?? 0);
|
|
$order = submit_task_order((int) $user['id'], $orderId, (string) ($_POST['proof_note'] ?? ''));
|
|
flash('success', '任务已提交审核,佣金已进入冻结余额。');
|
|
redirect('order.php?id=' . urlencode((string) ($order['id'] ?? $orderId)));
|
|
}
|
|
} catch (Throwable $exception) {
|
|
flash('danger', $exception->getMessage());
|
|
if ($taskSlug !== '') {
|
|
redirect('task.php?task=' . urlencode($taskSlug));
|
|
}
|
|
redirect('task.php');
|
|
}
|
|
}
|
|
|
|
$task = $taskSlug !== '' ? task_by_slug($taskSlug) : null;
|
|
if ($taskSlug !== '' && !$task) {
|
|
http_response_code(404);
|
|
render_layout_start('任务不存在', '未找到指定任务。', 'tasks');
|
|
?>
|
|
<section class="app-page-section">
|
|
<article class="app-card">
|
|
<div class="tiny-eyebrow">404</div>
|
|
<h1 class="app-section-title mb-2">任务不存在</h1>
|
|
<p class="app-copy mb-3">请返回任务大厅选择一个有效任务。</p>
|
|
<a class="btn btn-gradient" href="task.php">返回任务大厅</a>
|
|
</article>
|
|
</section>
|
|
<?php
|
|
render_layout_end();
|
|
exit;
|
|
}
|
|
|
|
$previewNotice = !$user;
|
|
$allTasks = array_values(task_catalog());
|
|
$activeOrdersBySlug = [];
|
|
if ($user) {
|
|
foreach (get_user_orders((int) $user['id'], 30) as $orderRow) {
|
|
$status = (string) ($orderRow['status'] ?? '');
|
|
$slug = (string) ($orderRow['task_slug'] ?? '');
|
|
if ($slug !== '' && in_array($status, ['claimed', 'pending_review'], true) && !isset($activeOrdersBySlug[$slug])) {
|
|
$activeOrdersBySlug[$slug] = $orderRow;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!$task) {
|
|
$filteredTasks = array_values(array_filter($allTasks, static function (array $entry) use ($selectedCategory): bool {
|
|
if ($selectedCategory === 'all') {
|
|
return true;
|
|
}
|
|
return task_visual_meta($entry)['category'] === $selectedCategory;
|
|
}));
|
|
|
|
render_layout_start('任务', '任务大厅页,支持分类筛选、任务详情入口与领取状态展示。', 'tasks');
|
|
?>
|
|
<section class="app-page-section">
|
|
<article class="app-card gradient-card slim-hero-card">
|
|
<div class="tiny-eyebrow">任务大厅</div>
|
|
<h1 class="app-hero-title compact-title">选择你想完成的任务</h1>
|
|
<p class="app-hero-copy mb-0">视频、点赞、社媒、网站、应用任务都能从这里进入。</p>
|
|
<?php if ($previewNotice): ?>
|
|
<div class="app-inline-note mt-3">现在是游客预览模式:可以浏览 5 个页面,登录后才能正式领取任务。</div>
|
|
<?php endif; ?>
|
|
</article>
|
|
</section>
|
|
|
|
<section class="app-page-section">
|
|
<div class="category-tabs" aria-label="任务分类">
|
|
<?php foreach ($categories as $key => $label): ?>
|
|
<a class="category-tab<?= $selectedCategory === $key ? ' active' : '' ?>" href="task.php<?= $key === 'all' ? '' : '?category=' . urlencode($key) ?>"><?= h($label) ?></a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="app-page-section">
|
|
<div class="app-task-list">
|
|
<?php foreach ($filteredTasks as $entry): ?>
|
|
<?php
|
|
$meta = task_visual_meta($entry);
|
|
$activeOrder = $user ? ($activeOrdersBySlug[(string) $entry['slug']] ?? null) : null;
|
|
$canAccess = $user ? can_access_task($user, $entry) : ((int) $entry['vip_required'] === 0);
|
|
?>
|
|
<article class="app-card task-list-row">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<span class="task-platform-icon <?= h((string) $meta['accent']) ?>"><?= app_icon_svg((string) $meta['icon']) ?></span>
|
|
<div class="flex-grow-1 min-w-0">
|
|
<div class="task-row-title"><?= h((string) $entry['title']) ?></div>
|
|
<div class="task-row-subtitle"><?= h((string) $meta['brand']) ?> · <?= h((string) $meta['hint']) ?></div>
|
|
</div>
|
|
<div class="text-end">
|
|
<div class="reward-strong">+<?= h(number_format((float) $entry['reward'], 2)) ?></div>
|
|
<div class="list-meta-line">USDT</div>
|
|
</div>
|
|
</div>
|
|
<div class="task-list-footer mt-3">
|
|
<div class="d-flex flex-wrap gap-2">
|
|
<span class="tag-chip"><?= h('VIP' . (string) $entry['vip_required']) ?></span>
|
|
<span class="tag-chip secondary-chip"><?= h((string) $categories[$meta['category']] ?? '任务') ?></span>
|
|
<?php if ($activeOrder): ?>
|
|
<?= render_status_badge((string) $activeOrder['status']) ?>
|
|
<?php elseif (!$canAccess): ?>
|
|
<span class="status-pill tone-muted">未解锁</span>
|
|
<?php else: ?>
|
|
<span class="status-pill tone-success">可领取</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<a class="btn btn-gradient btn-sm px-3" href="task.php?task=<?= h((string) $entry['slug']) ?>">查看</a>
|
|
</div>
|
|
</article>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</section>
|
|
<?php
|
|
render_layout_end();
|
|
exit;
|
|
}
|
|
|
|
$meta = task_visual_meta($task);
|
|
$activeOrder = $user ? active_order_for_task((int) $user['id'], (string) $task['slug']) : null;
|
|
$history = $user ? get_user_orders_for_task((int) $user['id'], (string) $task['slug'], 5) : [];
|
|
$canAccess = $user ? can_access_task($user, $task) : ((int) $task['vip_required'] === 0);
|
|
$unlockTimestamp = $activeOrder ? strtotime((string) $activeOrder['claimed_at']) + (int) $activeOrder['countdown_seconds'] : null;
|
|
|
|
render_layout_start((string) $task['title'], '任务详情页,包含任务说明、倒计时与提交审核入口。', 'tasks');
|
|
?>
|
|
<section class="app-page-section">
|
|
<article class="app-card gradient-card detail-hero-card">
|
|
<div class="task-detail-head">
|
|
<span class="task-platform-icon large-icon <?= h((string) $meta['accent']) ?>"><?= app_icon_svg((string) $meta['icon']) ?></span>
|
|
<div class="flex-grow-1">
|
|
<div class="tiny-eyebrow"><?= h((string) $meta['brand']) ?> · <?= h((string) $task['type']) ?></div>
|
|
<h1 class="app-section-title mb-2"><?= h((string) $task['title']) ?></h1>
|
|
<p class="app-copy mb-0"><?= h((string) $task['summary']) ?></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="detail-metrics mt-3">
|
|
<div class="detail-metric-box">
|
|
<div class="mini-label">奖励金额</div>
|
|
<div class="detail-amount">+<?= h(number_format((float) $task['reward'], 2)) ?> USDT</div>
|
|
</div>
|
|
<div class="detail-meta-grid mt-3">
|
|
<div>
|
|
<div class="mini-label">任务要求</div>
|
|
<div class="detail-mini-value">VIP<?= h((string) $task['vip_required']) ?></div>
|
|
</div>
|
|
<div>
|
|
<div class="mini-label">倒计时</div>
|
|
<div class="detail-mini-value"><?= h((string) $task['countdown']) ?> 秒</div>
|
|
</div>
|
|
<div>
|
|
<div class="mini-label">当前状态</div>
|
|
<div class="detail-mini-value">
|
|
<?php if ($activeOrder): ?>
|
|
<?= render_status_badge((string) $activeOrder['status']) ?>
|
|
<?php elseif ($canAccess): ?>
|
|
<span class="status-pill tone-success">可领取</span>
|
|
<?php else: ?>
|
|
<span class="status-pill tone-muted">需升级 VIP</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
|
|
<section class="app-page-section">
|
|
<article class="app-card">
|
|
<div class="section-heading-app mb-3">
|
|
<div class="tiny-eyebrow">任务要求</div>
|
|
<h2 class="app-section-title">操作步骤</h2>
|
|
</div>
|
|
<div class="timeline-mini-list">
|
|
<?php foreach ($task['steps'] as $index => $step): ?>
|
|
<div class="timeline-mini-item">
|
|
<span class="timeline-mini-index"><?= h((string) ($index + 1)) ?></span>
|
|
<div>
|
|
<div class="list-title-strong">步骤 <?= h((string) ($index + 1)) ?></div>
|
|
<div class="list-meta-line"><?= h((string) $step) ?></div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
|
|
<section class="app-page-section">
|
|
<article class="app-card">
|
|
<div class="section-heading-app mb-3">
|
|
<div class="tiny-eyebrow">开始任务</div>
|
|
<h2 class="app-section-title">领取与提交</h2>
|
|
</div>
|
|
|
|
<?php if (!$user): ?>
|
|
<div class="app-inline-note mb-3">你正在浏览视觉预览版。登录后才可以正式领取并提交任务。</div>
|
|
<a class="btn btn-gradient w-100" href="<?= h(login_page_url(current_request_target())) ?>">登录后开始任务</a>
|
|
<?php elseif (!$canAccess): ?>
|
|
<div class="app-inline-note mb-3">当前账号为 <?= h(vip_info((int) $user['vip_level'])['name']) ?>,该任务需要 VIP<?= h((string) $task['vip_required']) ?>。</div>
|
|
<a class="btn btn-gradient w-100" href="vip.php?level=<?= h((string) $task['vip_required']) ?>">去开通 VIP<?= h((string) $task['vip_required']) ?></a>
|
|
<?php elseif (!$activeOrder): ?>
|
|
<form method="post" class="d-grid gap-3">
|
|
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
|
<input type="hidden" name="action" value="claim_task">
|
|
<input type="hidden" name="task_slug" value="<?= h((string) $task['slug']) ?>">
|
|
<button class="btn btn-gradient" type="submit">开始任务</button>
|
|
</form>
|
|
<?php elseif ((string) $activeOrder['status'] === 'claimed'): ?>
|
|
<div class="countdown-card front-countdown-card mb-3" data-countdown-card>
|
|
<div class="mini-label">倒计时剩余</div>
|
|
<div class="countdown-display" data-countdown="<?= h((string) $unlockTimestamp) ?>" data-countdown-target="#submit-order-button"><?= h((string) max(0, (int) ($unlockTimestamp - time()))) ?> 秒</div>
|
|
<div class="list-meta-line mt-2">时间到之后才可以提交,服务端也会再次验证。</div>
|
|
</div>
|
|
<form method="post" class="d-grid gap-3">
|
|
<input type="hidden" name="csrf_token" value="<?= h(csrf_token()) ?>">
|
|
<input type="hidden" name="action" value="submit_order">
|
|
<input type="hidden" name="task_slug" value="<?= h((string) $task['slug']) ?>">
|
|
<input type="hidden" name="order_id" value="<?= h((string) $activeOrder['id']) ?>">
|
|
<div>
|
|
<label class="form-label" for="proof-note">完成备注</label>
|
|
<textarea class="form-control" id="proof-note" name="proof_note" rows="4" placeholder="例如:已观看 60 秒,已完成点赞与停留" required></textarea>
|
|
</div>
|
|
<button class="btn btn-gradient" id="submit-order-button" type="submit" disabled>提交审核</button>
|
|
</form>
|
|
<?php else: ?>
|
|
<div class="app-inline-note mb-3">该任务已提交审核或已处理完成,你可以查看订单详情了解最新状态。</div>
|
|
<a class="btn btn-gradient w-100" href="order.php?id=<?= h((string) $activeOrder['id']) ?>">查看订单详情</a>
|
|
<?php endif; ?>
|
|
</article>
|
|
</section>
|
|
|
|
<?php if ($history): ?>
|
|
<section class="app-page-section">
|
|
<article class="app-card">
|
|
<div class="section-heading-app mb-3">
|
|
<div class="tiny-eyebrow">任务历史</div>
|
|
<h2 class="app-section-title">最近记录</h2>
|
|
</div>
|
|
<div class="app-list-stack">
|
|
<?php foreach ($history as $record): ?>
|
|
<a class="app-list-item" href="order.php?id=<?= h((string) $record['id']) ?>">
|
|
<span>
|
|
<span class="list-title-strong">订单 #<?= h((string) $record['id']) ?></span>
|
|
<span class="list-meta-line"><?= h(format_datetime((string) $record['claimed_at'])) ?> · <?= h(format_usdt($record['reward_usdt'])) ?></span>
|
|
</span>
|
|
<span><?= render_status_badge((string) $record['status']) ?></span>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</article>
|
|
</section>
|
|
<?php endif; ?>
|
|
<?php render_layout_end(); ?>
|