Files

164 lines
6.1 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// +----------------------------------------------------------------------
// | YwxApp [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2026-2036 http://ywxapp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: ywxapp<admin@ywxapp.cn>
// +----------------------------------------------------------------------
declare(strict_types=1);
namespace addon\appmall\controller;
use ywxapp\controller\FrontendBase;
use addon\appmall\service\MarketService;
/**
* 应用商店前台展示页(公开,仅中心站)
*
* 列出应用市场上线的插件 / 模板,卡片展示 logo、价格、评分、下载量等。
* 数据来自中心站本地库(appmall_addon_list),复用 MarketService::catalog()。
* 路由前缀:/appmall/store/*(由 AppService::loadAddonRoutes 外层包 Route::group('appmall'))。
* 视图:addons/appmall/view/frontend/store/。
*/
class Store extends FrontendBase
{
protected $noNeedLogin = ['*'];
protected $noNeedVerify = ['*'];
/**
* 锁定视图路径到插件目录;仅中心站暴露(客户机不持有市场列表数据,访问即 404)。
*/
protected function initialize()
{
if (is_market_client()) {
abort(404, '应用商店仅在中心站(市场服务端)可用');
}
$this->view->config([
'view_path' => ADDON_PATH . 'appmall' . DIRECTORY_SEPARATOR
. 'view' . DIRECTORY_SEPARATOR . 'frontend' . DIRECTORY_SEPARATOR,
]);
}
/**
* 商店首页:上线插件列表
*/
public function index()
{
$catalog = MarketService::instance()->catalog();
$items = $catalog['list'] ?? [];
$categories = $catalog['categories'] ?? [];
$plugins = [];
foreach ($items as $it) {
$price = (float) ($it['price'] ?? 0);
$plugins[] = [
'id' => $it['id'] ?? 0,
'name' => $it['name'] ?? '',
'title' => $it['title'] ?? ($it['name'] ?? ''),
'desc' => $it['intro'] ?? '',
'author' => $it['author'] ?? '',
'logo' => $it['logo'] ?? '',
'version' => $it['version'] ?? '',
'price' => $price,
'price_text' => $price > 0 ? '¥' . number_format($price, 2) : '免费',
'rating' => (float) ($it['rating'] ?? 0),
'downloads' => (int) ($it['download_count'] ?? 0),
'category' => $it['category'] ?? '',
'type' => $it['type'] ?? 'addon',
];
}
$this->view->assign('list', $plugins);
$this->view->assign('categories', $categories);
$this->view->assign('market_name', config('appmall.appmall_name', 'YwxApp 应用市场'));
return $this->view->fetch('store/index');
}
/**
* 插件详情页(/appmall/store/detail/<name>
* 参考 FastAdmin 插件市场详情版式:左封面+截图、右元信息+版本历史。
*/
public function detail()
{
$name = input('name', '', 'trim');
if ($name === '') {
abort(404, '插件标识为空');
}
$catalog = MarketService::instance()->catalog();
$hit = null;
foreach (($catalog['list'] ?? []) as $it) {
if (($it['name'] ?? '') === $name) {
$hit = $it;
break;
}
}
if (!$hit) {
abort(404, '插件不存在或未上架');
}
$price = (float) ($hit['price'] ?? 0);
$row = [
'id' => $hit['id'] ?? 0,
'name' => $hit['name'] ?? '',
'title' => $hit['title'] ?? ($hit['name'] ?? ''),
'intro' => $hit['intro'] ?? '',
'author' => $hit['author'] ?? '',
'logo' => $hit['logo'] ?? '',
'version' => $hit['version'] ?? '',
'price' => $price,
'price_text' => $price > 0 ? '¥' . number_format($price, 2) : '免费',
'rating' => (float) ($hit['rating'] ?? 0),
'downloads' => (int) ($hit['download_count'] ?? 0),
'category' => $hit['category'] ?? '',
'tags' => $hit['tags'] ?? '',
'type' => $hit['type'] ?? 'addon',
'update_at' => (int) ($hit['update_at'] ?? 0),
'update_fmt' => $hit['update_at'] ? date('Y-m-d', (int) $hit['update_at']) : '',
'screenshots'=> $this->parseScreenshots($hit['screenshots'] ?? ''),
'versions' => $this->normalizeVersions($hit['versions'] ?? []),
];
$this->view->assign('addon', $row);
$this->view->assign('market_name', config('appmall.appmall_name', 'YwxApp 应用市场'));
return $this->view->fetch('store/detail');
}
/**
* screenshots 可能是逗号分隔字符串 / JSON 数组,归一化为数组。
*/
private function parseScreenshots($raw): array
{
if (is_array($raw)) {
return array_values($raw);
}
$raw = trim((string) $raw);
if ($raw === '') {
return [];
}
if (strpos($raw, '[') === 0) {
$dec = json_decode($raw, true);
return is_array($dec) ? array_values($dec) : [];
}
return array_filter(array_map('trim', explode(',', $raw)), fn ($x) => $x !== '');
}
/**
* versions 子版本归一化(version/price/update_fmt)。
*/
private function normalizeVersions(array $vers): array
{
$out = [];
foreach ($vers as $v) {
$out[] = [
'version' => (string) ($v['version'] ?? ''),
'price' => (float) ($v['price'] ?? 0),
'price_text'=> ((float) ($v['price'] ?? 0)) > 0 ? '¥' . number_format((float) $v['price'], 2) : '免费',
'update_fmt'=> !empty($v['update_at']) ? date('Y-m-d', (int) $v['update_at']) : '',
];
}
return $out;
}
}