Files
d8d-admin-mobile-starter-pu…/server/routes_file_upload.ts

258 lines
7.0 KiB
TypeScript

import { Hono } from "hono";
import debug from "debug";
import type {
FileLibrary,
} from "../client/share/types.ts";
import {
DeleteStatus,
EnableStatus,
} from "../client/share/types.ts";
import type { Variables, WithAuth } from "./middlewares.ts";
const log = {
api: debug("api:sys"),
};
// 创建文件上传路由
export function createFileUploadRoutes(withAuth: WithAuth) {
const fileUploadRoutes = new Hono<{ Variables: Variables }>();
// 获取 MinIO 上传策略
fileUploadRoutes.get("/policy", withAuth, async (c) => {
try {
const prefix = c.req.query("prefix") || "uploads/";
const filename = c.req.query("filename");
const maxSize = Number(c.req.query("maxSize")) || 10 * 1024 * 1024; // 默认10MB
if (!filename) {
return c.json({ error: "文件名不能为空" }, 400);
}
const apiClient = c.get('apiClient');
const policy = await apiClient.storage.getUploadPolicy(
prefix,
filename,
maxSize
);
return c.json({
message: "获取上传策略成功",
data: policy,
});
} catch (error) {
log.api("获取上传策略失败:", error);
return c.json({ error: "获取上传策略失败" }, 500);
}
});
// 保存文件信息到文件库
fileUploadRoutes.post("/save", withAuth, async (c) => {
try {
const fileData = (await c.req.json()) as Partial<FileLibrary>;
const user = c.get("user");
// 验证必填字段
if (!fileData.file_name || !fileData.file_path || !fileData.file_type) {
return c.json({ error: "文件名、路径和类型不能为空" }, 400);
}
const apiClient = c.get('apiClient');
// 设置上传者信息
if (user) {
fileData.uploader_id = user.id;
fileData.uploader_name = user.nickname || user.username;
}
// 插入文件库记录
const [id] = await apiClient.database.table("file_library").insert({
...fileData,
download_count: 0,
is_disabled: EnableStatus.ENABLED,
is_deleted: DeleteStatus.NOT_DELETED,
created_at: apiClient.database.fn.now(),
updated_at: apiClient.database.fn.now(),
});
// 获取插入的数据
const [insertedFile] = await apiClient.database
.table("file_library")
.where("id", id);
return c.json({
message: "文件信息保存成功",
data: insertedFile,
});
} catch (error) {
log.api("保存文件信息失败:", error);
return c.json({ error: "保存文件信息失败" }, 500);
}
});
// 获取文件列表
fileUploadRoutes.get("/list", withAuth, async (c) => {
try {
const page = Number(c.req.query("page")) || 1;
const pageSize = Number(c.req.query("pageSize")) || 10;
const category_id = c.req.query("category_id");
const fileType = c.req.query("fileType");
const keyword = c.req.query("keyword");
const apiClient = c.get('apiClient');
let query = apiClient.database
.table("file_library")
.where("is_deleted", DeleteStatus.NOT_DELETED)
.orderBy("created_at", "desc");
// 应用过滤条件
if (category_id) {
query = query.where("category_id", category_id);
}
if (fileType) {
query = query.where("file_type", fileType);
}
if (keyword) {
query = query.where((builder) => {
builder
.where("file_name", "like", `%${keyword}%`)
.orWhere("description", "like", `%${keyword}%`)
.orWhere("tags", "like", `%${keyword}%`);
});
}
// 获取总数
const total = await query.clone().count();
// 分页查询
const files = await query.limit(pageSize).offset((page - 1) * pageSize);
return c.json({
message: "获取文件列表成功",
data: {
list: files,
pagination: {
current: page,
pageSize,
total: Number(total),
},
},
});
} catch (error) {
log.api("获取文件列表失败:", error);
return c.json({ error: "获取文件列表失败" }, 500);
}
});
// 获取单个文件信息
fileUploadRoutes.get("/:id", withAuth, async (c) => {
try {
const id = Number(c.req.param("id"));
if (!id || isNaN(id)) {
return c.json({ error: "无效的文件ID" }, 400);
}
const apiClient = c.get('apiClient');
const file = await apiClient.database
.table("file_library")
.where("id", id)
.where("is_deleted", DeleteStatus.NOT_DELETED)
.first();
if (!file) {
return c.json({ error: "文件不存在" }, 404);
}
return c.json({
message: "获取文件信息成功",
data: file,
});
} catch (error) {
log.api("获取文件信息失败:", error);
return c.json({ error: "获取文件信息失败" }, 500);
}
});
// 增加文件下载计数
fileUploadRoutes.post("/:id/download", withAuth, async (c) => {
try {
const id = Number(c.req.param("id"));
if (!id || isNaN(id)) {
return c.json({ error: "无效的文件ID" }, 400);
}
const apiClient = c.get('apiClient');
// 查询文件是否存在
const file = await apiClient.database
.table("file_library")
.where("id", id)
.where("is_deleted", DeleteStatus.NOT_DELETED)
.first();
if (!file) {
return c.json({ error: "文件不存在" }, 404);
}
// 增加下载计数
await apiClient.database
.table("file_library")
.where("id", id)
.update({
download_count: apiClient.database.raw("download_count + 1"),
updated_at: apiClient.database.fn.now(),
});
return c.json({
message: "更新下载计数成功",
});
} catch (error) {
log.api("更新下载计数失败:", error);
return c.json({ error: "更新下载计数失败" }, 500);
}
});
// 删除文件
fileUploadRoutes.delete("/:id", withAuth, async (c) => {
try {
const id = Number(c.req.param("id"));
if (!id || isNaN(id)) {
return c.json({ error: "无效的文件ID" }, 400);
}
const apiClient = c.get('apiClient');
// 查询文件是否存在
const file = await apiClient.database
.table("file_library")
.where("id", id)
.where("is_deleted", DeleteStatus.NOT_DELETED)
.first();
if (!file) {
return c.json({ error: "文件不存在" }, 404);
}
// 软删除文件
await apiClient.database.table("file_library").where("id", id).update({
is_deleted: DeleteStatus.DELETED,
updated_at: apiClient.database.fn.now(),
});
return c.json({
message: "文件删除成功",
});
} catch (error) {
log.api("删除文件失败:", error);
return c.json({ error: "删除文件失败" }, 500);
}
});
return fileUploadRoutes;
}