重构 monorepo 并完善网页端订阅与首页体验
- 迁移为 frontend-web、frontend-electron、backend-web 与 docker 部署结构 - 网页端:订阅门禁二次弹窗、套餐/支付组件化、顶栏分组对齐 - 首页:最近文件与模板库布局优化,缩略图对齐,下载与删除操作 - 新增管理后台、支付与云端文件 API,更新 README 与项目规范 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Soon\Api\Controllers;
|
||||
|
||||
use Soon\Api\Core\Json;
|
||||
use Soon\Api\Middleware\Auth;
|
||||
use Soon\Api\Services\FileService;
|
||||
use Soon\Api\Services\MembershipService;
|
||||
|
||||
final class FileController
|
||||
{
|
||||
public function index(): void
|
||||
{
|
||||
$u = Auth::require();
|
||||
$page = max(1, (int)($_GET['page'] ?? 0));
|
||||
$size = max(1, min(200, (int)($_GET['size'] ?? 0)));
|
||||
$limit = $size > 0 ? $size : max(1, min(200, (int)($_GET['limit'] ?? 50)));
|
||||
$offset = $page > 0 ? ($page - 1) * $limit : max(0, (int)($_GET['offset'] ?? 0));
|
||||
if ($page > 0) {
|
||||
$list = FileService::list($u['id'], $limit, $offset);
|
||||
Json::ok([
|
||||
'items' => $list,
|
||||
'total' => FileService::fileCount($u['id']),
|
||||
'page' => $page,
|
||||
'size' => $limit,
|
||||
]);
|
||||
return;
|
||||
}
|
||||
$list = FileService::list($u['id'], $limit, $offset);
|
||||
Json::ok([
|
||||
'items' => $list,
|
||||
'total' => FileService::fileCount($u['id']),
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(): void
|
||||
{
|
||||
$u = Auth::require();
|
||||
MembershipService::requireActiveMember($u['id']);
|
||||
$body = Json::readBody();
|
||||
$name = (string)($body['name'] ?? 'untitled.soon');
|
||||
$json = (string)($body['json'] ?? '{}');
|
||||
Json::ok(FileService::create($u['id'], $name, $json));
|
||||
}
|
||||
|
||||
public function update(int $id): void
|
||||
{
|
||||
$u = Auth::require();
|
||||
MembershipService::requireActiveMember($u['id']);
|
||||
$body = Json::readBody();
|
||||
$name = (string)($body['name'] ?? 'untitled.soon');
|
||||
$json = (string)($body['json'] ?? '{}');
|
||||
$version = isset($body['version']) ? (int)$body['version'] : null;
|
||||
Json::ok(FileService::update($u['id'], $id, $name, $json, $version));
|
||||
}
|
||||
|
||||
public function delete(int $id): void
|
||||
{
|
||||
$u = Auth::require();
|
||||
FileService::softDelete($u['id'], $id);
|
||||
Json::ok(['id' => $id]);
|
||||
}
|
||||
|
||||
public function download(int $id): void
|
||||
{
|
||||
$u = Auth::require();
|
||||
$accept = (string)($_SERVER['HTTP_ACCEPT'] ?? '');
|
||||
$jsonRead = stripos($accept, 'application/json') !== false
|
||||
&& stripos($accept, 'application/octet-stream') === false;
|
||||
if (!$jsonRead) {
|
||||
MembershipService::requireActiveMember($u['id']);
|
||||
}
|
||||
$row = FileService::fetch($u['id'], $id);
|
||||
$name = (string)$row['name'];
|
||||
$json = (string)$row['json'];
|
||||
$size = strlen($json);
|
||||
$etag = '"' . md5($json) . '"';
|
||||
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) === $etag) {
|
||||
http_response_code(304);
|
||||
exit;
|
||||
}
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment; filename="' . rawurlencode($name) . '"');
|
||||
header('Content-Length: ' . $size);
|
||||
header('ETag: ' . $etag);
|
||||
header('Accept-Ranges: bytes');
|
||||
header('Cache-Control: private, max-age=0, must-revalidate');
|
||||
$start = 0;
|
||||
$end = $size - 1;
|
||||
if (isset($_SERVER['HTTP_RANGE']) && preg_match('/bytes=(\d+)-(\d*)/', $_SERVER['HTTP_RANGE'], $m)) {
|
||||
$start = (int)$m[1];
|
||||
if ($m[2] !== '') $end = (int)$m[2];
|
||||
if ($end >= $size) $end = $size - 1;
|
||||
http_response_code(206);
|
||||
header('Content-Range: bytes ' . $start . '-' . $end . '/' . $size);
|
||||
header('Content-Length: ' . ($end - $start + 1));
|
||||
}
|
||||
$out = fopen('php://output', 'wb');
|
||||
fwrite($out, substr($json, $start, $end - $start + 1));
|
||||
fclose($out);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user