feat(note): add image upload functionality for notes

- Implemented a new endpoint in the Note controller to handle image uploads associated with notes.
- Added the `uploadImage` method in NoteService to manage image storage and return public URLs.
- Updated API routes to include the new image upload endpoint, enhancing note management capabilities.
This commit is contained in:
nepiedg
2026-04-20 10:27:54 +00:00
parent 9cc82df980
commit 69eb3e5019
4 changed files with 84 additions and 0 deletions
+23
View File
@@ -178,4 +178,27 @@ class Note extends BaseController
return Response::error($e->getMessage(), $e->getCode() ?: 500);
}
}
/**
* 上传笔记图片
* POST /note/v1/item/image/:id
*/
public function image(Request $request, int $id)
{
try {
if ($id <= 0) {
return Response::error('笔记 ID 不正确', 400);
}
$file = $request->file('image');
if (!$file) {
return Response::error('图片文件不能为空', 400);
}
$result = $this->noteService->uploadImage($this->getCurrentNoteUserId(), $id, $file);
return Response::success($result, '上传成功');
} catch (\Throwable $e) {
return Response::error($e->getMessage(), $e->getCode() ?: 500);
}
}
}
+1
View File
@@ -33,6 +33,7 @@ Route::group('v1', function () {
Route::post('item/delete/:id', [Note::class, 'delete']);
Route::post('item/transcript/:id', [Note::class, 'transcript']);
Route::post('item/audio/:id', [Note::class, 'audio']);
Route::post('item/image/:id', [Note::class, 'image']);
Route::post('ai/summary/:id', [Ai::class, 'summary']);
Route::get('ai/summary/:id', [Ai::class, 'readSummary']);
+59
View File
@@ -268,6 +268,33 @@ class NoteService
return $this->formatAudio($audio);
}
/**
* 上传笔记图片。
*
* 这里不额外建表,直接返回公开图片地址,由前端把图片标记写回 note.content
* 以便在跨设备打开同一笔记时仍能恢复图片内容。
*
* @param int $noteUserId
* @param int $id
* @param File $file
* @return array
* @throws \Exception
*/
public function uploadImage(int $noteUserId, int $id, File $file): array
{
$this->getOwnedNote($noteUserId, $id);
$savedPath = str_replace('\\', '/', Filesystem::disk('public')->putFile('note/image', $file));
return [
'disk' => 'public',
'file_path' => $savedPath,
'image_url' => $this->buildPublicFileUrl($savedPath),
'file_size' => (int) $file->getSize(),
'mime_type' => $this->detectImageMimeType($savedPath, $file),
'updated_at' => time(),
];
}
/**
* 创建分享
*
@@ -444,6 +471,38 @@ class NoteService
return $mimeMap[$extension] ?? 'application/octet-stream';
}
/**
* 推断图片 MIME。
*
* 与音频上传一样,这里优先按扩展名兜底,避免依赖 fileinfo 扩展。
*
* @param string $savedPath
* @param File $file
* @return string
*/
private function detectImageMimeType(string $savedPath, File $file): string
{
$extension = strtolower((string) pathinfo($savedPath, PATHINFO_EXTENSION));
if ($extension === '') {
$extension = strtolower((string) pathinfo((string) $file->getOriginalName(), PATHINFO_EXTENSION));
}
$mimeMap = [
'avif' => 'image/avif',
'bmp' => 'image/bmp',
'gif' => 'image/gif',
'heic' => 'image/heic',
'heif' => 'image/heif',
'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg',
'png' => 'image/png',
'svg' => 'image/svg+xml',
'webp' => 'image/webp',
];
return $mimeMap[$extension] ?? 'application/octet-stream';
}
/**
* 规范化标题
*