creatives.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.creativesRouter = creativesRouter;
  7. const express_1 = require("express");
  8. const uuid_1 = require("uuid");
  9. const fs_1 = __importDefault(require("fs"));
  10. const path_1 = __importDefault(require("path"));
  11. function creativesRouter(db, storageDir, onThemeSaved) {
  12. const router = (0, express_1.Router)();
  13. // GET /api/v1/creatives — 创意列表
  14. router.get("/", (req, res) => {
  15. const { status, page = "1", limit = "20" } = req.query;
  16. const offset = (Number(page) - 1) * Number(limit);
  17. let sql = `
  18. SELECT c.*, t.name as template_name
  19. FROM creatives c
  20. JOIN templates t ON c.template_id = t.id
  21. `;
  22. const params = [];
  23. if (status) {
  24. sql += " WHERE c.status = ?";
  25. params.push(status);
  26. }
  27. sql += " ORDER BY c.updated_at DESC LIMIT ? OFFSET ?";
  28. params.push(Number(limit), offset);
  29. const rows = db.prepare(sql).all(...params);
  30. const data = rows.map((row) => ({
  31. id: row.id,
  32. name: row.name,
  33. templateId: row.template_id,
  34. templateName: row.template_name,
  35. status: row.status,
  36. createdAt: row.created_at,
  37. updatedAt: row.updated_at,
  38. }));
  39. res.json({ data });
  40. });
  41. // POST /api/v1/creatives — 新建创意
  42. router.post("/", (req, res) => {
  43. const { name, templateId } = req.body;
  44. if (!name || !templateId) {
  45. res.status(400).json({
  46. error: { message: "name and templateId are required" },
  47. });
  48. return;
  49. }
  50. // 校验模板存在
  51. const template = db
  52. .prepare("SELECT id FROM templates WHERE id = ?")
  53. .get(templateId);
  54. if (!template) {
  55. res.status(400).json({
  56. error: { message: `Template '${templateId}' not found` },
  57. });
  58. return;
  59. }
  60. const id = (0, uuid_1.v4)();
  61. db.prepare("INSERT INTO creatives (id, name, template_id) VALUES (?, ?, ?)").run(id, name, templateId);
  62. const creative = db.prepare("SELECT * FROM creatives WHERE id = ?").get(id);
  63. res.status(201).json({
  64. data: {
  65. id: creative.id,
  66. name: creative.name,
  67. templateId: creative.template_id,
  68. status: creative.status,
  69. theme: JSON.parse(creative.theme),
  70. createdAt: creative.created_at,
  71. updatedAt: creative.updated_at,
  72. },
  73. });
  74. });
  75. // GET /api/v1/creatives/:id — 创意详情
  76. router.get("/:id", (req, res) => {
  77. const creative = db
  78. .prepare(`SELECT c.*, t.name as template_name
  79. FROM creatives c
  80. JOIN templates t ON c.template_id = t.id
  81. WHERE c.id = ?`)
  82. .get(req.params.id);
  83. if (!creative) {
  84. res.status(404).json({ error: { message: "Creative not found" } });
  85. return;
  86. }
  87. // 获取素材列表
  88. const assets = db
  89. .prepare("SELECT * FROM creative_assets WHERE creative_id = ?")
  90. .all(creative.id);
  91. // 获取最近构建
  92. const recentBuilds = db
  93. .prepare("SELECT id, status, platforms, results, error_log, started_at, finished_at, created_at FROM builds WHERE creative_id = ? ORDER BY created_at DESC LIMIT 5")
  94. .all(creative.id);
  95. res.json({
  96. data: {
  97. id: creative.id,
  98. name: creative.name,
  99. templateId: creative.template_id,
  100. template: {
  101. id: creative.template_id,
  102. name: creative.template_name,
  103. },
  104. status: creative.status,
  105. theme: JSON.parse(creative.theme),
  106. assets: assets.map((a) => ({
  107. key: a.file_key,
  108. fileName: a.file_name,
  109. fileSize: a.file_size,
  110. isRequired: !!a.is_required,
  111. })),
  112. recentBuilds: recentBuilds.map((b) => ({
  113. id: b.id,
  114. status: b.status,
  115. platforms: JSON.parse(b.platforms),
  116. previewUrl: b.status === "completed" ? `/q/${b.id.replace(/-/g, "").slice(0, 8)}.html` : null,
  117. results: b.results ? JSON.parse(b.results) : null,
  118. errorLog: b.error_log,
  119. startedAt: b.started_at,
  120. finishedAt: b.finished_at,
  121. createdAt: b.created_at,
  122. })),
  123. createdAt: creative.created_at,
  124. updatedAt: creative.updated_at,
  125. },
  126. });
  127. });
  128. // PATCH /api/v1/creatives/:id — 更新创意
  129. router.patch("/:id", (req, res) => {
  130. const creative = db
  131. .prepare("SELECT * FROM creatives WHERE id = ?")
  132. .get(req.params.id);
  133. if (!creative) {
  134. res.status(404).json({ error: { message: "Creative not found" } });
  135. return;
  136. }
  137. const { name, theme } = req.body;
  138. if (name !== undefined) {
  139. db.prepare("UPDATE creatives SET name = ?, updated_at = datetime('now') WHERE id = ?")
  140. .run(name, req.params.id);
  141. }
  142. if (theme !== undefined) {
  143. db.prepare("UPDATE creatives SET theme = ?, updated_at = datetime('now') WHERE id = ?")
  144. .run(JSON.stringify(theme), req.params.id);
  145. // 通知预览服务更新配置
  146. onThemeSaved?.(req.params.id, theme, storageDir);
  147. }
  148. // 返回更新后的数据
  149. const updated = db
  150. .prepare("SELECT * FROM creatives WHERE id = ?")
  151. .get(req.params.id);
  152. res.json({
  153. data: {
  154. id: updated.id,
  155. name: updated.name,
  156. templateId: updated.template_id,
  157. status: updated.status,
  158. theme: JSON.parse(updated.theme),
  159. updatedAt: updated.updated_at,
  160. },
  161. });
  162. });
  163. // DELETE /api/v1/creatives/:id — 删除创意
  164. router.delete("/:id", (req, res) => {
  165. const creative = db
  166. .prepare("SELECT * FROM creatives WHERE id = ?")
  167. .get(req.params.id);
  168. if (!creative) {
  169. res.status(404).json({ error: { message: "Creative not found" } });
  170. return;
  171. }
  172. // 删除磁盘文件
  173. const creativeDir = path_1.default.join(storageDir, "creatives", creative.id);
  174. if (fs_1.default.existsSync(creativeDir)) {
  175. fs_1.default.rmSync(creativeDir, { recursive: true, force: true });
  176. }
  177. // 级联删除数据库记录(foreign key ON DELETE CASCADE)
  178. db.prepare("DELETE FROM creatives WHERE id = ?").run(req.params.id);
  179. res.json({ data: { id: req.params.id, deleted: true } });
  180. });
  181. return router;
  182. }
  183. //# sourceMappingURL=creatives.js.map