diff --git a/app/ApiHandler.php b/app/ApiHandler.php index a4cfe45..5dc56dc 100644 --- a/app/ApiHandler.php +++ b/app/ApiHandler.php @@ -109,7 +109,7 @@ final class ApiHandler case 'vehicles': $this->vehicles($id, $method); return; case 'nodetypes': $this->nodeTypes($id, $method); return; case 'ledger': $this->ledger($id, $sub, $method); return; - case 'resources': $this->resources($id, $method); return; + case 'resources': $this->resources($id, $sub, $method); return; case 'books': $this->books($id, $sub, $method); return; case 'notes': $this->notes($id, $sub, $method); return; // 🔴 v45:登录(手机号 + 密码 → API 令牌)。 @@ -2623,12 +2623,79 @@ final class ApiHandler 资源 / 书 / 笔记 ═══════════════════════════════════════════════════════════════ */ - private function resources(int $id, string $method): void + private function resources(int $id, string $sub, string $method): void { [$fam, $pid] = Api::me(); if ($id > 0) { $r = Resource::find($fam, $id, $pid); if (!$r) { Api::notFound('这条资源'); } + + /* 🔴 工单 #25(用户 2026-10-28「鸿蒙端对齐网页端」):资源附件 + 共享。 + 端上原来明说「附件与共享还在网页端」,服务端这里补 API。 + ⚠️ 三段路由(`Api::dispatch` 只解析 /resources//), + 删附件用 `attachment_id` 参数(与 tasks 同招),不是第 4 段。 */ + if ($sub === 'attach') { + if ($method === 'GET') { + Api::ok(['items' => \App\Attachment::list(Resource::ATTACH, $id)]); + } + Api::requireWrite(); + if (!Resource::canWrite($r, $pid)) { + Api::fail('这条资源不能改。', 'forbidden', 403); + } + if ($method === 'POST') { + $file = $_FILES['file'] ?? null; + if (!is_array($file)) { + Api::fail('没有收到文件。', 'unprocessable', 422); + } + $res = \App\Attachment::save($fam, Resource::ATTACH, $id, $file, $pid); + if (empty($res['ok'])) { + $m = (string)($res['error'] ?? ''); + Api::fail($m !== '' ? $m : '文件没存下来', 'unprocessable', 422); + } + Api::ok(['id' => (int)($res['id'] ?? 0)], 201); + } + if ($method === 'DELETE') { + $aid = Api::int('attachment_id'); + if ($aid <= 0) { + Api::fail('要指定删哪个附件。', 'bad_request', 400); + } + if (!\App\Attachment::removeFrom(Resource::ATTACH, $id, $aid)) { + Api::notFound('这个附件'); + } + Api::ok(['deleted' => $aid]); + } + Api::fail('不支持的方法。', 'method_not_allowed', 405); + } + + if ($sub === 'shares') { + $isOwner = (int)($r['owner_id'] ?? 0) === $pid; + if ($method === 'GET') { + Api::ok(['items' => Resource::shares($id), 'is_owner' => $isOwner]); + } + // 只有 owner 或可写的人能改共享(Web 端 resources/share 的 canWrite 语义) + Api::requireWrite(); + if (!Resource::canWrite($r, $pid)) { + Api::fail('这条资源不能共享。', 'forbidden', 403); + } + if ($method === 'POST') { + $who = Api::int('person_id'); + if ($who <= 0) { + Api::fail('要共享给谁?缺 `person_id`。', 'unprocessable', 422); + } + Resource::setShare($id, (int)$r['owner_id'], $who, Api::str('perm', 'read')); + Api::ok(['items' => Resource::shares($id)]); + } + if ($method === 'DELETE') { + $who = Api::int('person_id'); + if ($who <= 0) { + Api::fail('要取消谁的共享?缺 `person_id`。', 'unprocessable', 422); + } + Resource::dropShare($id, $who); + Api::ok(['items' => Resource::shares($id)]); + } + Api::fail('不支持的方法。', 'method_not_allowed', 405); + } + if ($method === 'GET') { Api::ok($r); } if ($method === 'PATCH' || $method === 'PUT') { Api::requireWrite();