完善功能
This commit is contained in:
29
web10/resources/views/frontend/article/index.blade.php
Normal file
29
web10/resources/views/frontend/article/index.blade.php
Normal file
@@ -0,0 +1,29 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>文章</h1>
|
||||
<p>AI 工具资讯、评测与实用教程。</p>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'list', 'title' => '推广位'])
|
||||
|
||||
<div class="article-list">
|
||||
@forelse($articles as $article)
|
||||
<a class="article-item" href="{{ route('articles.show', $article->slug) }}">
|
||||
<div class="article-title">{{ $article->title }}</div>
|
||||
<div class="article-meta">
|
||||
<span>{{ $article->author ?? '官方' }}</span>
|
||||
<span>{{ optional($article->published_at)->format('Y-m-d') }}</span>
|
||||
</div>
|
||||
<div class="article-summary">{{ $article->summary }}</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="empty">暂无文章</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="pagination">
|
||||
{{ $articles->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
142
web10/resources/views/frontend/article/show.blade.php
Normal file
142
web10/resources/views/frontend/article/show.blade.php
Normal file
@@ -0,0 +1,142 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
$title = $article->seo_title ?: $article->title;
|
||||
$description = $article->seo_description ?: $article->summary;
|
||||
$ogType = 'article';
|
||||
$ogImage = $article->cover ? Storage::url($article->cover) : null;
|
||||
@endphp
|
||||
|
||||
@push('head')
|
||||
<script type="application/ld+json">
|
||||
{!! json_encode([
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'Article',
|
||||
'headline' => $article->title,
|
||||
'description' => $article->summary,
|
||||
'datePublished' => optional($article->published_at)->toAtomString(),
|
||||
'author' => $article->author ? ['@type' => 'Person', 'name' => $article->author] : null,
|
||||
'mainEntityOfPage' => url()->current(),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) !!}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>{{ $article->title }}</h1>
|
||||
<p>{{ $article->summary }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="detail-grid">
|
||||
<div class="detail-main">
|
||||
<div class="article-meta">
|
||||
<span>{{ $article->author ?? '官方' }}</span>
|
||||
<span>{{ optional($article->published_at)->format('Y-m-d') }}</span>
|
||||
<span>浏览 {{ $article->view_count }}</span>
|
||||
</div>
|
||||
<div class="rich-text">{!! Str::markdown($article->content_md) !!}</div>
|
||||
</div>
|
||||
<div class="detail-side">
|
||||
@if($article->cover)
|
||||
<div class="detail-card">
|
||||
<img src="{{ Storage::url($article->cover) }}" alt="{{ $article->title }}" class="cover-image">
|
||||
</div>
|
||||
@endif
|
||||
<div class="detail-card">
|
||||
<h4>标签</h4>
|
||||
<div class="tag-cloud">
|
||||
@foreach($article->tags as $tag)
|
||||
<a href="{{ route('articles.index', ['tag' => $tag->slug]) }}" class="tag-chip">{{ $tag->name }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'detail', 'title' => '推广位'])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>相关文章</h2>
|
||||
</div>
|
||||
<div class="article-list">
|
||||
@foreach($relatedArticles as $item)
|
||||
<a class="article-item" href="{{ route('articles.show', $item->slug) }}">
|
||||
<div class="article-title">{{ $item->title }}</div>
|
||||
<div class="article-meta">
|
||||
<span>{{ optional($item->published_at)->format('Y-m-d') }}</span>
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@php
|
||||
$commentsEnabled = \App\Models\SiteSetting::value('comments_enabled', '1');
|
||||
@endphp
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>评论</h2>
|
||||
</div>
|
||||
|
||||
@if($commentsEnabled)
|
||||
@if(session('success'))
|
||||
<div class="notice success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="notice error">
|
||||
@foreach($errors->all() as $error)
|
||||
<div>{{ $error }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="comment-form" method="post" action="{{ route('comments.store') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="target_type" value="article">
|
||||
<input type="hidden" name="target_id" value="{{ $article->id }}">
|
||||
<div class="form-row">
|
||||
<input type="text" name="nickname" placeholder="昵称" required>
|
||||
<input type="email" name="email" placeholder="邮箱(可选)">
|
||||
</div>
|
||||
<textarea name="content" rows="4" placeholder="写下你的评论" required></textarea>
|
||||
<div class="form-row captcha-row">
|
||||
<input type="text" name="captcha" placeholder="验证码" required>
|
||||
<img src="{{ route('comments.captcha') }}" alt="验证码" onclick="this.src='{{ route('comments.captcha') }}?t=' + Date.now()" class="captcha-image">
|
||||
</div>
|
||||
<button type="submit" class="primary-button">提交评论</button>
|
||||
</form>
|
||||
|
||||
<div class="comment-list">
|
||||
@forelse($comments as $comment)
|
||||
<div class="comment-item">
|
||||
<div class="comment-header">
|
||||
<strong>{{ $comment->nickname }}</strong>
|
||||
<span>{{ $comment->created_at->format('Y-m-d H:i') }}</span>
|
||||
</div>
|
||||
<div class="comment-body">{{ $comment->content }}</div>
|
||||
<div class="comment-actions">
|
||||
<form method="post" action="{{ route('comments.like', $comment->id) }}">
|
||||
@csrf
|
||||
<button type="submit" class="like-button">点赞 {{ $comment->like_count }}</button>
|
||||
</form>
|
||||
</div>
|
||||
@if($comment->reply_content)
|
||||
<div class="comment-reply">
|
||||
<span>官方回复:</span>{{ $comment->reply_content }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@empty
|
||||
<div class="empty">暂无评论</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@else
|
||||
<div class="empty">评论已关闭</div>
|
||||
@endif
|
||||
</section>
|
||||
@endsection
|
||||
18
web10/resources/views/frontend/category/index.blade.php
Normal file
18
web10/resources/views/frontend/category/index.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>分类</h1>
|
||||
<p>按分类浏览 AI 工具与产品。</p>
|
||||
</div>
|
||||
|
||||
<div class="category-grid">
|
||||
@foreach($categories as $category)
|
||||
<a class="category-card" href="{{ route('categories.show', $category->slug) }}">
|
||||
<div class="category-card-title">{{ $category->name }}</div>
|
||||
<div class="category-card-desc">{{ $category->description }}</div>
|
||||
<div class="category-card-count">{{ $category->products_count }} 个产品</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endsection
|
||||
74
web10/resources/views/frontend/category/show.blade.php
Normal file
74
web10/resources/views/frontend/category/show.blade.php
Normal file
@@ -0,0 +1,74 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@php
|
||||
$viewMode = request('view', 'grid');
|
||||
$pricingOptions = [
|
||||
'' => '全部价格',
|
||||
'free' => '免费',
|
||||
'paid' => '付费',
|
||||
'subscription' => '订阅',
|
||||
'trial' => '试用',
|
||||
];
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>{{ $category->name }}</h1>
|
||||
<p>{{ $category->description }}</p>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'list', 'title' => '推广位'])
|
||||
|
||||
<form class="filter-bar" method="get">
|
||||
<input type="hidden" name="view" value="{{ $viewMode }}">
|
||||
<select name="tag">
|
||||
<option value="">全部标签</option>
|
||||
@foreach($tags as $tag)
|
||||
<option value="{{ $tag->slug }}" @selected($tagSlug === $tag->slug)>{{ $tag->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<select name="pricing">
|
||||
@foreach($pricingOptions as $value => $label)
|
||||
<option value="{{ $value }}" @selected($pricing === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="primary-button">筛选</button>
|
||||
</form>
|
||||
|
||||
<div class="view-toggle">
|
||||
<a href="{{ request()->fullUrlWithQuery(['view' => 'grid']) }}" class="{{ $viewMode === 'grid' ? 'active' : '' }}">网格</a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['view' => 'list']) }}" class="{{ $viewMode === 'list' ? 'active' : '' }}">列表</a>
|
||||
</div>
|
||||
|
||||
@if($products->total() > $moreThreshold)
|
||||
<div class="more-panel">
|
||||
<span>当前分类内容较多</span>
|
||||
<a href="{{ $products->nextPageUrl() ?? $products->url(1) }}" class="more-link">查看全部</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($viewMode === 'list')
|
||||
<div class="article-list">
|
||||
@forelse($products as $product)
|
||||
<a class="article-item" href="{{ route('products.show', $product->slug) }}">
|
||||
<div class="article-title">{{ $product->name }}</div>
|
||||
<div class="article-summary">{{ $product->summary }}</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="empty">暂无产品</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@else
|
||||
<div class="product-grid">
|
||||
@forelse($products as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@empty
|
||||
<div class="empty">暂无产品</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="pagination">
|
||||
{{ $products->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
62
web10/resources/views/frontend/home.blade.php
Normal file
62
web10/resources/views/frontend/home.blade.php
Normal file
@@ -0,0 +1,62 @@
|
||||
@extends('frontend.layouts.app')
|
||||
@section('content')
|
||||
<div class="home-hero">
|
||||
<div class="hero-text">
|
||||
<h1>发现优质 AI 工具与产品</h1>
|
||||
<p>精选高质量 AI 工具与产品,覆盖写作、设计、编程与办公等场景。</p>
|
||||
</div>
|
||||
<form class="search-bar" action="{{ route('search.index') }}" method="get">
|
||||
<input type="text" name="q" placeholder="搜索 AI 工具、产品、标签" aria-label="搜索">
|
||||
<button type="submit">搜索</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'home', 'title' => '推广位'])
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>热门推荐</h2>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
@forelse($featuredProducts as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@empty
|
||||
<div class="empty">暂无热门推荐</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>新加产品</h2>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
@forelse($newProducts as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@empty
|
||||
<div class="empty">暂无新加产品</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>全部分类</h2>
|
||||
</div>
|
||||
<div class="category-blocks">
|
||||
@foreach($categories as $category)
|
||||
<div class="category-block">
|
||||
<div class="category-block-header">
|
||||
<h3>{{ $category->name }}</h3>
|
||||
<a href="{{ route('categories.show', $category->slug) }}" class="more-link">更多</a>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
@foreach($category->products as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
@endsection
|
||||
58
web10/resources/views/frontend/layouts/app.blade.php
Normal file
58
web10/resources/views/frontend/layouts/app.blade.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{ $title ?? $siteTitle }}</title>
|
||||
<meta name="description" content="{{ $description ?? $siteDescription }}">
|
||||
<meta property="og:title" content="{{ $title ?? $siteTitle }}">
|
||||
<meta property="og:description" content="{{ $description ?? $siteDescription }}">
|
||||
<meta property="og:type" content="{{ $ogType ?? 'website' }}">
|
||||
<meta property="og:url" content="{{ url()->current() }}">
|
||||
@if(!empty($ogImage))
|
||||
<meta property="og:image" content="{{ $ogImage }}">
|
||||
@endif
|
||||
<script type="application/ld+json">
|
||||
{!! json_encode([
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'WebSite',
|
||||
'name' => $siteTitle,
|
||||
'url' => url('/'),
|
||||
'potentialAction' => [
|
||||
'@type' => 'SearchAction',
|
||||
'target' => route('search.index') . '?q={search_term_string}',
|
||||
'query-input' => 'required name=search_term_string',
|
||||
],
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) !!}
|
||||
</script>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
@if($gaId)
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id={{ $gaId }}"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
gtag('config', '{{ $gaId }}');
|
||||
</script>
|
||||
@endif
|
||||
@stack('head')
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-shell">
|
||||
@include('frontend.partials.header')
|
||||
|
||||
<div class="app-body">
|
||||
<aside class="sidebar">
|
||||
@include('frontend.partials.sidebar')
|
||||
</aside>
|
||||
<main class="content">
|
||||
@yield('content')
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.footer')
|
||||
</div>
|
||||
@stack('scripts')
|
||||
</body>
|
||||
</html>
|
||||
|
||||
13
web10/resources/views/frontend/page/about.blade.php
Normal file
13
web10/resources/views/frontend/page/about.blade.php
Normal file
@@ -0,0 +1,13 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Str;
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>关于我们</h1>
|
||||
</div>
|
||||
|
||||
<div class="rich-text">{!! Str::markdown($content) !!}</div>
|
||||
@endsection
|
||||
29
web10/resources/views/frontend/page/contact.blade.php
Normal file
29
web10/resources/views/frontend/page/contact.blade.php
Normal file
@@ -0,0 +1,29 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>联系我们</h1>
|
||||
<p>欢迎提交合作、建议或问题,我们会尽快回复。</p>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="notice success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="notice error">
|
||||
@foreach($errors->all() as $error)
|
||||
<div>{{ $error }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="contact-form" method="post" action="{{ route('contact.store') }}">
|
||||
@csrf
|
||||
<div class="form-row">
|
||||
<input type="text" name="name" placeholder="姓名" required>
|
||||
<input type="email" name="email" placeholder="邮箱" required>
|
||||
</div>
|
||||
<textarea name="content" rows="5" placeholder="请填写你的问题或合作意向" required></textarea>
|
||||
<button type="submit" class="primary-button">提交</button>
|
||||
</form>
|
||||
@endsection
|
||||
31
web10/resources/views/frontend/partials/ad-slot.blade.php
Normal file
31
web10/resources/views/frontend/partials/ad-slot.blade.php
Normal file
@@ -0,0 +1,31 @@
|
||||
@php
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
$ads = \App\Models\AdSlot::getActiveAds($slotKey ?? '');
|
||||
@endphp
|
||||
|
||||
@if($ads->isNotEmpty())
|
||||
<div class="ad-slot">
|
||||
@if(!empty($title))
|
||||
<div class="ad-slot-title">{{ $title }}</div>
|
||||
@endif
|
||||
<div class="ad-list">
|
||||
@foreach($ads as $ad)
|
||||
@php
|
||||
$url = route('ads.redirect', $ad->id);
|
||||
$target = $ad->link_target ?: '_blank';
|
||||
@endphp
|
||||
<a class="ad-item" href="{{ $url }}" target="{{ $target }}" rel="noopener">
|
||||
@if($ad->image)
|
||||
<img src="{{ Storage::url($ad->image) }}" alt="{{ $ad->title }}">
|
||||
@endif
|
||||
<div class="ad-item-body">
|
||||
<div class="ad-item-title">{{ $ad->title }}</div>
|
||||
@if($ad->description)
|
||||
<div class="ad-item-desc">{{ $ad->description }}</div>
|
||||
@endif
|
||||
</div>
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
18
web10/resources/views/frontend/partials/footer.blade.php
Normal file
18
web10/resources/views/frontend/partials/footer.blade.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<footer class="footer">
|
||||
<div class="footer-inner">
|
||||
<span>© {{ date('Y') }} {{ $siteTitle }}</span>
|
||||
@if($siteFooter)
|
||||
<span class="footer-text">{{ $siteFooter }}</span>
|
||||
@endif
|
||||
@if($icpNumber)
|
||||
<span class="footer-text">{{ $icpNumber }}</span>
|
||||
@endif
|
||||
@if(!empty($socialLinks))
|
||||
<span class="footer-links">
|
||||
@foreach($socialLinks as $link)
|
||||
<a href="{{ $link['url'] }}" target="_blank" rel="noopener">{{ $link['name'] }}</a>
|
||||
@endforeach
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</footer>
|
||||
22
web10/resources/views/frontend/partials/header.blade.php
Normal file
22
web10/resources/views/frontend/partials/header.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<a href="{{ route('home') }}" class="brand-link">
|
||||
@if($siteLogo)
|
||||
<img src="{{ $siteLogo }}" alt="{{ $siteTitle }}" class="brand-logo">
|
||||
@else
|
||||
<span class="brand-text">{{ $siteTitle }}</span>
|
||||
@endif
|
||||
</a>
|
||||
</div>
|
||||
<nav class="topnav">
|
||||
<a href="{{ route('home') }}">首页</a>
|
||||
<a href="{{ route('categories.index') }}">分类</a>
|
||||
<a href="{{ route('articles.index') }}">文章</a>
|
||||
<a href="{{ route('about') }}">关于</a>
|
||||
</nav>
|
||||
<div class="topbar-actions">
|
||||
<button type="button" class="theme-toggle" id="theme-toggle" aria-label="切换主题">
|
||||
<span class="theme-icon">暗/亮</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
31
web10/resources/views/frontend/partials/pagination.blade.php
Normal file
31
web10/resources/views/frontend/partials/pagination.blade.php
Normal file
@@ -0,0 +1,31 @@
|
||||
@if ($paginator->hasPages())
|
||||
<nav class="pagination">
|
||||
@if ($paginator->onFirstPage())
|
||||
<span class="page disabled">上一页</span>
|
||||
@else
|
||||
<a class="page" href="{{ $paginator->previousPageUrl() }}">上一页</a>
|
||||
@endif
|
||||
|
||||
@foreach ($elements as $element)
|
||||
@if (is_string($element))
|
||||
<span class="page disabled">{{ $element }}</span>
|
||||
@endif
|
||||
|
||||
@if (is_array($element))
|
||||
@foreach ($element as $page => $url)
|
||||
@if ($page == $paginator->currentPage())
|
||||
<span class="page active">{{ $page }}</span>
|
||||
@else
|
||||
<a class="page" href="{{ $url }}">{{ $page }}</a>
|
||||
@endif
|
||||
@endforeach
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
@if ($paginator->hasMorePages())
|
||||
<a class="page" href="{{ $paginator->nextPageUrl() }}">下一页</a>
|
||||
@else
|
||||
<span class="page disabled">下一页</span>
|
||||
@endif
|
||||
</nav>
|
||||
@endif
|
||||
@@ -0,0 +1,22 @@
|
||||
@php
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
@endphp
|
||||
|
||||
<div class="product-card">
|
||||
<a href="{{ route('products.show', $product->slug) }}" class="product-card-link">
|
||||
<div class="product-card-media">
|
||||
@if($product->cover)
|
||||
<img src="{{ Storage::url($product->cover) }}" alt="{{ $product->name }}">
|
||||
@else
|
||||
<div class="product-card-placeholder">{{ mb_substr($product->name, 0, 2) }}</div>
|
||||
@endif
|
||||
@if(\App\Models\SiteSetting::value('show_sponsor_label', '1') === '1' && $product->is_sponsored)
|
||||
<span class="sponsor-badge">推广</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="product-card-body">
|
||||
<div class="product-card-title">{{ $product->name }}</div>
|
||||
<div class="product-card-summary">{{ $product->summary }}</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
28
web10/resources/views/frontend/partials/sidebar.blade.php
Normal file
28
web10/resources/views/frontend/partials/sidebar.blade.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<div class="sidebar-block">
|
||||
<div class="sidebar-title">分类导航</div>
|
||||
<div class="category-list">
|
||||
@foreach($sidebarCategories as $category)
|
||||
<details class="category-group" @if($loop->first) open @endif>
|
||||
<summary>
|
||||
<span>
|
||||
@if($category->icon)
|
||||
<span class="icon">{{ $category->icon }}</span>
|
||||
@endif
|
||||
{{ $category->name }}
|
||||
</span>
|
||||
<span class="count">{{ $category->products_count }}</span>
|
||||
</summary>
|
||||
<ul>
|
||||
@foreach($category->children as $child)
|
||||
<li>
|
||||
<a href="{{ route('categories.show', $child->slug) }}">
|
||||
{{ $child->name }}
|
||||
<span class="count">{{ $child->products_count }}</span>
|
||||
</a>
|
||||
</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</details>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
148
web10/resources/views/frontend/product/show.blade.php
Normal file
148
web10/resources/views/frontend/product/show.blade.php
Normal file
@@ -0,0 +1,148 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@php
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
$platformText = is_array($product->platforms) ? implode(', ', $product->platforms) : '';
|
||||
$title = $product->seo_title ?: $product->name;
|
||||
$description = $product->seo_description ?: $product->summary;
|
||||
$ogType = 'product';
|
||||
$ogImage = $product->cover ? Storage::url($product->cover) : null;
|
||||
@endphp
|
||||
|
||||
@push('head')
|
||||
<script type="application/ld+json">
|
||||
{!! json_encode([
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'SoftwareApplication',
|
||||
'name' => $product->name,
|
||||
'description' => $product->summary,
|
||||
'url' => url()->current(),
|
||||
'applicationCategory' => $product->category?->name,
|
||||
'operatingSystem' => $platformText,
|
||||
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) !!}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1>{{ $product->name }}</h1>
|
||||
<p>{{ $product->summary }}</p>
|
||||
</div>
|
||||
<a href="{{ route('outbound', $product->slug) }}" class="primary-button" target="_blank" rel="noopener">访问官网</a>
|
||||
</div>
|
||||
|
||||
<div class="detail-grid">
|
||||
<div class="detail-main">
|
||||
<div class="detail-section">
|
||||
<h3>产品介绍</h3>
|
||||
<div class="rich-text">{!! nl2br(e($product->description)) !!}</div>
|
||||
</div>
|
||||
|
||||
@if($product->screenshots)
|
||||
<div class="detail-section">
|
||||
<h3>截图</h3>
|
||||
<div class="media-grid">
|
||||
@foreach($product->screenshots as $shot)
|
||||
<img src="{{ Storage::url($shot) }}" alt="{{ $product->name }}">
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
<div class="detail-side">
|
||||
<div class="detail-card">
|
||||
<div class="meta-item"><span>分类</span><strong>{{ $product->category?->name }}</strong></div>
|
||||
<div class="meta-item"><span>浏览</span><strong>{{ $product->view_count }}</strong></div>
|
||||
<div class="meta-item"><span>点击</span><strong>{{ $product->click_count }}</strong></div>
|
||||
<div class="meta-item"><span>收费</span><strong>{{ $product->pricing_type ?? '未知' }}</strong></div>
|
||||
</div>
|
||||
<div class="detail-card">
|
||||
<h4>标签</h4>
|
||||
<div class="tag-cloud">
|
||||
@foreach($product->tags as $tag)
|
||||
<a href="{{ route('tags.show', $tag->slug) }}" class="tag-chip">{{ $tag->name }}</a>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'detail', 'title' => '推广位'])
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>相关推荐</h2>
|
||||
</div>
|
||||
<div class="product-grid">
|
||||
@foreach($relatedProducts as $item)
|
||||
@include('frontend.partials.product-card', ['product' => $item])
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@php
|
||||
$commentsEnabled = \App\Models\SiteSetting::value('comments_enabled', '1');
|
||||
@endphp
|
||||
|
||||
<section class="section">
|
||||
<div class="section-header">
|
||||
<h2>评论</h2>
|
||||
</div>
|
||||
|
||||
@if($commentsEnabled)
|
||||
@if(session('success'))
|
||||
<div class="notice success">{{ session('success') }}</div>
|
||||
@endif
|
||||
@if($errors->any())
|
||||
<div class="notice error">
|
||||
@foreach($errors->all() as $error)
|
||||
<div>{{ $error }}</div>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form class="comment-form" method="post" action="{{ route('comments.store') }}">
|
||||
@csrf
|
||||
<input type="hidden" name="target_type" value="product">
|
||||
<input type="hidden" name="target_id" value="{{ $product->id }}">
|
||||
<div class="form-row">
|
||||
<input type="text" name="nickname" placeholder="昵称" required>
|
||||
<input type="email" name="email" placeholder="邮箱(可选)">
|
||||
</div>
|
||||
<textarea name="content" rows="4" placeholder="写下你的评论" required></textarea>
|
||||
<div class="form-row captcha-row">
|
||||
<input type="text" name="captcha" placeholder="验证码" required>
|
||||
<img src="{{ route('comments.captcha') }}" alt="验证码" onclick="this.src='{{ route('comments.captcha') }}?t=' + Date.now()" class="captcha-image">
|
||||
</div>
|
||||
<button type="submit" class="primary-button">提交评论</button>
|
||||
</form>
|
||||
|
||||
<div class="comment-list">
|
||||
@forelse($comments as $comment)
|
||||
<div class="comment-item">
|
||||
<div class="comment-header">
|
||||
<strong>{{ $comment->nickname }}</strong>
|
||||
<span>{{ $comment->created_at->format('Y-m-d H:i') }}</span>
|
||||
</div>
|
||||
<div class="comment-body">{{ $comment->content }}</div>
|
||||
<div class="comment-actions">
|
||||
<form method="post" action="{{ route('comments.like', $comment->id) }}">
|
||||
@csrf
|
||||
<button type="submit" class="like-button">点赞 {{ $comment->like_count }}</button>
|
||||
</form>
|
||||
</div>
|
||||
@if($comment->reply_content)
|
||||
<div class="comment-reply">
|
||||
<span>官方回复:</span>{{ $comment->reply_content }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@empty
|
||||
<div class="empty">暂无评论</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@else
|
||||
<div class="empty">评论已关闭</div>
|
||||
@endif
|
||||
</section>
|
||||
@endsection
|
||||
22
web10/resources/views/frontend/search/index.blade.php
Normal file
22
web10/resources/views/frontend/search/index.blade.php
Normal file
@@ -0,0 +1,22 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>搜索结果</h1>
|
||||
<p>关键词:{{ $query ?: '全部' }}</p>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'list', 'title' => '推广位'])
|
||||
|
||||
<div class="product-grid">
|
||||
@forelse($products as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@empty
|
||||
<div class="empty">暂无搜索结果</div>
|
||||
@endforelse
|
||||
</div>
|
||||
|
||||
<div class="pagination">
|
||||
{{ $products->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
21
web10/resources/views/frontend/tag/index.blade.php
Normal file
21
web10/resources/views/frontend/tag/index.blade.php
Normal file
@@ -0,0 +1,21 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>标签</h1>
|
||||
<p>浏览全站热门标签,快速定位感兴趣的 AI 工具。</p>
|
||||
</div>
|
||||
|
||||
<form class="filter-bar" method="get" action="{{ route('tags.index') }}">
|
||||
<input type="text" name="q" placeholder="搜索标签" value="{{ $query }}">
|
||||
<button type="submit" class="primary-button">搜索</button>
|
||||
</form>
|
||||
|
||||
<div class="tag-cloud">
|
||||
@foreach($tags as $tag)
|
||||
<a href="{{ route('tags.show', $tag->slug) }}" class="tag-chip">
|
||||
{{ $tag->name }}
|
||||
</a>
|
||||
@endforeach
|
||||
</div>
|
||||
@endsection
|
||||
67
web10/resources/views/frontend/tag/show.blade.php
Normal file
67
web10/resources/views/frontend/tag/show.blade.php
Normal file
@@ -0,0 +1,67 @@
|
||||
@extends('frontend.layouts.app')
|
||||
|
||||
@php
|
||||
$viewMode = request('view', 'grid');
|
||||
$pricingOptions = [
|
||||
'' => '全部价格',
|
||||
'free' => '免费',
|
||||
'paid' => '付费',
|
||||
'subscription' => '订阅',
|
||||
'trial' => '试用',
|
||||
];
|
||||
@endphp
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<h1>标签:{{ $tag->name }}</h1>
|
||||
</div>
|
||||
|
||||
@include('frontend.partials.ad-slot', ['slotKey' => 'list', 'title' => '推广位'])
|
||||
|
||||
<form class="filter-bar" method="get">
|
||||
<input type="hidden" name="view" value="{{ $viewMode }}">
|
||||
<select name="pricing">
|
||||
@foreach($pricingOptions as $value => $label)
|
||||
<option value="{{ $value }}" @selected($pricing === $value)>{{ $label }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
<button type="submit" class="primary-button">筛选</button>
|
||||
</form>
|
||||
|
||||
<div class="view-toggle">
|
||||
<a href="{{ request()->fullUrlWithQuery(['view' => 'grid']) }}" class="{{ $viewMode === 'grid' ? 'active' : '' }}">网格</a>
|
||||
<a href="{{ request()->fullUrlWithQuery(['view' => 'list']) }}" class="{{ $viewMode === 'list' ? 'active' : '' }}">列表</a>
|
||||
</div>
|
||||
|
||||
@if($products->total() > $moreThreshold)
|
||||
<div class="more-panel">
|
||||
<span>当前标签内容较多</span>
|
||||
<a href="{{ $products->nextPageUrl() ?? $products->url(1) }}" class="more-link">查看全部</a>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($viewMode === 'list')
|
||||
<div class="article-list">
|
||||
@forelse($products as $product)
|
||||
<a class="article-item" href="{{ route('products.show', $product->slug) }}">
|
||||
<div class="article-title">{{ $product->name }}</div>
|
||||
<div class="article-summary">{{ $product->summary }}</div>
|
||||
</a>
|
||||
@empty
|
||||
<div class="empty">暂无产品</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@else
|
||||
<div class="product-grid">
|
||||
@forelse($products as $product)
|
||||
@include('frontend.partials.product-card', ['product' => $product])
|
||||
@empty
|
||||
<div class="empty">暂无产品</div>
|
||||
@endforelse
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="pagination">
|
||||
{{ $products->links() }}
|
||||
</div>
|
||||
@endsection
|
||||
134
web10/resources/views/frontend/welcome.blade.php
Normal file
134
web10/resources/views/frontend/welcome.blade.php
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user