sa2kit 1.6.44 → 1.6.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AliyunOSSProvider-2FARPAQD.js +15 -0
- package/dist/{AliyunOSSProvider-HCNGDJL7.js.map → AliyunOSSProvider-2FARPAQD.js.map} +1 -1
- package/dist/AliyunOSSProvider-UMVGVBDJ.mjs +9 -0
- package/dist/{AliyunOSSProvider-4W47OFEK.mjs.map → AliyunOSSProvider-UMVGVBDJ.mjs.map} +1 -1
- package/dist/CollisionBalls-BpHufX3H.d.mts +41 -0
- package/dist/CollisionBalls-BpHufX3H.d.ts +41 -0
- package/dist/ConfigService-QR67WYNK.mjs +4 -0
- package/dist/{ConfigService-V6ZK273Z.mjs.map → ConfigService-QR67WYNK.mjs.map} +1 -1
- package/dist/{ConfigService-3DIC6C3Q.js → ConfigService-UYC6ZTCM.js} +3 -3
- package/dist/{ConfigService-3DIC6C3Q.js.map → ConfigService-UYC6ZTCM.js.map} +1 -1
- package/dist/GenericOrderManager-e4WizpNf.d.mts +28 -0
- package/dist/GenericOrderManager-e4WizpNf.d.ts +28 -0
- package/dist/LocalStorageProvider-JQF5WK5H.js +15 -0
- package/dist/{LocalStorageProvider-PP7MA5OT.js.map → LocalStorageProvider-JQF5WK5H.js.map} +1 -1
- package/dist/LocalStorageProvider-PYOHETJV.mjs +9 -0
- package/dist/{LocalStorageProvider-3RVPCQB3.mjs.map → LocalStorageProvider-PYOHETJV.mjs.map} +1 -1
- package/dist/PMXParser-RLBDO7YK.mjs +4 -0
- package/dist/{PMXParser-RNVQL76A.mjs.map → PMXParser-RLBDO7YK.mjs.map} +1 -1
- package/dist/{PMXParser-2VTA737I.js → PMXParser-XHNO2KNI.js} +3 -3
- package/dist/{PMXParser-2VTA737I.js.map → PMXParser-XHNO2KNI.js.map} +1 -1
- package/dist/UniversalFileService-RBV6EN5J.js +15 -0
- package/dist/UniversalFileService-RBV6EN5J.js.map +1 -0
- package/dist/UniversalFileService-TNYKO6JN.mjs +9 -0
- package/dist/UniversalFileService-TNYKO6JN.mjs.map +1 -0
- package/dist/analytics/index.js +1 -1
- package/dist/analytics/index.mjs +1 -1
- package/dist/analytics/server/index.js +1 -1
- package/dist/analytics/server/index.mjs +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/index.mjs +1 -1
- package/dist/audioDetection/index.js +1 -1
- package/dist/audioDetection/index.mjs +1 -1
- package/dist/auth/client/index.js +1 -1
- package/dist/auth/client/index.mjs +1 -1
- package/dist/auth/components/index.js +1 -1
- package/dist/auth/components/index.mjs +1 -1
- package/dist/auth/hooks/index.js +1 -1
- package/dist/auth/hooks/index.mjs +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/auth/index.mjs +1 -1
- package/dist/auth/middleware/index.js +1 -1
- package/dist/auth/middleware/index.mjs +1 -1
- package/dist/auth/routes/index.js +1 -1
- package/dist/auth/routes/index.mjs +1 -1
- package/dist/auth/schema/index.js +1 -1
- package/dist/auth/schema/index.mjs +1 -1
- package/dist/auth/services/index.js +1 -1
- package/dist/auth/services/index.mjs +1 -1
- package/dist/calendar/index.js +12 -12
- package/dist/calendar/index.mjs +5 -5
- package/dist/calendar/routes/index.js +1 -1
- package/dist/calendar/routes/index.mjs +1 -1
- package/dist/calendar/server.js +1 -1
- package/dist/calendar/server.mjs +1 -1
- package/dist/chunk-2PS5PIXV.mjs +443 -0
- package/dist/chunk-2PS5PIXV.mjs.map +1 -0
- package/dist/chunk-35CXIK5Y.js +277 -0
- package/dist/chunk-35CXIK5Y.js.map +1 -0
- package/dist/{chunk-GMIUSZXC.mjs → chunk-3JW4X3AC.mjs} +3 -3
- package/dist/{chunk-GMIUSZXC.mjs.map → chunk-3JW4X3AC.mjs.map} +1 -1
- package/dist/chunk-3M6T5KVD.js +453 -0
- package/dist/chunk-3M6T5KVD.js.map +1 -0
- package/dist/chunk-3TNR6IMC.js +168 -0
- package/dist/chunk-3TNR6IMC.js.map +1 -0
- package/dist/chunk-4NFOSCM6.js +34 -0
- package/dist/chunk-4NFOSCM6.js.map +1 -0
- package/dist/{chunk-3NHAT7D4.mjs → chunk-4VJQZSPU.mjs} +4 -3
- package/dist/chunk-4VJQZSPU.mjs.map +1 -0
- package/dist/{chunk-SCDDMIF6.js → chunk-4XXIBWCO.js} +66 -66
- package/dist/{chunk-SCDDMIF6.js.map → chunk-4XXIBWCO.js.map} +1 -1
- package/dist/chunk-6AHYPPUP.js +344 -0
- package/dist/chunk-6AHYPPUP.js.map +1 -0
- package/dist/{chunk-EGJPS7OL.mjs → chunk-6BJ76BYC.mjs} +3 -3
- package/dist/{chunk-EGJPS7OL.mjs.map → chunk-6BJ76BYC.mjs.map} +1 -1
- package/dist/chunk-76V7EKBX.mjs +796 -0
- package/dist/chunk-76V7EKBX.mjs.map +1 -0
- package/dist/chunk-ACLOJXXE.js +195 -0
- package/dist/chunk-ACLOJXXE.js.map +1 -0
- package/dist/chunk-AEXPAH7Z.mjs +32 -0
- package/dist/chunk-AEXPAH7Z.mjs.map +1 -0
- package/dist/chunk-CFGX3EKK.js +560 -0
- package/dist/chunk-CFGX3EKK.js.map +1 -0
- package/dist/chunk-D2HXMGXS.js +46 -0
- package/dist/chunk-D2HXMGXS.js.map +1 -0
- package/dist/chunk-DM2GUVUH.js +1201 -0
- package/dist/chunk-DM2GUVUH.js.map +1 -0
- package/dist/{chunk-ZWQJSZEY.js → chunk-DVENFCQY.js} +5 -4
- package/dist/chunk-DVENFCQY.js.map +1 -0
- package/dist/chunk-EONPKLEJ.mjs +163 -0
- package/dist/chunk-EONPKLEJ.mjs.map +1 -0
- package/dist/{chunk-L47ZOYHL.js → chunk-EUIXQPPU.js} +4 -4
- package/dist/{chunk-L47ZOYHL.js.map → chunk-EUIXQPPU.js.map} +1 -1
- package/dist/chunk-K7WNCB4V.mjs +554 -0
- package/dist/chunk-K7WNCB4V.mjs.map +1 -0
- package/dist/chunk-L4ZYBFB2.mjs +44 -0
- package/dist/chunk-L4ZYBFB2.mjs.map +1 -0
- package/dist/chunk-M4HGHTIC.js +820 -0
- package/dist/chunk-M4HGHTIC.js.map +1 -0
- package/dist/{chunk-HHVDOIPV.js → chunk-MZKATHB7.js} +4 -4
- package/dist/{chunk-HHVDOIPV.js.map → chunk-MZKATHB7.js.map} +1 -1
- package/dist/{chunk-UKT3PLON.mjs → chunk-NXQVTAOP.mjs} +3 -3
- package/dist/{chunk-UKT3PLON.mjs.map → chunk-NXQVTAOP.mjs.map} +1 -1
- package/dist/chunk-OBIPI4GU.mjs +266 -0
- package/dist/chunk-OBIPI4GU.mjs.map +1 -0
- package/dist/chunk-PAX4S7QM.mjs +94 -0
- package/dist/chunk-PAX4S7QM.mjs.map +1 -0
- package/dist/chunk-PXWDQFWV.mjs +192 -0
- package/dist/chunk-PXWDQFWV.mjs.map +1 -0
- package/dist/chunk-QROLPPXP.mjs +5797 -0
- package/dist/chunk-QROLPPXP.mjs.map +1 -0
- package/dist/chunk-TGNUEULF.mjs +1158 -0
- package/dist/chunk-TGNUEULF.mjs.map +1 -0
- package/dist/chunk-VBQFVXOW.mjs +2772 -0
- package/dist/chunk-VBQFVXOW.mjs.map +1 -0
- package/dist/chunk-VLZ5N6XZ.js +5888 -0
- package/dist/chunk-VLZ5N6XZ.js.map +1 -0
- package/dist/chunk-VTGPHE4Z.mjs +322 -0
- package/dist/chunk-VTGPHE4Z.mjs.map +1 -0
- package/dist/chunk-WMJKH4XE.mjs +30 -0
- package/dist/{chunk-BJTO5JO5.mjs.map → chunk-WMJKH4XE.mjs.map} +1 -1
- package/dist/chunk-XYQMAF7H.js +96 -0
- package/dist/chunk-XYQMAF7H.js.map +1 -0
- package/dist/chunk-Z3G3IXEF.js +2814 -0
- package/dist/chunk-Z3G3IXEF.js.map +1 -0
- package/dist/chunk-Z6ZWNWWR.js +35 -0
- package/dist/{chunk-DGUM43GV.js.map → chunk-Z6ZWNWWR.js.map} +1 -1
- package/dist/components/index.d.mts +378 -0
- package/dist/components/index.d.ts +378 -0
- package/dist/components/index.js +414 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +9 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.js +1 -1
- package/dist/config/index.mjs +1 -1
- package/dist/config/server/index.js +1 -1
- package/dist/config/server/index.mjs +1 -1
- package/dist/fileService-O3W6YXCI.mjs +4 -0
- package/dist/fileService-O3W6YXCI.mjs.map +1 -0
- package/dist/fileService-YUDIYOAS.js +13 -0
- package/dist/fileService-YUDIYOAS.js.map +1 -0
- package/dist/i18n/index.js +7 -7
- package/dist/i18n/index.mjs +1 -1
- package/dist/imageCrop/index.js +1 -1
- package/dist/imageCrop/index.mjs +1 -1
- package/dist/index.d.mts +9 -580
- package/dist/index.d.ts +9 -580
- package/dist/index.js +297 -956
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -789
- package/dist/index.mjs.map +1 -1
- package/dist/logger/index.js +8 -8
- package/dist/logger/index.mjs +5 -2
- package/dist/mikuFireworks3D/index.js +1 -1
- package/dist/mikuFireworks3D/index.mjs +1 -1
- package/dist/mikuFireworks3D/server/index.js +1 -1
- package/dist/mikuFireworks3D/server/index.mjs +1 -1
- package/dist/mikuFusionGame/index.js +5 -5
- package/dist/mikuFusionGame/index.mjs +4 -4
- package/dist/mmd/admin/index.js +1 -1
- package/dist/mmd/admin/index.mjs +1 -1
- package/dist/mmd/index.js +2 -2
- package/dist/mmd/index.mjs +2 -2
- package/dist/mmd/server/index.js +1 -1
- package/dist/mmd/server/index.mjs +1 -1
- package/dist/music/index.js +1 -1
- package/dist/music/index.mjs +1 -1
- package/dist/music/server/index.js +1 -1
- package/dist/music/server/index.mjs +1 -1
- package/dist/navigation/index.d.mts +93 -0
- package/dist/navigation/index.d.ts +93 -0
- package/dist/navigation/index.js +29 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/index.mjs +4 -0
- package/dist/navigation/index.mjs.map +1 -0
- package/dist/popupConfig-BznThU1O.d.mts +330 -0
- package/dist/popupConfig-BznThU1O.d.ts +330 -0
- package/dist/portfolio/index.d.mts +57 -0
- package/dist/portfolio/index.d.ts +57 -0
- package/dist/portfolio/index.js +35 -0
- package/dist/portfolio/index.js.map +1 -0
- package/dist/portfolio/index.mjs +10 -0
- package/dist/portfolio/index.mjs.map +1 -0
- package/dist/request/index.js +1 -1
- package/dist/request/index.mjs +1 -1
- package/dist/showmasterpiece/index.d.mts +2524 -0
- package/dist/showmasterpiece/index.d.ts +2524 -0
- package/dist/showmasterpiece/index.js +9681 -0
- package/dist/showmasterpiece/index.js.map +1 -0
- package/dist/showmasterpiece/index.mjs +9631 -0
- package/dist/showmasterpiece/index.mjs.map +1 -0
- package/dist/showmasterpiece/migration/index.d.mts +120 -0
- package/dist/showmasterpiece/migration/index.d.ts +120 -0
- package/dist/showmasterpiece/migration/index.js +595 -0
- package/dist/showmasterpiece/migration/index.js.map +1 -0
- package/dist/showmasterpiece/migration/index.mjs +589 -0
- package/dist/showmasterpiece/migration/index.mjs.map +1 -0
- package/dist/showmasterpiece/scripts/index.d.mts +28 -0
- package/dist/showmasterpiece/scripts/index.d.ts +28 -0
- package/dist/showmasterpiece/scripts/index.js +327 -0
- package/dist/showmasterpiece/scripts/index.js.map +1 -0
- package/dist/showmasterpiece/scripts/index.mjs +325 -0
- package/dist/showmasterpiece/scripts/index.mjs.map +1 -0
- package/dist/showmasterpiece/server/index.d.mts +2698 -0
- package/dist/showmasterpiece/server/index.d.ts +2698 -0
- package/dist/showmasterpiece/server/index.js +179 -0
- package/dist/showmasterpiece/server/index.js.map +1 -0
- package/dist/showmasterpiece/server/index.mjs +6 -0
- package/dist/showmasterpiece/server/index.mjs.map +1 -0
- package/dist/storage/index.js +8 -8
- package/dist/storage/index.mjs +2 -2
- package/dist/testYourself/admin/index.js +1 -1
- package/dist/testYourself/admin/index.mjs +1 -1
- package/dist/testYourself/index.js +2 -2
- package/dist/testYourself/index.mjs +2 -2
- package/dist/testYourself/server/index.js +1 -1
- package/dist/testYourself/server/index.mjs +1 -1
- package/dist/universalExport/index.js +154 -1195
- package/dist/universalExport/index.js.map +1 -1
- package/dist/universalExport/index.mjs +2 -1157
- package/dist/universalExport/index.mjs.map +1 -1
- package/dist/universalExport/server/index.js +5 -3
- package/dist/universalExport/server/index.js.map +1 -1
- package/dist/universalExport/server/index.mjs +4 -2
- package/dist/universalExport/server/index.mjs.map +1 -1
- package/dist/universalFile/index.js +10 -7
- package/dist/universalFile/index.js.map +1 -1
- package/dist/universalFile/index.mjs +6 -2
- package/dist/universalFile/index.mjs.map +1 -1
- package/dist/universalFile/server/index.d.mts +592 -265
- package/dist/universalFile/server/index.d.ts +592 -265
- package/dist/universalFile/server/index.js +298 -5637
- package/dist/universalFile/server/index.js.map +1 -1
- package/dist/universalFile/server/index.mjs +8 -5559
- package/dist/universalFile/server/index.mjs.map +1 -1
- package/dist/utils/index.js +12 -12
- package/dist/utils/index.mjs +3 -3
- package/package.json +36 -1
- package/dist/AliyunOSSProvider-4W47OFEK.mjs +0 -6
- package/dist/AliyunOSSProvider-HCNGDJL7.js +0 -15
- package/dist/ConfigService-V6ZK273Z.mjs +0 -4
- package/dist/LocalStorageProvider-3RVPCQB3.mjs +0 -6
- package/dist/LocalStorageProvider-PP7MA5OT.js +0 -15
- package/dist/PMXParser-RNVQL76A.mjs +0 -4
- package/dist/chunk-25OFOKNF.js +0 -171
- package/dist/chunk-25OFOKNF.js.map +0 -1
- package/dist/chunk-3DXPQ4YV.mjs +0 -165
- package/dist/chunk-3DXPQ4YV.mjs.map +0 -1
- package/dist/chunk-3NHAT7D4.mjs.map +0 -1
- package/dist/chunk-BJTO5JO5.mjs +0 -10
- package/dist/chunk-CIVO4R6N.mjs +0 -37
- package/dist/chunk-CIVO4R6N.mjs.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -12
- package/dist/chunk-HDMIOOZY.mjs +0 -546
- package/dist/chunk-HDMIOOZY.mjs.map +0 -1
- package/dist/chunk-HJ6MH7J7.js +0 -552
- package/dist/chunk-HJ6MH7J7.js.map +0 -1
- package/dist/chunk-KH6RQ4J5.js +0 -28
- package/dist/chunk-KH6RQ4J5.js.map +0 -1
- package/dist/chunk-Q5EDCKQA.js +0 -336
- package/dist/chunk-Q5EDCKQA.js.map +0 -1
- package/dist/chunk-YOTQG4NP.mjs +0 -314
- package/dist/chunk-YOTQG4NP.mjs.map +0 -1
- package/dist/chunk-ZGVB35L2.mjs +0 -25
- package/dist/chunk-ZGVB35L2.mjs.map +0 -1
- package/dist/chunk-ZRAW3HXA.js +0 -43
- package/dist/chunk-ZRAW3HXA.js.map +0 -1
- package/dist/chunk-ZWQJSZEY.js.map +0 -1
|
@@ -0,0 +1,2772 @@
|
|
|
1
|
+
import { normalizeHomeTabConfig, buildDefaultHomeTabConfig } from './chunk-EONPKLEJ.mjs';
|
|
2
|
+
import { relations, eq, asc, and, sql, count, desc, inArray, like } from 'drizzle-orm';
|
|
3
|
+
import { pgTable, timestamp, varchar, json, boolean, integer, text, serial, index, uuid, jsonb } from 'drizzle-orm/pg-core';
|
|
4
|
+
|
|
5
|
+
var comicUniverseConfigs = pgTable("comic_universe_configs", {
|
|
6
|
+
/** 主键ID */
|
|
7
|
+
id: serial("id").primaryKey(),
|
|
8
|
+
/** 网站名称 */
|
|
9
|
+
siteName: varchar("site_name", { length: 255 }).notNull().default("\u753B\u96C6\u5C55\u89C8"),
|
|
10
|
+
/** 网站描述 */
|
|
11
|
+
siteDescription: text("site_description").default("\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\u5C55\u89C8"),
|
|
12
|
+
/** 首页主标题 */
|
|
13
|
+
heroTitle: varchar("hero_title", { length: 255 }).notNull().default("\u827A\u672F\u753B\u96C6\u5C55\u89C8"),
|
|
14
|
+
/** 首页副标题 */
|
|
15
|
+
heroSubtitle: text("hero_subtitle").default("\u63A2\u7D22\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\uFF0C\u611F\u53D7\u521B\u4F5C\u7684\u9B45\u529B"),
|
|
16
|
+
/** 每页显示的最大画集数量 */
|
|
17
|
+
maxCollectionsPerPage: integer("max_collections_per_page").notNull().default(9),
|
|
18
|
+
/** 是否启用搜索功能 */
|
|
19
|
+
enableSearch: boolean("enable_search").notNull().default(true),
|
|
20
|
+
/** 是否启用分类功能 */
|
|
21
|
+
enableCategories: boolean("enable_categories").notNull().default(true),
|
|
22
|
+
/** 首页分类Tab配置 */
|
|
23
|
+
homeTabConfig: json("home_tab_config").default([]),
|
|
24
|
+
/** 默认分类('all'表示显示所有分类) */
|
|
25
|
+
defaultCategory: varchar("default_category", { length: 100 }).notNull().default("all"),
|
|
26
|
+
/** 主题模式:light(浅色)、dark(深色)、auto(自动) */
|
|
27
|
+
theme: varchar("theme", { length: 20 }).notNull().default("light"),
|
|
28
|
+
/** 界面语言:zh(中文)、en(英文) */
|
|
29
|
+
language: varchar("language", { length: 10 }).notNull().default("zh"),
|
|
30
|
+
/** 创建时间 */
|
|
31
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
32
|
+
/** 更新时间 */
|
|
33
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
34
|
+
});
|
|
35
|
+
var comicUniverseCategories = pgTable("comic_universe_categories", {
|
|
36
|
+
/** 主键ID */
|
|
37
|
+
id: serial("id").primaryKey(),
|
|
38
|
+
/** 分类名称(唯一) */
|
|
39
|
+
name: varchar("name", { length: 100 }).notNull().unique(),
|
|
40
|
+
/** 分类描述 */
|
|
41
|
+
description: text("description"),
|
|
42
|
+
/** 显示顺序(数字越小越靠前) */
|
|
43
|
+
displayOrder: integer("display_order").default(0),
|
|
44
|
+
/** 是否启用该分类 */
|
|
45
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
46
|
+
/** 创建时间 */
|
|
47
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
48
|
+
/** 更新时间 */
|
|
49
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
50
|
+
}, (table) => ({
|
|
51
|
+
/** 按启用状态查询的索引 */
|
|
52
|
+
isActiveIndex: index("categories_is_active_idx").on(table.isActive),
|
|
53
|
+
/** 按显示顺序排序的索引 */
|
|
54
|
+
displayOrderIndex: index("categories_display_order_idx").on(table.displayOrder)
|
|
55
|
+
}));
|
|
56
|
+
var comicUniverseTags = pgTable("comic_universe_tags", {
|
|
57
|
+
/** 主键ID */
|
|
58
|
+
id: serial("id").primaryKey(),
|
|
59
|
+
/** 标签名称(唯一) */
|
|
60
|
+
name: varchar("name", { length: 50 }).notNull().unique(),
|
|
61
|
+
/** 标签颜色(十六进制色值,用于UI显示) */
|
|
62
|
+
color: varchar("color", { length: 7 }).default("#3b82f6"),
|
|
63
|
+
/** 是否启用该标签 */
|
|
64
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
65
|
+
/** 创建时间 */
|
|
66
|
+
createdAt: timestamp("created_at").defaultNow().notNull()
|
|
67
|
+
}, (table) => ({
|
|
68
|
+
/** 按启用状态查询的索引 */
|
|
69
|
+
isActiveIndex: index("tags_is_active_idx").on(table.isActive)
|
|
70
|
+
}));
|
|
71
|
+
var comicUniverseCollections = pgTable("comic_universe_collections", {
|
|
72
|
+
/** 主键ID */
|
|
73
|
+
id: serial("id").primaryKey(),
|
|
74
|
+
/** 画集标题 */
|
|
75
|
+
title: varchar("title", { length: 255 }).notNull(),
|
|
76
|
+
/** 编号 */
|
|
77
|
+
number: varchar("number", { length: 255 }).notNull(),
|
|
78
|
+
/** 封面图片(支持URL或base64编码) */
|
|
79
|
+
coverImage: text("cover_image").notNull(),
|
|
80
|
+
/** 通用文件服务的封面图片文件ID(新架构) */
|
|
81
|
+
coverImageFileId: uuid("cover_image_file_id"),
|
|
82
|
+
/** 画集描述 */
|
|
83
|
+
description: text("description"),
|
|
84
|
+
/** 分类ID(外键,支持级联删除时设为null) */
|
|
85
|
+
categoryId: integer("category_id").references(() => comicUniverseCategories.id, { onDelete: "set null" }),
|
|
86
|
+
/** 是否已发布(false表示草稿状态) */
|
|
87
|
+
isPublished: boolean("is_published").notNull().default(true),
|
|
88
|
+
/** 发布时间 */
|
|
89
|
+
publishedAt: timestamp("published_at"),
|
|
90
|
+
/** 显示顺序(数字越小越靠前) */
|
|
91
|
+
displayOrder: integer("display_order").default(0),
|
|
92
|
+
/** 画集价格(单位:元,null表示免费或价格待定) */
|
|
93
|
+
price: integer("price"),
|
|
94
|
+
/** 访问次数统计 */
|
|
95
|
+
viewCount: integer("view_count").notNull().default(0),
|
|
96
|
+
/** 创建时间 */
|
|
97
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
98
|
+
/** 更新时间 */
|
|
99
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
100
|
+
}, (table) => ({
|
|
101
|
+
/** 按发布状态查询的索引 */
|
|
102
|
+
isPublishedIndex: index("collections_is_published_idx").on(table.isPublished),
|
|
103
|
+
/** 按显示顺序排序的索引 */
|
|
104
|
+
displayOrderIndex: index("collections_display_order_idx").on(table.displayOrder),
|
|
105
|
+
/** 按分类查询的索引 */
|
|
106
|
+
categoryIdIndex: index("collections_category_id_idx").on(table.categoryId),
|
|
107
|
+
/** 已发布画集按顺序排序的复合索引(优化首页查询) */
|
|
108
|
+
publishedOrderIndex: index("collections_published_order_idx").on(table.isPublished, table.displayOrder),
|
|
109
|
+
/** 已发布画集按创建时间排序的复合索引(优化时间线查询) */
|
|
110
|
+
publishedCreatedIndex: index("collections_published_created_idx").on(table.isPublished, table.createdAt),
|
|
111
|
+
/** 封面图片文件ID查询索引(新架构) */
|
|
112
|
+
coverImageFileIdIndex: index("collections_cover_image_file_id_idx").on(table.coverImageFileId)
|
|
113
|
+
}));
|
|
114
|
+
var comicUniverseCollectionTags = pgTable("comic_universe_collection_tags", {
|
|
115
|
+
/** 画集ID(外键,级联删除) */
|
|
116
|
+
collectionId: integer("collection_id").notNull().references(() => comicUniverseCollections.id, { onDelete: "cascade" }),
|
|
117
|
+
/** 标签ID(外键,级联删除) */
|
|
118
|
+
tagId: integer("tag_id").notNull().references(() => comicUniverseTags.id, { onDelete: "cascade" })
|
|
119
|
+
}, (table) => ({
|
|
120
|
+
/** 复合主键,确保同一画集不会重复关联同一标签 */
|
|
121
|
+
pk: { primaryKey: [table.collectionId, table.tagId] },
|
|
122
|
+
/** 按画集查询标签的索引 */
|
|
123
|
+
collectionIdIndex: index("collection_tags_collection_id_idx").on(table.collectionId),
|
|
124
|
+
/** 按标签查询画集的索引 */
|
|
125
|
+
tagIdIndex: index("collection_tags_tag_id_idx").on(table.tagId)
|
|
126
|
+
}));
|
|
127
|
+
var comicUniverseArtworks = pgTable("comic_universe_artworks", {
|
|
128
|
+
/** 主键ID */
|
|
129
|
+
id: serial("id").primaryKey(),
|
|
130
|
+
/** 所属画集ID(外键,级联删除) */
|
|
131
|
+
collectionId: integer("collection_id").notNull().references(() => comicUniverseCollections.id, { onDelete: "cascade" }),
|
|
132
|
+
/** 作品标题 */
|
|
133
|
+
title: varchar("title", { length: 255 }).notNull(),
|
|
134
|
+
/** 编号 */
|
|
135
|
+
number: varchar("number", { length: 255 }).notNull(),
|
|
136
|
+
/** 作品图片(支持URL或base64编码,兼容旧数据) */
|
|
137
|
+
image: text("image"),
|
|
138
|
+
/** 通用文件服务的文件ID(新架构) */
|
|
139
|
+
fileId: uuid("file_id"),
|
|
140
|
+
/** 迁移状态:pending(待迁移), completed(已完成), failed(失败) */
|
|
141
|
+
migrationStatus: varchar("migration_status", { length: 20 }).default("pending"),
|
|
142
|
+
/** 作品描述 */
|
|
143
|
+
description: text("description"),
|
|
144
|
+
/** 创作时间(自由格式,如"2024年春" "明代" 等) */
|
|
145
|
+
createdTime: varchar("created_time", { length: 20 }),
|
|
146
|
+
/** 作品主题(如"山水" "人物" "静物"等) */
|
|
147
|
+
theme: varchar("theme", { length: 255 }),
|
|
148
|
+
/** 作品尺寸(如"120x80cm" "A4" 等) */
|
|
149
|
+
dimensions: varchar("dimensions", { length: 100 }),
|
|
150
|
+
/** 在画集中的页面顺序(从0开始) */
|
|
151
|
+
pageOrder: integer("page_order").notNull().default(0),
|
|
152
|
+
/** 是否启用(false表示已删除或隐藏) */
|
|
153
|
+
isActive: boolean("is_active").notNull().default(true),
|
|
154
|
+
/** 创建时间 */
|
|
155
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
156
|
+
/** 更新时间 */
|
|
157
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull()
|
|
158
|
+
}, (table) => ({
|
|
159
|
+
/** 按画集查询作品的索引 */
|
|
160
|
+
collectionIdIndex: index("artworks_collection_id_idx").on(table.collectionId),
|
|
161
|
+
/** 按启用状态查询的索引 */
|
|
162
|
+
isActiveIndex: index("artworks_is_active_idx").on(table.isActive),
|
|
163
|
+
/** 按页面顺序排序的索引 */
|
|
164
|
+
pageOrderIndex: index("artworks_page_order_idx").on(table.pageOrder),
|
|
165
|
+
/** 画集和启用状态的复合索引(优化画集内容查询) */
|
|
166
|
+
collectionActiveIndex: index("artworks_collection_active_idx").on(table.collectionId, table.isActive),
|
|
167
|
+
/** 画集和页面顺序的复合索引(优化排序查询) */
|
|
168
|
+
collectionOrderIndex: index("artworks_collection_order_idx").on(table.collectionId, table.pageOrder),
|
|
169
|
+
/** 画集、启用状态和页面顺序的三元复合索引(优化完整查询) */
|
|
170
|
+
collectionActiveOrderIndex: index("artworks_collection_active_order_idx").on(table.collectionId, table.isActive, table.pageOrder),
|
|
171
|
+
/** 文件ID查询索引(新架构) */
|
|
172
|
+
fileIdIndex: index("artworks_file_id_idx").on(table.fileId),
|
|
173
|
+
/** 迁移状态查询索引 */
|
|
174
|
+
migrationStatusIndex: index("artworks_migration_status_idx").on(table.migrationStatus)
|
|
175
|
+
}));
|
|
176
|
+
var comicUniverseConfigsRelations = relations(comicUniverseConfigs, ({ many }) => ({
|
|
177
|
+
// 配置表通常只有一条记录,不需要关系
|
|
178
|
+
}));
|
|
179
|
+
var comicUniverseCategoriesRelations = relations(comicUniverseCategories, ({ many }) => ({
|
|
180
|
+
/** 该分类下的所有画集 */
|
|
181
|
+
collections: many(comicUniverseCollections)
|
|
182
|
+
}));
|
|
183
|
+
var comicUniverseTagsRelations = relations(comicUniverseTags, ({ many }) => ({
|
|
184
|
+
/** 该标签的所有关联记录 */
|
|
185
|
+
collectionTags: many(comicUniverseCollectionTags)
|
|
186
|
+
}));
|
|
187
|
+
var comicUniverseCollectionsRelations = relations(comicUniverseCollections, ({ one, many }) => ({
|
|
188
|
+
/** 所属分类 */
|
|
189
|
+
category: one(comicUniverseCategories, {
|
|
190
|
+
fields: [comicUniverseCollections.categoryId],
|
|
191
|
+
references: [comicUniverseCategories.id]
|
|
192
|
+
}),
|
|
193
|
+
/** 包含的所有作品页面 */
|
|
194
|
+
artworks: many(comicUniverseArtworks),
|
|
195
|
+
/** 关联的所有标签记录 */
|
|
196
|
+
collectionTags: many(comicUniverseCollectionTags)
|
|
197
|
+
}));
|
|
198
|
+
var comicUniverseCollectionTagsRelations = relations(comicUniverseCollectionTags, ({ one }) => ({
|
|
199
|
+
/** 关联的画集 */
|
|
200
|
+
collection: one(comicUniverseCollections, {
|
|
201
|
+
fields: [comicUniverseCollectionTags.collectionId],
|
|
202
|
+
references: [comicUniverseCollections.id]
|
|
203
|
+
}),
|
|
204
|
+
/** 关联的标签 */
|
|
205
|
+
tag: one(comicUniverseTags, {
|
|
206
|
+
fields: [comicUniverseCollectionTags.tagId],
|
|
207
|
+
references: [comicUniverseTags.id]
|
|
208
|
+
})
|
|
209
|
+
}));
|
|
210
|
+
var comicUniverseArtworksRelations = relations(comicUniverseArtworks, ({ one }) => ({
|
|
211
|
+
/** 所属画集 */
|
|
212
|
+
collection: one(comicUniverseCollections, {
|
|
213
|
+
fields: [comicUniverseArtworks.collectionId],
|
|
214
|
+
references: [comicUniverseCollections.id]
|
|
215
|
+
})
|
|
216
|
+
}));
|
|
217
|
+
var comicUniverseBookings = pgTable("comic_universe_bookings", {
|
|
218
|
+
/** 自增ID(用于内部管理) */
|
|
219
|
+
id: serial("id"),
|
|
220
|
+
/** 预订的画集ID(外键,级联删除) */
|
|
221
|
+
collectionId: integer("collection_id").notNull().references(() => comicUniverseCollections.id, { onDelete: "cascade" }),
|
|
222
|
+
/** 用户QQ号 */
|
|
223
|
+
qqNumber: varchar("qq_number", { length: 20 }).notNull(),
|
|
224
|
+
/** 用户手机号 */
|
|
225
|
+
phoneNumber: varchar("phone_number", { length: 20 }).notNull(),
|
|
226
|
+
/** 预订数量 */
|
|
227
|
+
quantity: integer("quantity").notNull().default(1),
|
|
228
|
+
/** 预订状态:pending(待确认)、confirmed(已确认)、completed(已完成)、cancelled(已取消) */
|
|
229
|
+
status: varchar("status", { length: 20 }).notNull().default("pending"),
|
|
230
|
+
/** 预订备注信息 */
|
|
231
|
+
notes: text("notes"),
|
|
232
|
+
/** 领取方式 */
|
|
233
|
+
pickupMethod: text("pickup_method"),
|
|
234
|
+
/** 管理员处理备注 */
|
|
235
|
+
adminNotes: text("admin_notes"),
|
|
236
|
+
/** 预订时间 */
|
|
237
|
+
createdAt: timestamp("created_at").defaultNow().notNull(),
|
|
238
|
+
/** 更新时间 */
|
|
239
|
+
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
|
240
|
+
/** 确认时间 */
|
|
241
|
+
confirmedAt: timestamp("confirmed_at"),
|
|
242
|
+
/** 完成时间 */
|
|
243
|
+
completedAt: timestamp("completed_at"),
|
|
244
|
+
/** 取消时间 */
|
|
245
|
+
cancelledAt: timestamp("cancelled_at")
|
|
246
|
+
}, (table) => ({
|
|
247
|
+
// 移除复合主键约束,允许用户对同一画集进行多次预订
|
|
248
|
+
// userCollectionPk: primaryKey({ columns: [table.qqNumber, table.phoneNumber, table.collectionId] }),
|
|
249
|
+
/** 按画集查询预订的索引 */
|
|
250
|
+
collectionIdIndex: index("bookings_collection_id_idx").on(table.collectionId),
|
|
251
|
+
/** 按状态查询的索引 */
|
|
252
|
+
statusIndex: index("bookings_status_idx").on(table.status),
|
|
253
|
+
/** 按QQ号查询的索引 */
|
|
254
|
+
qqNumberIndex: index("bookings_qq_number_idx").on(table.qqNumber),
|
|
255
|
+
/** 按手机号查询的索引 */
|
|
256
|
+
phoneNumberIndex: index("bookings_phone_number_idx").on(table.phoneNumber),
|
|
257
|
+
/** 按创建时间排序的索引 */
|
|
258
|
+
createdAtIndex: index("bookings_created_at_idx").on(table.createdAt),
|
|
259
|
+
/** 画集和状态的复合索引(优化画集预订查询) */
|
|
260
|
+
collectionStatusIndex: index("bookings_collection_status_idx").on(table.collectionId, table.status),
|
|
261
|
+
/** QQ号和状态的复合索引(优化用户预订查询) */
|
|
262
|
+
qqStatusIndex: index("bookings_qq_status_idx").on(table.qqNumber, table.status),
|
|
263
|
+
/** QQ号+手机号的复合索引(优化用户查询) */
|
|
264
|
+
userIndex: index("bookings_user_idx").on(table.qqNumber, table.phoneNumber),
|
|
265
|
+
/** QQ号+手机号+状态的复合索引(优化用户状态查询) */
|
|
266
|
+
userStatusIndex: index("bookings_user_status_idx").on(table.qqNumber, table.phoneNumber, table.status)
|
|
267
|
+
}));
|
|
268
|
+
var comicUniverseBookingsRelations = relations(comicUniverseBookings, ({ one }) => ({
|
|
269
|
+
/** 预订的画集 */
|
|
270
|
+
collection: one(comicUniverseCollections, {
|
|
271
|
+
fields: [comicUniverseBookings.collectionId],
|
|
272
|
+
references: [comicUniverseCollections.id]
|
|
273
|
+
})
|
|
274
|
+
}));
|
|
275
|
+
var popupConfigs = pgTable("popup_configs", {
|
|
276
|
+
/** 配置ID */
|
|
277
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
278
|
+
/** 配置名称 */
|
|
279
|
+
name: text("name").notNull(),
|
|
280
|
+
/** 配置描述 */
|
|
281
|
+
description: text("description"),
|
|
282
|
+
/** 弹窗类型 */
|
|
283
|
+
type: text("type").notNull().default("deadline"),
|
|
284
|
+
// deadline, announcement, etc.
|
|
285
|
+
/** 是否启用 */
|
|
286
|
+
enabled: boolean("enabled").default(false),
|
|
287
|
+
/** 触发条件配置 */
|
|
288
|
+
triggerConfig: jsonb("trigger_config").notNull().$type(),
|
|
289
|
+
/** 弹窗内容配置 */
|
|
290
|
+
contentConfig: jsonb("content_config").notNull().$type(),
|
|
291
|
+
/** 显示设置 */
|
|
292
|
+
displayConfig: jsonb("display_config").$type(),
|
|
293
|
+
/** 是否阻断流程 - true: 阻断提交,false: 仅提醒但允许继续 */
|
|
294
|
+
blockProcess: boolean("block_process").default(false),
|
|
295
|
+
/** 业务模块 */
|
|
296
|
+
businessModule: text("business_module").notNull().default("showmasterpiece"),
|
|
297
|
+
/** 业务场景 */
|
|
298
|
+
businessScene: text("business_scene").notNull().default("cart_checkout"),
|
|
299
|
+
/** 排序权重 */
|
|
300
|
+
sortOrder: text("sort_order").default("0"),
|
|
301
|
+
/** 创建时间 */
|
|
302
|
+
createdAt: timestamp("created_at").defaultNow(),
|
|
303
|
+
/** 更新时间 */
|
|
304
|
+
updatedAt: timestamp("updated_at").defaultNow()
|
|
305
|
+
});
|
|
306
|
+
var popupConfigsRelations = relations(popupConfigs, () => ({}));
|
|
307
|
+
var showmasterConfigCategories = pgTable("showmaster_config_categories", {
|
|
308
|
+
/** 配置分类ID */
|
|
309
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
310
|
+
/** 分类名称(用于代码引用) */
|
|
311
|
+
name: text("name").notNull(),
|
|
312
|
+
/** 显示名称(用于界面显示) */
|
|
313
|
+
displayName: text("display_name").notNull(),
|
|
314
|
+
/** 分类描述 */
|
|
315
|
+
description: text("description"),
|
|
316
|
+
/** 分类图标 */
|
|
317
|
+
icon: text("icon"),
|
|
318
|
+
/** 排序顺序 */
|
|
319
|
+
sortOrder: integer("sort_order").default(0),
|
|
320
|
+
/** 是否激活 */
|
|
321
|
+
isActive: boolean("is_active").default(true),
|
|
322
|
+
/** 创建时间 */
|
|
323
|
+
createdAt: timestamp("created_at").defaultNow(),
|
|
324
|
+
/** 更新时间 */
|
|
325
|
+
updatedAt: timestamp("updated_at").defaultNow()
|
|
326
|
+
});
|
|
327
|
+
var showmasterConfigItems = pgTable("showmaster_config_items", {
|
|
328
|
+
/** 配置项ID */
|
|
329
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
330
|
+
/** 分类ID */
|
|
331
|
+
categoryId: text("category_id").references(() => showmasterConfigCategories.id),
|
|
332
|
+
/** 配置键(必须唯一) */
|
|
333
|
+
key: text("key").notNull().unique(),
|
|
334
|
+
/** 显示名称 */
|
|
335
|
+
displayName: text("display_name").notNull(),
|
|
336
|
+
/** 配置描述 */
|
|
337
|
+
description: text("description"),
|
|
338
|
+
/** 配置值 */
|
|
339
|
+
value: text("value"),
|
|
340
|
+
/** 默认值 */
|
|
341
|
+
defaultValue: text("default_value"),
|
|
342
|
+
/** 配置类型:string, number, boolean, json, password */
|
|
343
|
+
type: text("type").notNull(),
|
|
344
|
+
/** 是否必填 */
|
|
345
|
+
isRequired: boolean("is_required").default(false),
|
|
346
|
+
/** 是否敏感信息 */
|
|
347
|
+
isSensitive: boolean("is_sensitive").default(false),
|
|
348
|
+
/** 验证规则(JSON格式) */
|
|
349
|
+
validation: jsonb("validation"),
|
|
350
|
+
/** 排序顺序 */
|
|
351
|
+
sortOrder: integer("sort_order").default(0),
|
|
352
|
+
/** 是否激活 */
|
|
353
|
+
isActive: boolean("is_active").default(true),
|
|
354
|
+
/** 环境标识(development, production, testing等) */
|
|
355
|
+
environment: text("environment").default("development"),
|
|
356
|
+
/** 创建时间 */
|
|
357
|
+
createdAt: timestamp("created_at").defaultNow(),
|
|
358
|
+
/** 更新时间 */
|
|
359
|
+
updatedAt: timestamp("updated_at").defaultNow()
|
|
360
|
+
});
|
|
361
|
+
var showmasterConfigHistory = pgTable("showmaster_config_history", {
|
|
362
|
+
/** 历史记录ID */
|
|
363
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
364
|
+
/** 配置项ID */
|
|
365
|
+
configItemId: text("config_item_id").references(() => showmasterConfigItems.id),
|
|
366
|
+
/** 旧值 */
|
|
367
|
+
oldValue: text("old_value"),
|
|
368
|
+
/** 新值 */
|
|
369
|
+
newValue: text("new_value"),
|
|
370
|
+
/** 修改人 */
|
|
371
|
+
changedBy: text("changed_by").notNull(),
|
|
372
|
+
/** 修改原因 */
|
|
373
|
+
changeReason: text("change_reason"),
|
|
374
|
+
/** 操作类型:create, update, delete */
|
|
375
|
+
operationType: text("operation_type").notNull(),
|
|
376
|
+
/** 环境标识 */
|
|
377
|
+
environment: text("environment").default("development"),
|
|
378
|
+
/** 创建时间 */
|
|
379
|
+
createdAt: timestamp("created_at").defaultNow()
|
|
380
|
+
});
|
|
381
|
+
var showmasterConfigPermissions = pgTable("showmaster_config_permissions", {
|
|
382
|
+
/** 权限ID */
|
|
383
|
+
id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
|
|
384
|
+
/** 用户ID */
|
|
385
|
+
userId: text("user_id").notNull(),
|
|
386
|
+
/** 分类ID */
|
|
387
|
+
categoryId: text("category_id").references(() => showmasterConfigCategories.id),
|
|
388
|
+
/** 可读权限 */
|
|
389
|
+
canRead: boolean("can_read").default(true),
|
|
390
|
+
/** 可写权限 */
|
|
391
|
+
canWrite: boolean("can_write").default(false),
|
|
392
|
+
/** 可删除权限 */
|
|
393
|
+
canDelete: boolean("can_delete").default(false),
|
|
394
|
+
/** 环境权限(可以访问的环境) */
|
|
395
|
+
allowedEnvironments: jsonb("allowed_environments").$type().default(["development"]),
|
|
396
|
+
/** 创建时间 */
|
|
397
|
+
createdAt: timestamp("created_at").defaultNow(),
|
|
398
|
+
/** 更新时间 */
|
|
399
|
+
updatedAt: timestamp("updated_at").defaultNow()
|
|
400
|
+
});
|
|
401
|
+
var ShowmasterConfigService = class {
|
|
402
|
+
constructor(db2) {
|
|
403
|
+
this.db = db2;
|
|
404
|
+
}
|
|
405
|
+
// ============= 配置分类管理 =============
|
|
406
|
+
/**
|
|
407
|
+
* 获取所有配置分类
|
|
408
|
+
*/
|
|
409
|
+
async getAllCategories() {
|
|
410
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u83B7\u53D6\u6240\u6709\u914D\u7F6E\u5206\u7C7B");
|
|
411
|
+
return await this.db.select().from(showmasterConfigCategories).where(eq(showmasterConfigCategories.isActive, true)).orderBy(asc(showmasterConfigCategories.sortOrder), asc(showmasterConfigCategories.displayName));
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* 根据ID获取配置分类
|
|
415
|
+
*/
|
|
416
|
+
async getCategoryById(id) {
|
|
417
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u83B7\u53D6\u914D\u7F6E\u5206\u7C7B:", id);
|
|
418
|
+
const [category] = await this.db.select().from(showmasterConfigCategories).where(and(
|
|
419
|
+
eq(showmasterConfigCategories.id, id),
|
|
420
|
+
eq(showmasterConfigCategories.isActive, true)
|
|
421
|
+
));
|
|
422
|
+
return category || null;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* 根据名称获取配置分类
|
|
426
|
+
*/
|
|
427
|
+
async getCategoryByName(name) {
|
|
428
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u6839\u636E\u540D\u79F0\u83B7\u53D6\u914D\u7F6E\u5206\u7C7B:", name);
|
|
429
|
+
const [category] = await this.db.select().from(showmasterConfigCategories).where(and(
|
|
430
|
+
eq(showmasterConfigCategories.name, name),
|
|
431
|
+
eq(showmasterConfigCategories.isActive, true)
|
|
432
|
+
));
|
|
433
|
+
return category || null;
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* 创建配置分类
|
|
437
|
+
*/
|
|
438
|
+
async createCategory(data) {
|
|
439
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u521B\u5EFA\u914D\u7F6E\u5206\u7C7B:", data.name);
|
|
440
|
+
const [category] = await this.db.insert(showmasterConfigCategories).values({
|
|
441
|
+
...data,
|
|
442
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
443
|
+
}).returning();
|
|
444
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u5206\u7C7B\u521B\u5EFA\u6210\u529F:", category.id);
|
|
445
|
+
return category;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* 更新配置分类
|
|
449
|
+
*/
|
|
450
|
+
async updateCategory(id, data) {
|
|
451
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u66F4\u65B0\u914D\u7F6E\u5206\u7C7B:", id);
|
|
452
|
+
const [category] = await this.db.update(showmasterConfigCategories).set({
|
|
453
|
+
...data,
|
|
454
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
455
|
+
}).where(eq(showmasterConfigCategories.id, id)).returning();
|
|
456
|
+
if (!category) {
|
|
457
|
+
throw new Error("\u914D\u7F6E\u5206\u7C7B\u4E0D\u5B58\u5728");
|
|
458
|
+
}
|
|
459
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u5206\u7C7B\u66F4\u65B0\u6210\u529F:", category.id);
|
|
460
|
+
return category;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* 删除配置分类
|
|
464
|
+
*/
|
|
465
|
+
async deleteCategory(id) {
|
|
466
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u5220\u9664\u914D\u7F6E\u5206\u7C7B:", id);
|
|
467
|
+
await this.db.update(showmasterConfigCategories).set({
|
|
468
|
+
isActive: false,
|
|
469
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
470
|
+
}).where(eq(showmasterConfigCategories.id, id));
|
|
471
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u5206\u7C7B\u5220\u9664\u6210\u529F:", id);
|
|
472
|
+
}
|
|
473
|
+
// ============= 配置项管理 =============
|
|
474
|
+
/**
|
|
475
|
+
* 获取配置项列表(支持分页和搜索)
|
|
476
|
+
*/
|
|
477
|
+
async getConfigItems(params = {}) {
|
|
478
|
+
const {
|
|
479
|
+
categoryId,
|
|
480
|
+
search,
|
|
481
|
+
type,
|
|
482
|
+
environment = "development",
|
|
483
|
+
isActive = true,
|
|
484
|
+
page = 1,
|
|
485
|
+
pageSize = 50
|
|
486
|
+
} = params;
|
|
487
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u83B7\u53D6\u914D\u7F6E\u9879\u5217\u8868:", { environment, page, pageSize });
|
|
488
|
+
const conditions = [];
|
|
489
|
+
if (isActive !== void 0) {
|
|
490
|
+
conditions.push(eq(showmasterConfigItems.isActive, isActive));
|
|
491
|
+
}
|
|
492
|
+
if (categoryId) {
|
|
493
|
+
conditions.push(eq(showmasterConfigItems.categoryId, categoryId));
|
|
494
|
+
}
|
|
495
|
+
if (type) {
|
|
496
|
+
conditions.push(eq(showmasterConfigItems.type, type));
|
|
497
|
+
}
|
|
498
|
+
if (environment) {
|
|
499
|
+
conditions.push(eq(showmasterConfigItems.environment, environment));
|
|
500
|
+
}
|
|
501
|
+
if (search) {
|
|
502
|
+
conditions.push(
|
|
503
|
+
sql`(${showmasterConfigItems.key} ILIKE ${"%" + search + "%"} OR
|
|
504
|
+
${showmasterConfigItems.displayName} ILIKE ${"%" + search + "%"} OR
|
|
505
|
+
${showmasterConfigItems.description} ILIKE ${"%" + search + "%"})`
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
const whereCondition = conditions.length > 0 ? and(...conditions) : void 0;
|
|
509
|
+
const [{ totalCount }] = await this.db.select({ totalCount: count() }).from(showmasterConfigItems).where(whereCondition);
|
|
510
|
+
const items = await this.db.select().from(showmasterConfigItems).where(whereCondition).orderBy(asc(showmasterConfigItems.sortOrder), asc(showmasterConfigItems.displayName)).limit(pageSize).offset((page - 1) * pageSize);
|
|
511
|
+
const totalPages = Math.ceil(totalCount / pageSize);
|
|
512
|
+
console.log(`\u2705 [ShowmasterConfigService] \u627E\u5230 ${items.length}/${totalCount} \u4E2A\u914D\u7F6E\u9879`);
|
|
513
|
+
return {
|
|
514
|
+
items,
|
|
515
|
+
total: totalCount,
|
|
516
|
+
page,
|
|
517
|
+
pageSize,
|
|
518
|
+
totalPages
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* 根据ID获取配置项
|
|
523
|
+
*/
|
|
524
|
+
async getConfigItemById(id) {
|
|
525
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u83B7\u53D6\u914D\u7F6E\u9879:", id);
|
|
526
|
+
const [item] = await this.db.select().from(showmasterConfigItems).where(eq(showmasterConfigItems.id, id));
|
|
527
|
+
return item || null;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* 根据key获取配置项
|
|
531
|
+
*/
|
|
532
|
+
async getConfigItemByKey(key, environment = "development") {
|
|
533
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u6839\u636Ekey\u83B7\u53D6\u914D\u7F6E\u9879:", key, "\u73AF\u5883:", environment);
|
|
534
|
+
const [item] = await this.db.select().from(showmasterConfigItems).where(and(
|
|
535
|
+
eq(showmasterConfigItems.key, key),
|
|
536
|
+
eq(showmasterConfigItems.environment, environment),
|
|
537
|
+
eq(showmasterConfigItems.isActive, true)
|
|
538
|
+
));
|
|
539
|
+
return item || null;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* 创建配置项
|
|
543
|
+
*/
|
|
544
|
+
async createConfigItem(data) {
|
|
545
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u521B\u5EFA\u914D\u7F6E\u9879:", data.key);
|
|
546
|
+
const existingItem = await this.getConfigItemByKey(data.key, data.environment || "development");
|
|
547
|
+
if (existingItem) {
|
|
548
|
+
throw new Error(`\u914D\u7F6E\u9879 ${data.key} \u5728 ${data.environment || "development"} \u73AF\u5883\u4E2D\u5DF2\u5B58\u5728`);
|
|
549
|
+
}
|
|
550
|
+
const [item] = await this.db.insert(showmasterConfigItems).values({
|
|
551
|
+
...data,
|
|
552
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
553
|
+
}).returning();
|
|
554
|
+
await this.recordHistory(item.id, null, item.value, "system", "create", item.environment || "development");
|
|
555
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u9879\u521B\u5EFA\u6210\u529F:", item.id);
|
|
556
|
+
return item;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* 更新配置项
|
|
560
|
+
*/
|
|
561
|
+
async updateConfigItem(id, data, changedBy = "system") {
|
|
562
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u66F4\u65B0\u914D\u7F6E\u9879:", id);
|
|
563
|
+
const oldItem = await this.getConfigItemById(id);
|
|
564
|
+
if (!oldItem) {
|
|
565
|
+
throw new Error("\u914D\u7F6E\u9879\u4E0D\u5B58\u5728");
|
|
566
|
+
}
|
|
567
|
+
const [item] = await this.db.update(showmasterConfigItems).set({
|
|
568
|
+
...data,
|
|
569
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
570
|
+
}).where(eq(showmasterConfigItems.id, id)).returning();
|
|
571
|
+
if (!item) {
|
|
572
|
+
throw new Error("\u914D\u7F6E\u9879\u4E0D\u5B58\u5728");
|
|
573
|
+
}
|
|
574
|
+
if (data.value !== void 0 && data.value !== oldItem.value) {
|
|
575
|
+
await this.recordHistory(item.id, oldItem.value, data.value, changedBy, "update", item.environment || "development");
|
|
576
|
+
}
|
|
577
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u9879\u66F4\u65B0\u6210\u529F:", item.id);
|
|
578
|
+
return item;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* 删除配置项
|
|
582
|
+
*/
|
|
583
|
+
async deleteConfigItem(id, changedBy = "system") {
|
|
584
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u5220\u9664\u914D\u7F6E\u9879:", id);
|
|
585
|
+
const item = await this.getConfigItemById(id);
|
|
586
|
+
if (!item) {
|
|
587
|
+
throw new Error("\u914D\u7F6E\u9879\u4E0D\u5B58\u5728");
|
|
588
|
+
}
|
|
589
|
+
await this.recordHistory(item.id, item.value, null, changedBy, "delete", item.environment || "development");
|
|
590
|
+
await this.db.update(showmasterConfigItems).set({
|
|
591
|
+
isActive: false,
|
|
592
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
593
|
+
}).where(eq(showmasterConfigItems.id, id));
|
|
594
|
+
console.log("\u2705 [ShowmasterConfigService] \u914D\u7F6E\u9879\u5220\u9664\u6210\u529F:", id);
|
|
595
|
+
}
|
|
596
|
+
// ============= 历史记录管理 =============
|
|
597
|
+
/**
|
|
598
|
+
* 记录配置变更历史
|
|
599
|
+
*/
|
|
600
|
+
async recordHistory(configItemId, oldValue, newValue, changedBy, operationType, environment) {
|
|
601
|
+
try {
|
|
602
|
+
await this.db.insert(showmasterConfigHistory).values({
|
|
603
|
+
configItemId,
|
|
604
|
+
oldValue,
|
|
605
|
+
newValue,
|
|
606
|
+
changedBy,
|
|
607
|
+
operationType,
|
|
608
|
+
environment
|
|
609
|
+
});
|
|
610
|
+
console.log(`\u{1F4DD} [ShowmasterConfigService] \u5386\u53F2\u8BB0\u5F55\u5DF2\u4FDD\u5B58: ${operationType} for ${configItemId}`);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
console.error("\u274C [ShowmasterConfigService] \u4FDD\u5B58\u5386\u53F2\u8BB0\u5F55\u5931\u8D25:", error);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* 获取配置项历史记录
|
|
617
|
+
*/
|
|
618
|
+
async getConfigItemHistory(configItemId, limit = 50) {
|
|
619
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u83B7\u53D6\u914D\u7F6E\u9879\u5386\u53F2:", configItemId);
|
|
620
|
+
return await this.db.select().from(showmasterConfigHistory).where(eq(showmasterConfigHistory.configItemId, configItemId)).orderBy(desc(showmasterConfigHistory.createdAt)).limit(limit);
|
|
621
|
+
}
|
|
622
|
+
// ============= 工具方法 =============
|
|
623
|
+
/**
|
|
624
|
+
* 获取配置值(带类型转换)
|
|
625
|
+
*/
|
|
626
|
+
async getConfigValue(key, environment = "development") {
|
|
627
|
+
const item = await this.getConfigItemByKey(key, environment);
|
|
628
|
+
if (!item || !item.value) {
|
|
629
|
+
return null;
|
|
630
|
+
}
|
|
631
|
+
try {
|
|
632
|
+
switch (item.type) {
|
|
633
|
+
case "number":
|
|
634
|
+
return Number(item.value);
|
|
635
|
+
case "boolean":
|
|
636
|
+
return item.value.toLowerCase() === "true";
|
|
637
|
+
case "json":
|
|
638
|
+
return JSON.parse(item.value);
|
|
639
|
+
default:
|
|
640
|
+
return item.value;
|
|
641
|
+
}
|
|
642
|
+
} catch (error) {
|
|
643
|
+
console.error(`\u274C [ShowmasterConfigService] \u914D\u7F6E\u503C\u7C7B\u578B\u8F6C\u6362\u5931\u8D25: ${key}`, error);
|
|
644
|
+
return item.value;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* 设置配置值
|
|
649
|
+
*/
|
|
650
|
+
async setConfigValue(key, value, environment = "development", changedBy = "system") {
|
|
651
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u8BBE\u7F6E\u914D\u7F6E\u503C:", key, "\u73AF\u5883:", environment);
|
|
652
|
+
const item = await this.getConfigItemByKey(key, environment);
|
|
653
|
+
if (!item) {
|
|
654
|
+
throw new Error(`\u914D\u7F6E\u9879 ${key} \u5728 ${environment} \u73AF\u5883\u4E2D\u4E0D\u5B58\u5728`);
|
|
655
|
+
}
|
|
656
|
+
let stringValue;
|
|
657
|
+
try {
|
|
658
|
+
switch (item.type) {
|
|
659
|
+
case "json":
|
|
660
|
+
stringValue = JSON.stringify(value);
|
|
661
|
+
break;
|
|
662
|
+
default:
|
|
663
|
+
stringValue = String(value);
|
|
664
|
+
break;
|
|
665
|
+
}
|
|
666
|
+
} catch (error) {
|
|
667
|
+
throw new Error(`\u914D\u7F6E\u503C\u8F6C\u6362\u5931\u8D25: ${error}`);
|
|
668
|
+
}
|
|
669
|
+
await this.updateConfigItem(item.id, { value: stringValue }, changedBy);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* 初始化默认配置分类
|
|
673
|
+
*/
|
|
674
|
+
async initializeDefaultCategories() {
|
|
675
|
+
console.log("\u{1F3A8} [ShowmasterConfigService] \u521D\u59CB\u5316\u9ED8\u8BA4\u914D\u7F6E\u5206\u7C7B");
|
|
676
|
+
const defaultCategories = [
|
|
677
|
+
{
|
|
678
|
+
name: "general",
|
|
679
|
+
displayName: "\u901A\u7528\u914D\u7F6E",
|
|
680
|
+
description: "ShowMasterPieces\u6A21\u5757\u901A\u7528\u914D\u7F6E\u9879",
|
|
681
|
+
icon: "\u2699\uFE0F",
|
|
682
|
+
sortOrder: 0
|
|
683
|
+
},
|
|
684
|
+
{
|
|
685
|
+
name: "display",
|
|
686
|
+
displayName: "\u663E\u793A\u914D\u7F6E",
|
|
687
|
+
description: "\u754C\u9762\u663E\u793A\u76F8\u5173\u914D\u7F6E",
|
|
688
|
+
icon: "\u{1F3A8}",
|
|
689
|
+
sortOrder: 1
|
|
690
|
+
},
|
|
691
|
+
{
|
|
692
|
+
name: "business",
|
|
693
|
+
displayName: "\u4E1A\u52A1\u914D\u7F6E",
|
|
694
|
+
description: "\u4E1A\u52A1\u903B\u8F91\u76F8\u5173\u914D\u7F6E",
|
|
695
|
+
icon: "\u{1F4BC}",
|
|
696
|
+
sortOrder: 2
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
name: "integration",
|
|
700
|
+
displayName: "\u96C6\u6210\u914D\u7F6E",
|
|
701
|
+
description: "\u7B2C\u4E09\u65B9\u670D\u52A1\u96C6\u6210\u914D\u7F6E",
|
|
702
|
+
icon: "\u{1F517}",
|
|
703
|
+
sortOrder: 3
|
|
704
|
+
}
|
|
705
|
+
];
|
|
706
|
+
for (const category of defaultCategories) {
|
|
707
|
+
try {
|
|
708
|
+
const existing = await this.db.select().from(showmasterConfigCategories).where(eq(showmasterConfigCategories.name, category.name));
|
|
709
|
+
if (existing.length === 0) {
|
|
710
|
+
await this.createCategory(category);
|
|
711
|
+
console.log(`\u2705 [ShowmasterConfigService] \u9ED8\u8BA4\u5206\u7C7B\u521B\u5EFA\u6210\u529F: ${category.name}`);
|
|
712
|
+
}
|
|
713
|
+
} catch (error) {
|
|
714
|
+
console.error(`\u274C [ShowmasterConfigService] \u521B\u5EFA\u9ED8\u8BA4\u5206\u7C7B\u5931\u8D25: ${category.name}`, error);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
};
|
|
719
|
+
function createShowmasterConfigService(db2) {
|
|
720
|
+
return new ShowmasterConfigService(db2);
|
|
721
|
+
}
|
|
722
|
+
var PopupConfigService = class {
|
|
723
|
+
constructor(db2) {
|
|
724
|
+
this.db = db2;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* 创建弹窗配置
|
|
728
|
+
*/
|
|
729
|
+
async createPopupConfig(data) {
|
|
730
|
+
try {
|
|
731
|
+
const [config] = await this.db.insert(popupConfigs).values({
|
|
732
|
+
...data,
|
|
733
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
734
|
+
}).returning();
|
|
735
|
+
console.log("\u2705 [PopupConfigService] \u5F39\u7A97\u914D\u7F6E\u521B\u5EFA\u6210\u529F:", config.id);
|
|
736
|
+
return config;
|
|
737
|
+
} catch (error) {
|
|
738
|
+
console.error("\u274C [PopupConfigService] \u521B\u5EFA\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
739
|
+
throw new Error("\u521B\u5EFA\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* 根据ID获取弹窗配置
|
|
744
|
+
*/
|
|
745
|
+
async getPopupConfigById(id) {
|
|
746
|
+
try {
|
|
747
|
+
const [config] = await this.db.select().from(popupConfigs).where(eq(popupConfigs.id, id)).limit(1);
|
|
748
|
+
return config || null;
|
|
749
|
+
} catch (error) {
|
|
750
|
+
console.error("\u274C [PopupConfigService] \u83B7\u53D6\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
751
|
+
throw new Error("\u83B7\u53D6\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
/**
|
|
755
|
+
* 获取指定业务场景的启用弹窗配置
|
|
756
|
+
*/
|
|
757
|
+
async getEnabledPopupConfigs(businessModule = "showmasterpiece", businessScene = "cart_checkout") {
|
|
758
|
+
try {
|
|
759
|
+
const conditions = [
|
|
760
|
+
eq(popupConfigs.enabled, true),
|
|
761
|
+
eq(popupConfigs.businessModule, businessModule),
|
|
762
|
+
eq(popupConfigs.businessScene, businessScene)
|
|
763
|
+
];
|
|
764
|
+
const configs = await this.db.select().from(popupConfigs).where(and(...conditions)).orderBy(desc(popupConfigs.sortOrder), desc(popupConfigs.createdAt));
|
|
765
|
+
console.log(`\u{1F4CA} [PopupConfigService] \u83B7\u53D6\u5230 ${configs.length} \u4E2A\u542F\u7528\u7684\u5F39\u7A97\u914D\u7F6E`);
|
|
766
|
+
return configs;
|
|
767
|
+
} catch (error) {
|
|
768
|
+
console.error("\u274C [PopupConfigService] \u83B7\u53D6\u542F\u7528\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
769
|
+
throw new Error("\u83B7\u53D6\u542F\u7528\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
/**
|
|
773
|
+
* 获取所有弹窗配置
|
|
774
|
+
*/
|
|
775
|
+
async getAllPopupConfigs() {
|
|
776
|
+
try {
|
|
777
|
+
const configs = await this.db.select().from(popupConfigs).orderBy(desc(popupConfigs.createdAt));
|
|
778
|
+
console.log(`\u{1F4CA} [PopupConfigService] \u83B7\u53D6\u5F39\u7A97\u914D\u7F6E: \u8FD4\u56DE${configs.length}\u4E2A\u914D\u7F6E`);
|
|
779
|
+
return configs;
|
|
780
|
+
} catch (error) {
|
|
781
|
+
console.error("\u274C [PopupConfigService] \u83B7\u53D6\u6240\u6709\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
782
|
+
throw new Error("\u83B7\u53D6\u6240\u6709\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
/**
|
|
786
|
+
* 更新弹窗配置
|
|
787
|
+
*/
|
|
788
|
+
async updatePopupConfig(id, data) {
|
|
789
|
+
try {
|
|
790
|
+
const [config] = await this.db.update(popupConfigs).set({
|
|
791
|
+
...data,
|
|
792
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
793
|
+
}).where(eq(popupConfigs.id, id)).returning();
|
|
794
|
+
if (!config) {
|
|
795
|
+
throw new Error("\u5F39\u7A97\u914D\u7F6E\u4E0D\u5B58\u5728");
|
|
796
|
+
}
|
|
797
|
+
console.log("\u2705 [PopupConfigService] \u5F39\u7A97\u914D\u7F6E\u66F4\u65B0\u6210\u529F:", config.id);
|
|
798
|
+
return config;
|
|
799
|
+
} catch (error) {
|
|
800
|
+
console.error("\u274C [PopupConfigService] \u66F4\u65B0\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
801
|
+
throw new Error("\u66F4\u65B0\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
/**
|
|
805
|
+
* 删除弹窗配置
|
|
806
|
+
*/
|
|
807
|
+
async deletePopupConfig(id) {
|
|
808
|
+
try {
|
|
809
|
+
const result = await this.db.delete(popupConfigs).where(eq(popupConfigs.id, id));
|
|
810
|
+
console.log("\u2705 [PopupConfigService] \u5F39\u7A97\u914D\u7F6E\u5220\u9664\u6210\u529F:", id);
|
|
811
|
+
return true;
|
|
812
|
+
} catch (error) {
|
|
813
|
+
console.error("\u274C [PopupConfigService] \u5220\u9664\u5F39\u7A97\u914D\u7F6E\u5931\u8D25:", error);
|
|
814
|
+
throw new Error("\u5220\u9664\u5F39\u7A97\u914D\u7F6E\u5931\u8D25");
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* 切换弹窗配置启用状态
|
|
819
|
+
*/
|
|
820
|
+
async togglePopupConfig(id, enabled) {
|
|
821
|
+
try {
|
|
822
|
+
const [config] = await this.db.update(popupConfigs).set({
|
|
823
|
+
enabled,
|
|
824
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
825
|
+
}).where(eq(popupConfigs.id, id)).returning();
|
|
826
|
+
if (!config) {
|
|
827
|
+
throw new Error("\u5F39\u7A97\u914D\u7F6E\u4E0D\u5B58\u5728");
|
|
828
|
+
}
|
|
829
|
+
console.log(`\u2705 [PopupConfigService] \u5F39\u7A97\u914D\u7F6E${enabled ? "\u542F\u7528" : "\u7981\u7528"}\u6210\u529F:`, config.id);
|
|
830
|
+
return config;
|
|
831
|
+
} catch (error) {
|
|
832
|
+
console.error("\u274C [PopupConfigService] \u5207\u6362\u5F39\u7A97\u914D\u7F6E\u72B6\u6001\u5931\u8D25:", error);
|
|
833
|
+
throw new Error("\u5207\u6362\u5F39\u7A97\u914D\u7F6E\u72B6\u6001\u5931\u8D25");
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* 检查是否需要显示弹窗
|
|
838
|
+
*/
|
|
839
|
+
async shouldShowPopup(businessModule = "showmasterpiece", businessScene = "cart_checkout", currentTime = /* @__PURE__ */ new Date()) {
|
|
840
|
+
try {
|
|
841
|
+
const enabledConfigs = await this.getEnabledPopupConfigs(businessModule, businessScene);
|
|
842
|
+
const triggeredConfigs = [];
|
|
843
|
+
for (const config of enabledConfigs) {
|
|
844
|
+
const { triggerConfig } = config;
|
|
845
|
+
if (triggerConfig.triggerType === "always") {
|
|
846
|
+
triggeredConfigs.push(config);
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
if (triggerConfig.deadlineTime) {
|
|
850
|
+
const deadlineTime = new Date(triggerConfig.deadlineTime);
|
|
851
|
+
const timeDiff = deadlineTime.getTime() - currentTime.getTime();
|
|
852
|
+
const minutesDiff = Math.floor(timeDiff / (1e3 * 60));
|
|
853
|
+
switch (triggerConfig.triggerType) {
|
|
854
|
+
case "after_deadline":
|
|
855
|
+
if (currentTime > deadlineTime) {
|
|
856
|
+
triggeredConfigs.push(config);
|
|
857
|
+
}
|
|
858
|
+
break;
|
|
859
|
+
case "before_deadline":
|
|
860
|
+
if (triggerConfig.advanceMinutes && minutesDiff <= triggerConfig.advanceMinutes && minutesDiff > 0) {
|
|
861
|
+
triggeredConfigs.push(config);
|
|
862
|
+
}
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
console.log(`\u{1F514} [PopupConfigService] \u68C0\u67E5\u5230 ${triggeredConfigs.length} \u4E2A\u9700\u8981\u663E\u793A\u7684\u5F39\u7A97`);
|
|
868
|
+
return triggeredConfigs;
|
|
869
|
+
} catch (error) {
|
|
870
|
+
console.error("\u274C [PopupConfigService] \u68C0\u67E5\u5F39\u7A97\u663E\u793A\u6761\u4EF6\u5931\u8D25:", error);
|
|
871
|
+
return [];
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
};
|
|
875
|
+
function createPopupConfigService(db2) {
|
|
876
|
+
return new PopupConfigService(db2);
|
|
877
|
+
}
|
|
878
|
+
var MasterpiecesConfigDbService = class {
|
|
879
|
+
constructor(db2) {
|
|
880
|
+
this.db = db2;
|
|
881
|
+
}
|
|
882
|
+
async getConfig() {
|
|
883
|
+
const configs = await this.db.select().from(comicUniverseConfigs).limit(1);
|
|
884
|
+
if (configs.length === 0) {
|
|
885
|
+
const defaultConfig = await this.createDefaultConfig();
|
|
886
|
+
return this.mapDbConfigToType(defaultConfig);
|
|
887
|
+
}
|
|
888
|
+
return this.mapDbConfigToType(configs[0]);
|
|
889
|
+
}
|
|
890
|
+
async updateConfig(configData) {
|
|
891
|
+
const configs = await this.db.select().from(comicUniverseConfigs).limit(1);
|
|
892
|
+
if (configs.length === 0) {
|
|
893
|
+
const newConfig = await this.db.insert(comicUniverseConfigs).values({
|
|
894
|
+
siteName: configData.siteName || "\u753B\u96C6\u5C55\u89C8",
|
|
895
|
+
siteDescription: configData.siteDescription || "\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\u5C55\u89C8",
|
|
896
|
+
heroTitle: configData.heroTitle || "\u827A\u672F\u753B\u96C6\u5C55\u89C8",
|
|
897
|
+
heroSubtitle: configData.heroSubtitle || "\u63A2\u7D22\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\uFF0C\u611F\u53D7\u521B\u4F5C\u7684\u9B45\u529B",
|
|
898
|
+
maxCollectionsPerPage: configData.maxCollectionsPerPage || 9,
|
|
899
|
+
enableSearch: configData.enableSearch ?? true,
|
|
900
|
+
enableCategories: configData.enableCategories ?? true,
|
|
901
|
+
homeTabConfig: normalizeHomeTabConfig(configData.homeTabConfig),
|
|
902
|
+
defaultCategory: configData.defaultCategory || "all",
|
|
903
|
+
theme: configData.theme || "light",
|
|
904
|
+
language: configData.language || "zh",
|
|
905
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
906
|
+
}).returning();
|
|
907
|
+
return this.mapDbConfigToType(newConfig[0]);
|
|
908
|
+
}
|
|
909
|
+
const updateData = { updatedAt: /* @__PURE__ */ new Date() };
|
|
910
|
+
if (configData.siteName !== void 0) updateData.siteName = configData.siteName;
|
|
911
|
+
if (configData.siteDescription !== void 0) updateData.siteDescription = configData.siteDescription;
|
|
912
|
+
if (configData.heroTitle !== void 0) updateData.heroTitle = configData.heroTitle;
|
|
913
|
+
if (configData.heroSubtitle !== void 0) updateData.heroSubtitle = configData.heroSubtitle;
|
|
914
|
+
if (configData.maxCollectionsPerPage !== void 0) updateData.maxCollectionsPerPage = configData.maxCollectionsPerPage;
|
|
915
|
+
if (configData.enableSearch !== void 0) updateData.enableSearch = configData.enableSearch;
|
|
916
|
+
if (configData.enableCategories !== void 0) updateData.enableCategories = configData.enableCategories;
|
|
917
|
+
if (configData.homeTabConfig !== void 0) updateData.homeTabConfig = normalizeHomeTabConfig(configData.homeTabConfig);
|
|
918
|
+
if (configData.defaultCategory !== void 0) updateData.defaultCategory = configData.defaultCategory;
|
|
919
|
+
if (configData.theme !== void 0) updateData.theme = configData.theme;
|
|
920
|
+
if (configData.language !== void 0) updateData.language = configData.language;
|
|
921
|
+
const updatedConfig = await this.db.update(comicUniverseConfigs).set(updateData).where(eq(comicUniverseConfigs.id, configs[0].id)).returning();
|
|
922
|
+
return this.mapDbConfigToType(updatedConfig[0]);
|
|
923
|
+
}
|
|
924
|
+
async resetConfig() {
|
|
925
|
+
await this.db.delete(comicUniverseConfigs);
|
|
926
|
+
const defaultConfig = await this.createDefaultConfig();
|
|
927
|
+
return this.mapDbConfigToType(defaultConfig);
|
|
928
|
+
}
|
|
929
|
+
async createDefaultConfig() {
|
|
930
|
+
const newConfig = await this.db.insert(comicUniverseConfigs).values({
|
|
931
|
+
siteName: "\u753B\u96C6\u5C55\u89C8",
|
|
932
|
+
siteDescription: "\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\u5C55\u89C8",
|
|
933
|
+
heroTitle: "\u827A\u672F\u753B\u96C6\u5C55\u89C8",
|
|
934
|
+
heroSubtitle: "\u63A2\u7D22\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\uFF0C\u611F\u53D7\u521B\u4F5C\u7684\u9B45\u529B",
|
|
935
|
+
maxCollectionsPerPage: 9,
|
|
936
|
+
enableSearch: true,
|
|
937
|
+
enableCategories: true,
|
|
938
|
+
homeTabConfig: buildDefaultHomeTabConfig(),
|
|
939
|
+
defaultCategory: "all",
|
|
940
|
+
theme: "light",
|
|
941
|
+
language: "zh"
|
|
942
|
+
}).returning();
|
|
943
|
+
return newConfig[0];
|
|
944
|
+
}
|
|
945
|
+
mapDbConfigToType(dbConfig) {
|
|
946
|
+
return {
|
|
947
|
+
siteName: dbConfig.siteName,
|
|
948
|
+
siteDescription: dbConfig.siteDescription,
|
|
949
|
+
heroTitle: dbConfig.heroTitle,
|
|
950
|
+
heroSubtitle: dbConfig.heroSubtitle,
|
|
951
|
+
maxCollectionsPerPage: dbConfig.maxCollectionsPerPage,
|
|
952
|
+
enableSearch: dbConfig.enableSearch,
|
|
953
|
+
enableCategories: dbConfig.enableCategories,
|
|
954
|
+
homeTabConfig: normalizeHomeTabConfig(dbConfig.homeTabConfig),
|
|
955
|
+
defaultCategory: dbConfig.defaultCategory,
|
|
956
|
+
theme: dbConfig.theme,
|
|
957
|
+
language: dbConfig.language
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
var CategoriesDbService = class {
|
|
962
|
+
constructor(db2) {
|
|
963
|
+
this.db = db2;
|
|
964
|
+
}
|
|
965
|
+
async getCategories() {
|
|
966
|
+
const conditions = [eq(comicUniverseCategories.isActive, true)];
|
|
967
|
+
const categories = await this.db.select().from(comicUniverseCategories).where(and(...conditions)).orderBy(asc(comicUniverseCategories.displayOrder), asc(comicUniverseCategories.name));
|
|
968
|
+
return categories.map((cat) => cat.name);
|
|
969
|
+
}
|
|
970
|
+
async createCategory(name, description) {
|
|
971
|
+
await this.db.insert(comicUniverseCategories).values({ name, description });
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
var TagsDbService = class {
|
|
975
|
+
constructor(db2) {
|
|
976
|
+
this.db = db2;
|
|
977
|
+
}
|
|
978
|
+
async getTags() {
|
|
979
|
+
const conditions = [eq(comicUniverseTags.isActive, true)];
|
|
980
|
+
const tags = await this.db.select().from(comicUniverseTags).where(and(...conditions)).orderBy(asc(comicUniverseTags.name));
|
|
981
|
+
return tags.map((tag) => tag.name);
|
|
982
|
+
}
|
|
983
|
+
async createTag(name, color) {
|
|
984
|
+
await this.db.insert(comicUniverseTags).values({
|
|
985
|
+
name,
|
|
986
|
+
color: color || "#3b82f6"
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
function createMasterpiecesConfigDbService(db2) {
|
|
991
|
+
return new MasterpiecesConfigDbService(db2);
|
|
992
|
+
}
|
|
993
|
+
function createCategoriesDbService(db2) {
|
|
994
|
+
return new CategoriesDbService(db2);
|
|
995
|
+
}
|
|
996
|
+
function createTagsDbService(db2) {
|
|
997
|
+
return new TagsDbService(db2);
|
|
998
|
+
}
|
|
999
|
+
var db;
|
|
1000
|
+
function initializeShowmasterpieceDb(database, resolver) {
|
|
1001
|
+
db = database;
|
|
1002
|
+
globalThis.__sa2kitShowmasterpieceResolveFileUrl = resolver;
|
|
1003
|
+
}
|
|
1004
|
+
var MasterpiecesConfigDbService2 = class {
|
|
1005
|
+
// 获取配置
|
|
1006
|
+
async getConfig() {
|
|
1007
|
+
const configs = await db.select().from(comicUniverseConfigs).limit(1);
|
|
1008
|
+
if (configs.length === 0) {
|
|
1009
|
+
const defaultConfig = await this.createDefaultConfig();
|
|
1010
|
+
return this.mapDbConfigToType(defaultConfig);
|
|
1011
|
+
}
|
|
1012
|
+
return this.mapDbConfigToType(configs[0]);
|
|
1013
|
+
}
|
|
1014
|
+
// 更新配置
|
|
1015
|
+
async updateConfig(configData) {
|
|
1016
|
+
const configs = await db.select().from(comicUniverseConfigs).limit(1);
|
|
1017
|
+
if (configs.length === 0) {
|
|
1018
|
+
const newConfig = await db.insert(comicUniverseConfigs).values({
|
|
1019
|
+
siteName: configData.siteName || "\u753B\u96C6\u5C55\u89C8",
|
|
1020
|
+
siteDescription: configData.siteDescription || "\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\u5C55\u89C8",
|
|
1021
|
+
heroTitle: configData.heroTitle || "\u827A\u672F\u753B\u96C6\u5C55\u89C8",
|
|
1022
|
+
heroSubtitle: configData.heroSubtitle || "\u63A2\u7D22\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\uFF0C\u611F\u53D7\u521B\u4F5C\u7684\u9B45\u529B",
|
|
1023
|
+
maxCollectionsPerPage: configData.maxCollectionsPerPage || 9,
|
|
1024
|
+
enableSearch: configData.enableSearch ?? true,
|
|
1025
|
+
enableCategories: configData.enableCategories ?? true,
|
|
1026
|
+
homeTabConfig: normalizeHomeTabConfig(configData.homeTabConfig),
|
|
1027
|
+
defaultCategory: configData.defaultCategory || "all",
|
|
1028
|
+
theme: configData.theme || "light",
|
|
1029
|
+
language: configData.language || "zh",
|
|
1030
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1031
|
+
}).returning();
|
|
1032
|
+
return this.mapDbConfigToType(newConfig[0]);
|
|
1033
|
+
} else {
|
|
1034
|
+
const updateData = {
|
|
1035
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1036
|
+
};
|
|
1037
|
+
if (configData.siteName !== void 0) updateData.siteName = configData.siteName;
|
|
1038
|
+
if (configData.siteDescription !== void 0) updateData.siteDescription = configData.siteDescription;
|
|
1039
|
+
if (configData.heroTitle !== void 0) updateData.heroTitle = configData.heroTitle;
|
|
1040
|
+
if (configData.heroSubtitle !== void 0) updateData.heroSubtitle = configData.heroSubtitle;
|
|
1041
|
+
if (configData.maxCollectionsPerPage !== void 0) updateData.maxCollectionsPerPage = configData.maxCollectionsPerPage;
|
|
1042
|
+
if (configData.enableSearch !== void 0) updateData.enableSearch = configData.enableSearch;
|
|
1043
|
+
if (configData.enableCategories !== void 0) updateData.enableCategories = configData.enableCategories;
|
|
1044
|
+
if (configData.homeTabConfig !== void 0) updateData.homeTabConfig = normalizeHomeTabConfig(configData.homeTabConfig);
|
|
1045
|
+
if (configData.defaultCategory !== void 0) updateData.defaultCategory = configData.defaultCategory;
|
|
1046
|
+
if (configData.theme !== void 0) updateData.theme = configData.theme;
|
|
1047
|
+
if (configData.language !== void 0) updateData.language = configData.language;
|
|
1048
|
+
const updatedConfig = await db.update(comicUniverseConfigs).set(updateData).where(eq(comicUniverseConfigs.id, configs[0].id)).returning();
|
|
1049
|
+
return this.mapDbConfigToType(updatedConfig[0]);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
// 重置为默认配置
|
|
1053
|
+
async resetConfig() {
|
|
1054
|
+
await db.delete(comicUniverseConfigs);
|
|
1055
|
+
const defaultConfig = await this.createDefaultConfig();
|
|
1056
|
+
return this.mapDbConfigToType(defaultConfig);
|
|
1057
|
+
}
|
|
1058
|
+
// 创建默认配置
|
|
1059
|
+
async createDefaultConfig() {
|
|
1060
|
+
const newConfig = await db.insert(comicUniverseConfigs).values({
|
|
1061
|
+
siteName: "\u753B\u96C6\u5C55\u89C8",
|
|
1062
|
+
siteDescription: "\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\u5C55\u89C8",
|
|
1063
|
+
heroTitle: "\u827A\u672F\u753B\u96C6\u5C55\u89C8",
|
|
1064
|
+
heroSubtitle: "\u63A2\u7D22\u7CBE\u7F8E\u7684\u827A\u672F\u4F5C\u54C1\uFF0C\u611F\u53D7\u521B\u4F5C\u7684\u9B45\u529B",
|
|
1065
|
+
maxCollectionsPerPage: 9,
|
|
1066
|
+
enableSearch: true,
|
|
1067
|
+
enableCategories: true,
|
|
1068
|
+
homeTabConfig: buildDefaultHomeTabConfig(),
|
|
1069
|
+
defaultCategory: "all",
|
|
1070
|
+
theme: "light",
|
|
1071
|
+
language: "zh"
|
|
1072
|
+
}).returning();
|
|
1073
|
+
return newConfig[0];
|
|
1074
|
+
}
|
|
1075
|
+
// 映射数据库配置到类型
|
|
1076
|
+
mapDbConfigToType(dbConfig) {
|
|
1077
|
+
return {
|
|
1078
|
+
siteName: dbConfig.siteName,
|
|
1079
|
+
siteDescription: dbConfig.siteDescription,
|
|
1080
|
+
heroTitle: dbConfig.heroTitle,
|
|
1081
|
+
heroSubtitle: dbConfig.heroSubtitle,
|
|
1082
|
+
maxCollectionsPerPage: dbConfig.maxCollectionsPerPage,
|
|
1083
|
+
enableSearch: dbConfig.enableSearch,
|
|
1084
|
+
enableCategories: dbConfig.enableCategories,
|
|
1085
|
+
homeTabConfig: normalizeHomeTabConfig(dbConfig.homeTabConfig),
|
|
1086
|
+
defaultCategory: dbConfig.defaultCategory,
|
|
1087
|
+
theme: dbConfig.theme,
|
|
1088
|
+
language: dbConfig.language
|
|
1089
|
+
};
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
var CategoriesDbService2 = class {
|
|
1093
|
+
// 获取所有分类
|
|
1094
|
+
async getCategories() {
|
|
1095
|
+
const conditions = [eq(comicUniverseCategories.isActive, true)];
|
|
1096
|
+
const categories = await db.select().from(comicUniverseCategories).where(and(...conditions)).orderBy(asc(comicUniverseCategories.displayOrder), asc(comicUniverseCategories.name));
|
|
1097
|
+
console.log(`\u{1F4CA} [CategoriesDbService] \u83B7\u53D6\u5206\u7C7B: \u8FD4\u56DE${categories.length}\u4E2A\u5206\u7C7B`);
|
|
1098
|
+
return categories.map((cat) => cat.name);
|
|
1099
|
+
}
|
|
1100
|
+
// 创建分类
|
|
1101
|
+
async createCategory(name, description) {
|
|
1102
|
+
await db.insert(comicUniverseCategories).values({
|
|
1103
|
+
name,
|
|
1104
|
+
description
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
var TagsDbService2 = class {
|
|
1109
|
+
// 获取所有标签
|
|
1110
|
+
async getTags() {
|
|
1111
|
+
const conditions = [eq(comicUniverseTags.isActive, true)];
|
|
1112
|
+
const tags = await db.select().from(comicUniverseTags).where(and(...conditions)).orderBy(asc(comicUniverseTags.name));
|
|
1113
|
+
console.log(`\u{1F4CA} [TagsDbService] \u83B7\u53D6\u6807\u7B7E: \u8FD4\u56DE${tags.length}\u4E2A\u6807\u7B7E`);
|
|
1114
|
+
return tags.map((tag) => tag.name);
|
|
1115
|
+
}
|
|
1116
|
+
// 创建标签
|
|
1117
|
+
async createTag(name, color) {
|
|
1118
|
+
await db.insert(comicUniverseTags).values({
|
|
1119
|
+
name,
|
|
1120
|
+
color: color || "#3b82f6"
|
|
1121
|
+
});
|
|
1122
|
+
}
|
|
1123
|
+
};
|
|
1124
|
+
var CollectionsDbService = class {
|
|
1125
|
+
constructor() {
|
|
1126
|
+
// 缓存配置 - 多层缓存策略
|
|
1127
|
+
this.collectionsCache = null;
|
|
1128
|
+
this.collectionsCacheTime = 0;
|
|
1129
|
+
this.collectionsOverviewCache = null;
|
|
1130
|
+
this.collectionsOverviewCacheTime = 0;
|
|
1131
|
+
// 优化缓存时间配置
|
|
1132
|
+
this.CACHE_DURATION = 10 * 60 * 1e3;
|
|
1133
|
+
// 延长到10分钟
|
|
1134
|
+
this.OVERVIEW_CACHE_DURATION = 15 * 60 * 1e3;
|
|
1135
|
+
// 概览缓存15分钟
|
|
1136
|
+
this.STALE_WHILE_REVALIDATE = 30 * 60 * 1e3;
|
|
1137
|
+
}
|
|
1138
|
+
// 过期后30分钟内可用
|
|
1139
|
+
/**
|
|
1140
|
+
* 获取所有画集 - 优化版本
|
|
1141
|
+
*
|
|
1142
|
+
* 性能问题分析:
|
|
1143
|
+
* 1. 复杂的多表关联查询 - 涉及5个表的数据整合
|
|
1144
|
+
* 2. 作品数据量大 - 包含所有作品的完整信息(特别是图片数据)
|
|
1145
|
+
* 3. N+1查询风险 - 虽然使用并行查询,但仍有优化空间
|
|
1146
|
+
* 4. 缓存策略有限 - 2分钟缓存时间较短,首次访问必须全量查询
|
|
1147
|
+
*
|
|
1148
|
+
* 优化策略:
|
|
1149
|
+
* ✅ 并行查询 - 分类、标签、作品数据并行获取
|
|
1150
|
+
* ✅ 内存缓存 - 减少重复查询
|
|
1151
|
+
* ✅ 字段选择 - 只查询必要字段
|
|
1152
|
+
* ✅ 延长缓存时间 - 从2分钟增加到10分钟
|
|
1153
|
+
* ⚠️ 需要优化 - 数据库索引、分页加载、图片懒加载
|
|
1154
|
+
*/
|
|
1155
|
+
async getAllCollections(useCache = true) {
|
|
1156
|
+
if (useCache && this.collectionsCache) {
|
|
1157
|
+
const cacheAge = Date.now() - this.collectionsCacheTime;
|
|
1158
|
+
if (cacheAge < this.CACHE_DURATION) {
|
|
1159
|
+
return this.collectionsCache;
|
|
1160
|
+
}
|
|
1161
|
+
if (cacheAge < this.STALE_WHILE_REVALIDATE) {
|
|
1162
|
+
this.refreshCacheInBackground();
|
|
1163
|
+
return this.collectionsCache;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
try {
|
|
1167
|
+
const result = await this.fetchAllCollectionsFromDb();
|
|
1168
|
+
this.collectionsCache = result;
|
|
1169
|
+
this.collectionsCacheTime = Date.now();
|
|
1170
|
+
return result;
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
console.error("\u83B7\u53D6\u753B\u96C6\u6570\u636E\u5931\u8D25:", error);
|
|
1173
|
+
if (this.collectionsCache) {
|
|
1174
|
+
console.warn("\u6570\u636E\u5E93\u67E5\u8BE2\u5931\u8D25\uFF0C\u8FD4\u56DE\u8FC7\u671F\u7F13\u5B58\u6570\u636E");
|
|
1175
|
+
return this.collectionsCache;
|
|
1176
|
+
}
|
|
1177
|
+
throw error;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* 获取画集概览 - 不包含作品详情的轻量版本
|
|
1182
|
+
* 适用于首页列表、搜索结果等场景
|
|
1183
|
+
*/
|
|
1184
|
+
async getCollectionsOverview() {
|
|
1185
|
+
if (this.collectionsOverviewCache) {
|
|
1186
|
+
const cacheAge = Date.now() - this.collectionsOverviewCacheTime;
|
|
1187
|
+
if (cacheAge < this.OVERVIEW_CACHE_DURATION) {
|
|
1188
|
+
return this.collectionsOverviewCache;
|
|
1189
|
+
}
|
|
1190
|
+
if (cacheAge < this.STALE_WHILE_REVALIDATE) {
|
|
1191
|
+
this.refreshOverviewCacheInBackground();
|
|
1192
|
+
return this.collectionsOverviewCache;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
try {
|
|
1196
|
+
const result = await this.fetchCollectionsOverviewFromDb();
|
|
1197
|
+
this.collectionsOverviewCache = result;
|
|
1198
|
+
this.collectionsOverviewCacheTime = Date.now();
|
|
1199
|
+
return result;
|
|
1200
|
+
} catch (error) {
|
|
1201
|
+
console.error("\u83B7\u53D6\u753B\u96C6\u6982\u89C8\u5931\u8D25:", error);
|
|
1202
|
+
if (this.collectionsOverviewCache) {
|
|
1203
|
+
console.warn("\u6570\u636E\u5E93\u67E5\u8BE2\u5931\u8D25\uFF0C\u8FD4\u56DE\u8FC7\u671F\u7F13\u5B58\u6570\u636E");
|
|
1204
|
+
return this.collectionsOverviewCache;
|
|
1205
|
+
}
|
|
1206
|
+
throw error;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
/**
|
|
1210
|
+
* 后台异步刷新完整缓存
|
|
1211
|
+
*/
|
|
1212
|
+
async refreshCacheInBackground() {
|
|
1213
|
+
try {
|
|
1214
|
+
const result = await this.fetchAllCollectionsFromDb();
|
|
1215
|
+
this.collectionsCache = result;
|
|
1216
|
+
this.collectionsCacheTime = Date.now();
|
|
1217
|
+
console.log("\u7F13\u5B58\u5DF2\u5728\u540E\u53F0\u66F4\u65B0");
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
console.error("\u540E\u53F0\u7F13\u5B58\u66F4\u65B0\u5931\u8D25:", error);
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* 后台异步刷新概览缓存
|
|
1224
|
+
*/
|
|
1225
|
+
async refreshOverviewCacheInBackground() {
|
|
1226
|
+
try {
|
|
1227
|
+
const result = await this.fetchCollectionsOverviewFromDb();
|
|
1228
|
+
this.collectionsOverviewCache = result;
|
|
1229
|
+
this.collectionsOverviewCacheTime = Date.now();
|
|
1230
|
+
console.log("\u6982\u89C8\u7F13\u5B58\u5DF2\u5728\u540E\u53F0\u66F4\u65B0");
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
console.error("\u540E\u53F0\u6982\u89C8\u7F13\u5B58\u66F4\u65B0\u5931\u8D25:", error);
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* 从数据库获取完整画集数据
|
|
1237
|
+
* 优化版本:不再返回Base64图片数据,只返回fileId和imageUrl
|
|
1238
|
+
*/
|
|
1239
|
+
async fetchAllCollectionsFromDb() {
|
|
1240
|
+
try {
|
|
1241
|
+
const collections = await db.select({
|
|
1242
|
+
id: comicUniverseCollections.id,
|
|
1243
|
+
title: comicUniverseCollections.title,
|
|
1244
|
+
number: comicUniverseCollections.number,
|
|
1245
|
+
coverImage: comicUniverseCollections.coverImage,
|
|
1246
|
+
coverImageFileId: comicUniverseCollections.coverImageFileId,
|
|
1247
|
+
// 新增:封面图片文件ID
|
|
1248
|
+
description: comicUniverseCollections.description,
|
|
1249
|
+
isPublished: comicUniverseCollections.isPublished,
|
|
1250
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1251
|
+
price: comicUniverseCollections.price,
|
|
1252
|
+
createdAt: comicUniverseCollections.createdAt,
|
|
1253
|
+
categoryId: comicUniverseCollections.categoryId
|
|
1254
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1255
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1256
|
+
desc(comicUniverseCollections.createdAt)
|
|
1257
|
+
);
|
|
1258
|
+
if (collections.length === 0) {
|
|
1259
|
+
return [];
|
|
1260
|
+
}
|
|
1261
|
+
const collectionIds = collections.map((c) => c.id);
|
|
1262
|
+
const [categories, tags, artworks] = await Promise.all([
|
|
1263
|
+
// 获取分类信息
|
|
1264
|
+
db.select({
|
|
1265
|
+
id: comicUniverseCategories.id,
|
|
1266
|
+
name: comicUniverseCategories.name
|
|
1267
|
+
}).from(comicUniverseCategories).where(eq(comicUniverseCategories.isActive, true)),
|
|
1268
|
+
// 获取标签信息
|
|
1269
|
+
db.select({
|
|
1270
|
+
collectionId: comicUniverseCollectionTags.collectionId,
|
|
1271
|
+
tagName: comicUniverseTags.name
|
|
1272
|
+
}).from(comicUniverseCollectionTags).innerJoin(
|
|
1273
|
+
comicUniverseTags,
|
|
1274
|
+
eq(comicUniverseCollectionTags.tagId, comicUniverseTags.id)
|
|
1275
|
+
).where(
|
|
1276
|
+
and(
|
|
1277
|
+
inArray(comicUniverseCollectionTags.collectionId, collectionIds),
|
|
1278
|
+
eq(comicUniverseTags.isActive, true)
|
|
1279
|
+
)
|
|
1280
|
+
),
|
|
1281
|
+
// 获取作品数据(只查询fileId,不查询Base64图片)
|
|
1282
|
+
db.select({
|
|
1283
|
+
collectionId: comicUniverseArtworks.collectionId,
|
|
1284
|
+
id: comicUniverseArtworks.id,
|
|
1285
|
+
title: comicUniverseArtworks.title,
|
|
1286
|
+
number: comicUniverseArtworks.number,
|
|
1287
|
+
fileId: comicUniverseArtworks.fileId,
|
|
1288
|
+
// 只查询fileId,不查询Base64图片
|
|
1289
|
+
description: comicUniverseArtworks.description,
|
|
1290
|
+
createdTime: comicUniverseArtworks.createdTime,
|
|
1291
|
+
theme: comicUniverseArtworks.theme,
|
|
1292
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
1293
|
+
}).from(comicUniverseArtworks).where(
|
|
1294
|
+
and(
|
|
1295
|
+
inArray(comicUniverseArtworks.collectionId, collectionIds),
|
|
1296
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
1297
|
+
)
|
|
1298
|
+
).orderBy(asc(comicUniverseArtworks.pageOrder))
|
|
1299
|
+
]);
|
|
1300
|
+
const categoriesMap = new Map(categories.map((cat) => [cat.id, cat.name]));
|
|
1301
|
+
const tagsMap = /* @__PURE__ */ new Map();
|
|
1302
|
+
tags.forEach((tag) => {
|
|
1303
|
+
if (!tagsMap.has(tag.collectionId)) {
|
|
1304
|
+
tagsMap.set(tag.collectionId, []);
|
|
1305
|
+
}
|
|
1306
|
+
tagsMap.get(tag.collectionId).push(tag.tagName);
|
|
1307
|
+
});
|
|
1308
|
+
const fileIdToUrlMap = /* @__PURE__ */ new Map();
|
|
1309
|
+
const allFileIds = [
|
|
1310
|
+
...collections.filter((c) => c.coverImageFileId).map((c) => c.coverImageFileId),
|
|
1311
|
+
...artworks.filter((a) => a.fileId).map((a) => a.fileId)
|
|
1312
|
+
];
|
|
1313
|
+
if (allFileIds.length > 0) {
|
|
1314
|
+
try {
|
|
1315
|
+
const { getShowMasterpieceFileConfig: getShowMasterpieceFileConfig2 } = await import('./fileService-O3W6YXCI.mjs');
|
|
1316
|
+
const configManager = await getShowMasterpieceFileConfig2();
|
|
1317
|
+
const { UniversalFileService } = await import('./UniversalFileService-TNYKO6JN.mjs');
|
|
1318
|
+
const fileService = new UniversalFileService(configManager.getConfig());
|
|
1319
|
+
await fileService.initialize();
|
|
1320
|
+
const urlPromises = allFileIds.map(async (fileId) => {
|
|
1321
|
+
try {
|
|
1322
|
+
const fileUrl = await fileService.getFileUrl(fileId);
|
|
1323
|
+
return { fileId, url: fileUrl };
|
|
1324
|
+
} catch (error) {
|
|
1325
|
+
console.warn(`\u26A0\uFE0F \u83B7\u53D6\u6587\u4EF6URL\u5931\u8D25: ${fileId}`, error);
|
|
1326
|
+
return { fileId, url: null };
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
const urlResults = await Promise.all(urlPromises);
|
|
1330
|
+
urlResults.forEach((result) => {
|
|
1331
|
+
if (result.url) {
|
|
1332
|
+
fileIdToUrlMap.set(result.fileId, result.url);
|
|
1333
|
+
}
|
|
1334
|
+
});
|
|
1335
|
+
} catch (error) {
|
|
1336
|
+
console.warn("\u26A0\uFE0F \u6279\u91CF\u83B7\u53D6\u6587\u4EF6URL\u5931\u8D25:", error);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
const artworksMap = /* @__PURE__ */ new Map();
|
|
1340
|
+
artworks.forEach((artwork) => {
|
|
1341
|
+
if (!artworksMap.has(artwork.collectionId)) {
|
|
1342
|
+
artworksMap.set(artwork.collectionId, []);
|
|
1343
|
+
}
|
|
1344
|
+
let imageUrl;
|
|
1345
|
+
if (artwork.fileId && fileIdToUrlMap.has(artwork.fileId)) {
|
|
1346
|
+
imageUrl = fileIdToUrlMap.get(artwork.fileId);
|
|
1347
|
+
} else {
|
|
1348
|
+
imageUrl = `/api/showmasterpiece/collections/${artwork.collectionId}/artworks/${artwork.id}/image`;
|
|
1349
|
+
}
|
|
1350
|
+
const artworkPage = {
|
|
1351
|
+
id: artwork.id,
|
|
1352
|
+
title: artwork.title || "",
|
|
1353
|
+
number: artwork.number || "",
|
|
1354
|
+
image: imageUrl,
|
|
1355
|
+
// 使用处理后的图片URL
|
|
1356
|
+
fileId: artwork.fileId || void 0,
|
|
1357
|
+
// 添加fileId支持
|
|
1358
|
+
description: artwork.description || "",
|
|
1359
|
+
createdTime: artwork.createdTime || "",
|
|
1360
|
+
theme: artwork.theme || "",
|
|
1361
|
+
pageOrder: artwork.pageOrder || 0
|
|
1362
|
+
// 添加pageOrder字段
|
|
1363
|
+
};
|
|
1364
|
+
artworksMap.get(artwork.collectionId).push(artworkPage);
|
|
1365
|
+
});
|
|
1366
|
+
return collections.map((collection) => {
|
|
1367
|
+
let coverImageUrl;
|
|
1368
|
+
if (collection.coverImageFileId && fileIdToUrlMap.has(collection.coverImageFileId)) {
|
|
1369
|
+
coverImageUrl = fileIdToUrlMap.get(collection.coverImageFileId);
|
|
1370
|
+
console.log(`\u{1F517} [CollectionsDbService] \u4F7F\u7528OSS URL: ${coverImageUrl}`);
|
|
1371
|
+
} else if (collection.coverImage) {
|
|
1372
|
+
coverImageUrl = collection.coverImage;
|
|
1373
|
+
console.log(`\u{1F517} [CollectionsDbService] \u4F7F\u7528\u539F\u59CB\u8DEF\u5F84: ${coverImageUrl}`);
|
|
1374
|
+
} else {
|
|
1375
|
+
coverImageUrl = "";
|
|
1376
|
+
console.log(`\u{1F517} [CollectionsDbService] \u65E0\u5C01\u9762\u56FE\u7247`);
|
|
1377
|
+
}
|
|
1378
|
+
return {
|
|
1379
|
+
id: collection.id,
|
|
1380
|
+
title: collection.title,
|
|
1381
|
+
number: collection.number,
|
|
1382
|
+
coverImage: coverImageUrl,
|
|
1383
|
+
// ✅ 使用处理后的URL
|
|
1384
|
+
coverImageFileId: collection.coverImageFileId || void 0,
|
|
1385
|
+
description: collection.description || "",
|
|
1386
|
+
category: collection.categoryId ? categoriesMap.get(collection.categoryId) || "\u753B\u96C6" : "\u753B\u96C6",
|
|
1387
|
+
tags: tagsMap.get(collection.id) || [],
|
|
1388
|
+
isPublished: collection.isPublished,
|
|
1389
|
+
price: collection.price || void 0,
|
|
1390
|
+
pages: artworksMap.get(collection.id) || []
|
|
1391
|
+
// 🚀 作品数据精简,大幅减少传输量
|
|
1392
|
+
};
|
|
1393
|
+
});
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
console.error("\u83B7\u53D6\u753B\u96C6\u5217\u8868\u5931\u8D25:", error);
|
|
1396
|
+
throw error;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* 从数据库获取画集概览数据
|
|
1401
|
+
*/
|
|
1402
|
+
async fetchCollectionsOverviewFromDb() {
|
|
1403
|
+
try {
|
|
1404
|
+
const collections = await db.select({
|
|
1405
|
+
id: comicUniverseCollections.id,
|
|
1406
|
+
title: comicUniverseCollections.title,
|
|
1407
|
+
number: comicUniverseCollections.number,
|
|
1408
|
+
coverImage: comicUniverseCollections.coverImage,
|
|
1409
|
+
coverImageFileId: comicUniverseCollections.coverImageFileId,
|
|
1410
|
+
// 新增:封面图片文件ID
|
|
1411
|
+
description: comicUniverseCollections.description,
|
|
1412
|
+
isPublished: comicUniverseCollections.isPublished,
|
|
1413
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1414
|
+
price: comicUniverseCollections.price,
|
|
1415
|
+
createdAt: comicUniverseCollections.createdAt,
|
|
1416
|
+
categoryId: comicUniverseCollections.categoryId
|
|
1417
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1418
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1419
|
+
desc(comicUniverseCollections.createdAt)
|
|
1420
|
+
);
|
|
1421
|
+
if (collections.length === 0) {
|
|
1422
|
+
return [];
|
|
1423
|
+
}
|
|
1424
|
+
const collectionIds = collections.map((c) => c.id);
|
|
1425
|
+
const [categories, tags, artworkCounts] = await Promise.all([
|
|
1426
|
+
// 获取分类信息
|
|
1427
|
+
db.select({
|
|
1428
|
+
id: comicUniverseCategories.id,
|
|
1429
|
+
name: comicUniverseCategories.name
|
|
1430
|
+
}).from(comicUniverseCategories).where(eq(comicUniverseCategories.isActive, true)),
|
|
1431
|
+
// 获取标签信息
|
|
1432
|
+
db.select({
|
|
1433
|
+
collectionId: comicUniverseCollectionTags.collectionId,
|
|
1434
|
+
tagName: comicUniverseTags.name
|
|
1435
|
+
}).from(comicUniverseCollectionTags).innerJoin(
|
|
1436
|
+
comicUniverseTags,
|
|
1437
|
+
eq(comicUniverseCollectionTags.tagId, comicUniverseTags.id)
|
|
1438
|
+
).where(
|
|
1439
|
+
and(
|
|
1440
|
+
inArray(comicUniverseCollectionTags.collectionId, collectionIds),
|
|
1441
|
+
eq(comicUniverseTags.isActive, true)
|
|
1442
|
+
)
|
|
1443
|
+
),
|
|
1444
|
+
// 获取作品数量(而不是具体作品)
|
|
1445
|
+
db.select({
|
|
1446
|
+
collectionId: comicUniverseArtworks.collectionId,
|
|
1447
|
+
count: sql`count(*)`.as("count")
|
|
1448
|
+
}).from(comicUniverseArtworks).where(
|
|
1449
|
+
and(
|
|
1450
|
+
inArray(comicUniverseArtworks.collectionId, collectionIds),
|
|
1451
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
1452
|
+
)
|
|
1453
|
+
).groupBy(comicUniverseArtworks.collectionId)
|
|
1454
|
+
]);
|
|
1455
|
+
const categoriesMap = new Map(categories.map((cat) => [cat.id, cat.name]));
|
|
1456
|
+
const tagsMap = /* @__PURE__ */ new Map();
|
|
1457
|
+
tags.forEach((tag) => {
|
|
1458
|
+
if (!tagsMap.has(tag.collectionId)) {
|
|
1459
|
+
tagsMap.set(tag.collectionId, []);
|
|
1460
|
+
}
|
|
1461
|
+
tagsMap.get(tag.collectionId).push(tag.tagName);
|
|
1462
|
+
});
|
|
1463
|
+
const artworkCountsMap = new Map(artworkCounts.map((ac) => [ac.collectionId, ac.count]));
|
|
1464
|
+
const fileIdToUrlMap = /* @__PURE__ */ new Map();
|
|
1465
|
+
const coverImageFileIds = collections.filter((c) => c.coverImageFileId).map((c) => c.coverImageFileId);
|
|
1466
|
+
if (coverImageFileIds.length > 0) {
|
|
1467
|
+
try {
|
|
1468
|
+
const { getShowMasterpieceFileConfig: getShowMasterpieceFileConfig2 } = await import('./fileService-O3W6YXCI.mjs');
|
|
1469
|
+
const configManager = await getShowMasterpieceFileConfig2();
|
|
1470
|
+
const { UniversalFileService } = await import('./UniversalFileService-TNYKO6JN.mjs');
|
|
1471
|
+
const fileService = new UniversalFileService(configManager.getConfig());
|
|
1472
|
+
await fileService.initialize();
|
|
1473
|
+
const urlPromises = coverImageFileIds.map(async (fileId) => {
|
|
1474
|
+
try {
|
|
1475
|
+
const fileUrl = await fileService.getFileUrl(fileId);
|
|
1476
|
+
return { fileId, url: fileUrl };
|
|
1477
|
+
} catch (error) {
|
|
1478
|
+
console.warn(`\u26A0\uFE0F [CollectionsDbService] \u83B7\u53D6\u5C01\u9762\u56FE\u7247URL\u5931\u8D25: ${fileId}`, error);
|
|
1479
|
+
return { fileId, url: null };
|
|
1480
|
+
}
|
|
1481
|
+
});
|
|
1482
|
+
const urlResults = await Promise.all(urlPromises);
|
|
1483
|
+
urlResults.forEach((result) => {
|
|
1484
|
+
if (result.url) {
|
|
1485
|
+
fileIdToUrlMap.set(result.fileId, result.url);
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
} catch (error) {
|
|
1489
|
+
console.warn("\u26A0\uFE0F [CollectionsDbService] \u6279\u91CF\u83B7\u53D6\u5C01\u9762\u56FE\u7247URL\u5931\u8D25:", error);
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
return collections.map((collection) => {
|
|
1493
|
+
let coverImageUrl;
|
|
1494
|
+
if (collection.coverImageFileId && fileIdToUrlMap.has(collection.coverImageFileId)) {
|
|
1495
|
+
coverImageUrl = fileIdToUrlMap.get(collection.coverImageFileId);
|
|
1496
|
+
} else {
|
|
1497
|
+
coverImageUrl = collection.coverImage || "";
|
|
1498
|
+
}
|
|
1499
|
+
console.log(`\u{1F517} [CollectionsDbService] 1\u5C01\u9762\u56FE\u7247URL: ${coverImageUrl}`);
|
|
1500
|
+
return {
|
|
1501
|
+
id: collection.id,
|
|
1502
|
+
title: collection.title,
|
|
1503
|
+
number: collection.number,
|
|
1504
|
+
coverImage: coverImageUrl,
|
|
1505
|
+
// 使用处理后的封面图片URL
|
|
1506
|
+
coverImageFileId: collection.coverImageFileId || void 0,
|
|
1507
|
+
// 新增:封面图片文件ID
|
|
1508
|
+
description: collection.description || "",
|
|
1509
|
+
category: collection.categoryId ? categoriesMap.get(collection.categoryId) || "\u753B\u96C6" : "\u753B\u96C6",
|
|
1510
|
+
tags: tagsMap.get(collection.id) || [],
|
|
1511
|
+
isPublished: collection.isPublished,
|
|
1512
|
+
price: collection.price || void 0,
|
|
1513
|
+
artworkCount: artworkCountsMap.get(collection.id) || 0
|
|
1514
|
+
};
|
|
1515
|
+
});
|
|
1516
|
+
} catch (error) {
|
|
1517
|
+
console.error("\u83B7\u53D6\u753B\u96C6\u6982\u89C8\u5931\u8D25:", error);
|
|
1518
|
+
throw error;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
// 清除缓存的方法
|
|
1522
|
+
clearCache() {
|
|
1523
|
+
this.collectionsCache = null;
|
|
1524
|
+
this.collectionsCacheTime = 0;
|
|
1525
|
+
this.collectionsOverviewCache = null;
|
|
1526
|
+
this.collectionsOverviewCacheTime = 0;
|
|
1527
|
+
}
|
|
1528
|
+
// 创建画集
|
|
1529
|
+
async createCollection(collectionData) {
|
|
1530
|
+
let categoryId = null;
|
|
1531
|
+
if (collectionData.category) {
|
|
1532
|
+
const existingCategory = await db.select().from(comicUniverseCategories).where(eq(comicUniverseCategories.name, collectionData.category)).limit(1);
|
|
1533
|
+
if (existingCategory.length > 0) {
|
|
1534
|
+
categoryId = existingCategory[0].id;
|
|
1535
|
+
} else {
|
|
1536
|
+
const newCategory = await db.insert(comicUniverseCategories).values({
|
|
1537
|
+
name: collectionData.category
|
|
1538
|
+
}).returning();
|
|
1539
|
+
categoryId = newCategory[0].id;
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
const newCollection = await db.insert(comicUniverseCollections).values({
|
|
1543
|
+
title: collectionData.title,
|
|
1544
|
+
number: collectionData.number,
|
|
1545
|
+
coverImage: collectionData.coverImage,
|
|
1546
|
+
coverImageFileId: collectionData.coverImageFileId || null,
|
|
1547
|
+
description: collectionData.description,
|
|
1548
|
+
categoryId,
|
|
1549
|
+
isPublished: collectionData.isPublished,
|
|
1550
|
+
publishedAt: collectionData.isPublished ? /* @__PURE__ */ new Date() : null,
|
|
1551
|
+
price: collectionData.price || null
|
|
1552
|
+
}).returning();
|
|
1553
|
+
if (collectionData.tags && collectionData.tags.length > 0) {
|
|
1554
|
+
await this.updateCollectionTags(newCollection[0].id, collectionData.tags);
|
|
1555
|
+
}
|
|
1556
|
+
this.clearCache();
|
|
1557
|
+
const collections = await this.getAllCollections(false);
|
|
1558
|
+
const filterCollection = collections.filter((c) => c.id === newCollection[0].id);
|
|
1559
|
+
console.log("\u{1F3A8} [createCollection] \u521B\u5EFA\u753B\u96C6\u6210\u529F:", filterCollection);
|
|
1560
|
+
return filterCollection[0];
|
|
1561
|
+
}
|
|
1562
|
+
// 更新画集
|
|
1563
|
+
async updateCollection(id, collectionData) {
|
|
1564
|
+
let categoryId = null;
|
|
1565
|
+
if (collectionData.category) {
|
|
1566
|
+
const existingCategory = await db.select().from(comicUniverseCategories).where(eq(comicUniverseCategories.name, collectionData.category)).limit(1);
|
|
1567
|
+
if (existingCategory.length > 0) {
|
|
1568
|
+
categoryId = existingCategory[0].id;
|
|
1569
|
+
} else {
|
|
1570
|
+
const newCategory = await db.insert(comicUniverseCategories).values({
|
|
1571
|
+
name: collectionData.category
|
|
1572
|
+
}).returning();
|
|
1573
|
+
categoryId = newCategory[0].id;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
await db.update(comicUniverseCollections).set({
|
|
1577
|
+
title: collectionData.title,
|
|
1578
|
+
number: collectionData.number,
|
|
1579
|
+
coverImage: collectionData.coverImage,
|
|
1580
|
+
coverImageFileId: collectionData.coverImageFileId || null,
|
|
1581
|
+
description: collectionData.description,
|
|
1582
|
+
categoryId,
|
|
1583
|
+
isPublished: collectionData.isPublished,
|
|
1584
|
+
publishedAt: collectionData.isPublished ? /* @__PURE__ */ new Date() : null,
|
|
1585
|
+
price: collectionData.price || null,
|
|
1586
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1587
|
+
}).where(eq(comicUniverseCollections.id, id));
|
|
1588
|
+
await this.updateCollectionTags(id, collectionData.tags || []);
|
|
1589
|
+
this.clearCache();
|
|
1590
|
+
const collections = await this.getAllCollections(false);
|
|
1591
|
+
return collections.find((c) => c.id === id);
|
|
1592
|
+
}
|
|
1593
|
+
// 删除画集
|
|
1594
|
+
async deleteCollection(id) {
|
|
1595
|
+
const collection = await db.select({
|
|
1596
|
+
id: comicUniverseCollections.id,
|
|
1597
|
+
title: comicUniverseCollections.title
|
|
1598
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.id, id)).limit(1);
|
|
1599
|
+
if (!collection.length) {
|
|
1600
|
+
throw new Error("\u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1601
|
+
}
|
|
1602
|
+
const collectionData = collection[0];
|
|
1603
|
+
console.log(`\u{1F5D1}\uFE0F [deleteCollection] \u5220\u9664\u753B\u96C6 ID:${id} "${collectionData.title}"`);
|
|
1604
|
+
await db.delete(comicUniverseCollections).where(eq(comicUniverseCollections.id, id));
|
|
1605
|
+
this.clearCache();
|
|
1606
|
+
}
|
|
1607
|
+
// 更新画集标签
|
|
1608
|
+
async updateCollectionTags(collectionId, tagNames) {
|
|
1609
|
+
await db.delete(comicUniverseCollectionTags).where(eq(comicUniverseCollectionTags.collectionId, collectionId));
|
|
1610
|
+
if (tagNames.length === 0) return;
|
|
1611
|
+
const tagIds = [];
|
|
1612
|
+
for (const tagName of tagNames) {
|
|
1613
|
+
const existingTag = await db.select().from(comicUniverseTags).where(eq(comicUniverseTags.name, tagName)).limit(1);
|
|
1614
|
+
if (existingTag.length > 0) {
|
|
1615
|
+
tagIds.push(existingTag[0].id);
|
|
1616
|
+
} else {
|
|
1617
|
+
const newTag = await db.insert(comicUniverseTags).values({
|
|
1618
|
+
name: tagName
|
|
1619
|
+
}).returning();
|
|
1620
|
+
tagIds.push(newTag[0].id);
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
const tagRelations = tagIds.map((tagId) => ({
|
|
1624
|
+
collectionId,
|
|
1625
|
+
tagId
|
|
1626
|
+
}));
|
|
1627
|
+
await db.insert(comicUniverseCollectionTags).values(tagRelations);
|
|
1628
|
+
}
|
|
1629
|
+
// 更新画集显示顺序
|
|
1630
|
+
async updateCollectionOrder(collectionOrders) {
|
|
1631
|
+
try {
|
|
1632
|
+
await db.transaction(async (tx) => {
|
|
1633
|
+
for (const { id, displayOrder } of collectionOrders) {
|
|
1634
|
+
await tx.update(comicUniverseCollections).set({
|
|
1635
|
+
displayOrder,
|
|
1636
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1637
|
+
}).where(eq(comicUniverseCollections.id, id));
|
|
1638
|
+
}
|
|
1639
|
+
});
|
|
1640
|
+
this.clearCache();
|
|
1641
|
+
} catch (error) {
|
|
1642
|
+
console.error("\u66F4\u65B0\u753B\u96C6\u987A\u5E8F\u5931\u8D25:", error);
|
|
1643
|
+
throw error;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
// 移动画集到指定位置
|
|
1647
|
+
async moveCollection(collectionId, targetOrder) {
|
|
1648
|
+
try {
|
|
1649
|
+
const collections = await db.select({
|
|
1650
|
+
id: comicUniverseCollections.id,
|
|
1651
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1652
|
+
createdAt: comicUniverseCollections.createdAt
|
|
1653
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1654
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1655
|
+
desc(comicUniverseCollections.createdAt),
|
|
1656
|
+
desc(comicUniverseCollections.id)
|
|
1657
|
+
);
|
|
1658
|
+
const normalized = await this.normalizeCollectionOrderIfNeeded(collections);
|
|
1659
|
+
const workingCollections = normalized ?? collections;
|
|
1660
|
+
const targetCollection = workingCollections.find((c) => c.id === collectionId);
|
|
1661
|
+
if (!targetCollection) {
|
|
1662
|
+
throw new Error("\u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1663
|
+
}
|
|
1664
|
+
const sortedCollections = workingCollections.filter((c) => c.id !== collectionId);
|
|
1665
|
+
sortedCollections.splice(targetOrder, 0, targetCollection);
|
|
1666
|
+
const updates = sortedCollections.map((collection, index3) => ({
|
|
1667
|
+
id: collection.id,
|
|
1668
|
+
displayOrder: sortedCollections.length - index3
|
|
1669
|
+
// 从高到低排序
|
|
1670
|
+
}));
|
|
1671
|
+
await this.updateCollectionOrder(updates);
|
|
1672
|
+
} catch (error) {
|
|
1673
|
+
console.error("\u79FB\u52A8\u753B\u96C6\u5931\u8D25:", error);
|
|
1674
|
+
throw error;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
// 上移画集
|
|
1678
|
+
async moveCollectionUp(collectionId) {
|
|
1679
|
+
try {
|
|
1680
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5F00\u59CB\u4E0A\u79FB\u753B\u96C6\u64CD\u4F5C\uFF0CcollectionId:", collectionId);
|
|
1681
|
+
const collections = await db.select({
|
|
1682
|
+
id: comicUniverseCollections.id,
|
|
1683
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1684
|
+
title: comicUniverseCollections.title,
|
|
1685
|
+
createdAt: comicUniverseCollections.createdAt
|
|
1686
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1687
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1688
|
+
desc(comicUniverseCollections.createdAt),
|
|
1689
|
+
desc(comicUniverseCollections.id)
|
|
1690
|
+
);
|
|
1691
|
+
const normalized = await this.normalizeCollectionOrderIfNeeded(collections);
|
|
1692
|
+
const workingCollections = normalized ?? collections;
|
|
1693
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5F53\u524D\u6570\u636E\u5E93\u6392\u5E8F\u72B6\u6001 (\u6309displayOrder\u964D\u5E8F):", {
|
|
1694
|
+
totalCount: workingCollections.length,
|
|
1695
|
+
collections: workingCollections.map((c, i) => ({
|
|
1696
|
+
dbIndex: i,
|
|
1697
|
+
id: c.id,
|
|
1698
|
+
title: c.title,
|
|
1699
|
+
displayOrder: c.displayOrder,
|
|
1700
|
+
note: i === 0 ? "(\u6570\u636E\u5E93\u7B2C\u4E00\u6761/displayOrder\u6700\u5927)" : i === workingCollections.length - 1 ? "(\u6570\u636E\u5E93\u6700\u540E\u6761/displayOrder\u6700\u5C0F)" : ""
|
|
1701
|
+
}))
|
|
1702
|
+
});
|
|
1703
|
+
const currentIndex = workingCollections.findIndex((c) => c.id === collectionId);
|
|
1704
|
+
if (currentIndex === -1) {
|
|
1705
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1706
|
+
throw new Error("\u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1707
|
+
}
|
|
1708
|
+
if (currentIndex === 0) {
|
|
1709
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u753B\u96C6\u5DF2\u7ECF\u5728\u6700\u9876\u90E8 (displayOrder\u6700\u5927\u503C)");
|
|
1710
|
+
throw new Error("\u753B\u96C6\u5DF2\u7ECF\u5728\u6700\u9876\u90E8");
|
|
1711
|
+
}
|
|
1712
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u4E0A\u79FB\u64CD\u4F5C\u8BE6\u60C5:", {
|
|
1713
|
+
targetCollection: {
|
|
1714
|
+
id: workingCollections[currentIndex].id,
|
|
1715
|
+
title: workingCollections[currentIndex].title,
|
|
1716
|
+
currentDisplayOrder: workingCollections[currentIndex].displayOrder,
|
|
1717
|
+
currentDbIndex: currentIndex
|
|
1718
|
+
},
|
|
1719
|
+
willSwapWith: {
|
|
1720
|
+
id: workingCollections[currentIndex - 1].id,
|
|
1721
|
+
title: workingCollections[currentIndex - 1].title,
|
|
1722
|
+
currentDisplayOrder: workingCollections[currentIndex - 1].displayOrder,
|
|
1723
|
+
currentDbIndex: currentIndex - 1
|
|
1724
|
+
},
|
|
1725
|
+
semantics: "\u4E0A\u79FB=\u4EA4\u6362displayOrder\u503C\uFF0C\u4F7F\u76EE\u6807\u753B\u96C6\u83B7\u5F97\u66F4\u5927\u7684displayOrder\u503C"
|
|
1726
|
+
});
|
|
1727
|
+
const targetIndex = currentIndex - 1;
|
|
1728
|
+
const currentOrder = workingCollections[targetIndex].displayOrder ?? 0;
|
|
1729
|
+
const targetOrder = workingCollections[currentIndex].displayOrder ?? 0;
|
|
1730
|
+
const updates = [
|
|
1731
|
+
{ id: workingCollections[currentIndex].id, displayOrder: currentOrder },
|
|
1732
|
+
{ id: workingCollections[targetIndex].id, displayOrder: targetOrder }
|
|
1733
|
+
];
|
|
1734
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5C06\u6267\u884C\u7684\u66F4\u65B0\u64CD\u4F5C:", {
|
|
1735
|
+
updates,
|
|
1736
|
+
explanation: "\u76EE\u6807\u753B\u96C6\u5C06\u83B7\u5F97\u66F4\u5927\u7684displayOrder\u503C\uFF0C\u4ECE\u800C\u5728\u5217\u8868\u4E2D\u4E0A\u79FB"
|
|
1737
|
+
});
|
|
1738
|
+
await this.updateCollectionOrder(updates);
|
|
1739
|
+
console.log("\u2705 [\u540E\u7AEF\u6392\u5E8F] \u4E0A\u79FB\u64CD\u4F5C\u5B8C\u6210");
|
|
1740
|
+
} catch (error) {
|
|
1741
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u4E0A\u79FB\u753B\u96C6\u5931\u8D25:", error);
|
|
1742
|
+
throw error;
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
// 下移画集
|
|
1746
|
+
async moveCollectionDown(collectionId) {
|
|
1747
|
+
try {
|
|
1748
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5F00\u59CB\u4E0B\u79FB\u753B\u96C6\u64CD\u4F5C\uFF0CcollectionId:", collectionId);
|
|
1749
|
+
const collections = await db.select({
|
|
1750
|
+
id: comicUniverseCollections.id,
|
|
1751
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1752
|
+
title: comicUniverseCollections.title,
|
|
1753
|
+
createdAt: comicUniverseCollections.createdAt
|
|
1754
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1755
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1756
|
+
desc(comicUniverseCollections.createdAt),
|
|
1757
|
+
desc(comicUniverseCollections.id)
|
|
1758
|
+
);
|
|
1759
|
+
const normalized = await this.normalizeCollectionOrderIfNeeded(collections);
|
|
1760
|
+
const workingCollections = normalized ?? collections;
|
|
1761
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5F53\u524D\u6570\u636E\u5E93\u6392\u5E8F\u72B6\u6001 (\u6309displayOrder\u964D\u5E8F):", {
|
|
1762
|
+
totalCount: workingCollections.length,
|
|
1763
|
+
collections: workingCollections.map((c, i) => ({
|
|
1764
|
+
dbIndex: i,
|
|
1765
|
+
id: c.id,
|
|
1766
|
+
title: c.title,
|
|
1767
|
+
displayOrder: c.displayOrder,
|
|
1768
|
+
note: i === 0 ? "(\u6570\u636E\u5E93\u7B2C\u4E00\u6761/displayOrder\u6700\u5927)" : i === workingCollections.length - 1 ? "(\u6570\u636E\u5E93\u6700\u540E\u6761/displayOrder\u6700\u5C0F)" : ""
|
|
1769
|
+
}))
|
|
1770
|
+
});
|
|
1771
|
+
const currentIndex = workingCollections.findIndex((c) => c.id === collectionId);
|
|
1772
|
+
if (currentIndex === -1) {
|
|
1773
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1774
|
+
throw new Error("\u753B\u96C6\u4E0D\u5B58\u5728");
|
|
1775
|
+
}
|
|
1776
|
+
if (currentIndex === workingCollections.length - 1) {
|
|
1777
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u753B\u96C6\u5DF2\u7ECF\u5728\u6700\u5E95\u90E8 (displayOrder\u6700\u5C0F\u503C)");
|
|
1778
|
+
throw new Error("\u753B\u96C6\u5DF2\u7ECF\u5728\u6700\u5E95\u90E8");
|
|
1779
|
+
}
|
|
1780
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u4E0B\u79FB\u64CD\u4F5C\u8BE6\u60C5:", {
|
|
1781
|
+
targetCollection: {
|
|
1782
|
+
id: workingCollections[currentIndex].id,
|
|
1783
|
+
title: workingCollections[currentIndex].title,
|
|
1784
|
+
currentDisplayOrder: workingCollections[currentIndex].displayOrder,
|
|
1785
|
+
currentDbIndex: currentIndex
|
|
1786
|
+
},
|
|
1787
|
+
willSwapWith: {
|
|
1788
|
+
id: workingCollections[currentIndex + 1].id,
|
|
1789
|
+
title: workingCollections[currentIndex + 1].title,
|
|
1790
|
+
currentDisplayOrder: workingCollections[currentIndex + 1].displayOrder,
|
|
1791
|
+
currentDbIndex: currentIndex + 1
|
|
1792
|
+
},
|
|
1793
|
+
semantics: "\u4E0B\u79FB=\u4EA4\u6362displayOrder\u503C\uFF0C\u4F7F\u76EE\u6807\u753B\u96C6\u83B7\u5F97\u66F4\u5C0F\u7684displayOrder\u503C"
|
|
1794
|
+
});
|
|
1795
|
+
const targetIndex = currentIndex + 1;
|
|
1796
|
+
const currentOrder = workingCollections[targetIndex].displayOrder ?? 0;
|
|
1797
|
+
const targetOrder = workingCollections[currentIndex].displayOrder ?? 0;
|
|
1798
|
+
const updates = [
|
|
1799
|
+
{ id: workingCollections[currentIndex].id, displayOrder: currentOrder },
|
|
1800
|
+
{ id: workingCollections[targetIndex].id, displayOrder: targetOrder }
|
|
1801
|
+
];
|
|
1802
|
+
console.log("\u{1F4CA} [\u540E\u7AEF\u6392\u5E8F] \u5C06\u6267\u884C\u7684\u66F4\u65B0\u64CD\u4F5C:", {
|
|
1803
|
+
updates,
|
|
1804
|
+
explanation: "\u76EE\u6807\u753B\u96C6\u5C06\u83B7\u5F97\u66F4\u5C0F\u7684displayOrder\u503C\uFF0C\u4ECE\u800C\u5728\u5217\u8868\u4E2D\u4E0B\u79FB"
|
|
1805
|
+
});
|
|
1806
|
+
await this.updateCollectionOrder(updates);
|
|
1807
|
+
console.log("\u2705 [\u540E\u7AEF\u6392\u5E8F] \u4E0B\u79FB\u64CD\u4F5C\u5B8C\u6210");
|
|
1808
|
+
} catch (error) {
|
|
1809
|
+
console.error("\u274C [\u540E\u7AEF\u6392\u5E8F] \u4E0B\u79FB\u753B\u96C6\u5931\u8D25:", error);
|
|
1810
|
+
throw error;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
async normalizeCollectionOrderIfNeeded(collections) {
|
|
1814
|
+
if (collections.length <= 1) return null;
|
|
1815
|
+
const orders = collections.map((c) => c.displayOrder ?? 0);
|
|
1816
|
+
const uniqueOrders = new Set(orders);
|
|
1817
|
+
const hasDuplicates = uniqueOrders.size !== orders.length;
|
|
1818
|
+
const hasAllZero = uniqueOrders.size === 1 && orders[0] === 0;
|
|
1819
|
+
if (!hasDuplicates && !hasAllZero) return null;
|
|
1820
|
+
const updates = collections.map((collection, index3) => ({
|
|
1821
|
+
id: collection.id,
|
|
1822
|
+
displayOrder: collections.length - index3
|
|
1823
|
+
}));
|
|
1824
|
+
await this.updateCollectionOrder(updates);
|
|
1825
|
+
return db.select({
|
|
1826
|
+
id: comicUniverseCollections.id,
|
|
1827
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
1828
|
+
createdAt: comicUniverseCollections.createdAt
|
|
1829
|
+
}).from(comicUniverseCollections).where(eq(comicUniverseCollections.isPublished, true)).orderBy(
|
|
1830
|
+
desc(comicUniverseCollections.displayOrder),
|
|
1831
|
+
desc(comicUniverseCollections.createdAt),
|
|
1832
|
+
desc(comicUniverseCollections.id)
|
|
1833
|
+
);
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
var ArtworksDbService = class {
|
|
1837
|
+
constructor(collectionsService) {
|
|
1838
|
+
this.collectionsService = collectionsService;
|
|
1839
|
+
}
|
|
1840
|
+
// 添加作品到画集
|
|
1841
|
+
async addArtworkToCollection(collectionId, artworkData) {
|
|
1842
|
+
console.log("\u{1F5C3}\uFE0F [\u6570\u636E\u5E93] \u5F00\u59CB\u6DFB\u52A0\u4F5C\u54C1\u5230\u753B\u96C6:", {
|
|
1843
|
+
collectionId,
|
|
1844
|
+
title: artworkData.title,
|
|
1845
|
+
number: artworkData.number
|
|
1846
|
+
});
|
|
1847
|
+
const maxOrder = await db.select({
|
|
1848
|
+
maxOrder: sql`COALESCE(MAX(${comicUniverseArtworks.pageOrder}), -1)`
|
|
1849
|
+
}).from(comicUniverseArtworks).where(eq(comicUniverseArtworks.collectionId, collectionId));
|
|
1850
|
+
const newOrder = (maxOrder[0]?.maxOrder || -1) + 1;
|
|
1851
|
+
console.log("\u{1F4CA} [\u6570\u636E\u5E93] \u8BA1\u7B97\u65B0\u7684\u9875\u9762\u987A\u5E8F:", newOrder);
|
|
1852
|
+
const insertData = {
|
|
1853
|
+
collectionId,
|
|
1854
|
+
title: artworkData.title,
|
|
1855
|
+
number: artworkData.number,
|
|
1856
|
+
description: artworkData.description,
|
|
1857
|
+
createdTime: artworkData.createdTime,
|
|
1858
|
+
theme: artworkData.theme,
|
|
1859
|
+
pageOrder: newOrder
|
|
1860
|
+
};
|
|
1861
|
+
if (!artworkData.fileId) {
|
|
1862
|
+
throw new Error("\u5FC5\u987B\u63D0\u4F9B\u6587\u4EF6ID\uFF0C\u8BF7\u5148\u4E0A\u4F20\u56FE\u7247");
|
|
1863
|
+
}
|
|
1864
|
+
insertData.fileId = artworkData.fileId;
|
|
1865
|
+
insertData.migrationStatus = "completed";
|
|
1866
|
+
console.log("\u{1F4C1} [\u6570\u636E\u5E93] \u4F7F\u7528\u901A\u7528\u6587\u4EF6\u670D\u52A1ID:", artworkData.fileId);
|
|
1867
|
+
const newArtwork = await db.insert(comicUniverseArtworks).values(insertData).returning();
|
|
1868
|
+
console.log("\u2705 [\u6570\u636E\u5E93] \u4F5C\u54C1\u63D2\u5165\u6210\u529F:", {
|
|
1869
|
+
id: newArtwork[0].id,
|
|
1870
|
+
collectionId: newArtwork[0].collectionId,
|
|
1871
|
+
pageOrder: newArtwork[0].pageOrder,
|
|
1872
|
+
title: newArtwork[0].title,
|
|
1873
|
+
fileId: newArtwork[0].fileId,
|
|
1874
|
+
migrationStatus: newArtwork[0].migrationStatus
|
|
1875
|
+
});
|
|
1876
|
+
this.collectionsService.clearCache();
|
|
1877
|
+
console.log("\u{1F9F9} [\u6570\u636E\u5E93] \u7F13\u5B58\u5DF2\u6E05\u9664");
|
|
1878
|
+
const result = {
|
|
1879
|
+
id: newArtwork[0].id,
|
|
1880
|
+
title: newArtwork[0].title,
|
|
1881
|
+
number: newArtwork[0].number,
|
|
1882
|
+
image: newArtwork[0].image || "",
|
|
1883
|
+
fileId: newArtwork[0].fileId || void 0,
|
|
1884
|
+
description: newArtwork[0].description || "",
|
|
1885
|
+
createdTime: newArtwork[0].createdTime || void 0,
|
|
1886
|
+
theme: newArtwork[0].theme || void 0,
|
|
1887
|
+
pageOrder: newArtwork[0].pageOrder || 0
|
|
1888
|
+
};
|
|
1889
|
+
console.log("\u{1F4E4} [\u6570\u636E\u5E93] \u8FD4\u56DE\u4F5C\u54C1\u6570\u636E:", result);
|
|
1890
|
+
return result;
|
|
1891
|
+
}
|
|
1892
|
+
// 更新作品
|
|
1893
|
+
async updateArtwork(collectionId, artworkId, artworkData) {
|
|
1894
|
+
const existingArtwork = await db.select().from(comicUniverseArtworks).where(and(
|
|
1895
|
+
eq(comicUniverseArtworks.id, artworkId),
|
|
1896
|
+
eq(comicUniverseArtworks.collectionId, collectionId)
|
|
1897
|
+
)).limit(1);
|
|
1898
|
+
if (existingArtwork.length === 0) {
|
|
1899
|
+
throw new Error(`\u4F5C\u54C1\u4E0D\u5B58\u5728\u6216\u4E0D\u5C5E\u4E8E\u6307\u5B9A\u753B\u96C6 (\u4F5C\u54C1ID: ${artworkId}, \u753B\u96C6ID: ${collectionId})`);
|
|
1900
|
+
}
|
|
1901
|
+
const updateData = {
|
|
1902
|
+
title: artworkData.title,
|
|
1903
|
+
number: artworkData.number,
|
|
1904
|
+
description: artworkData.description,
|
|
1905
|
+
createdTime: artworkData.createdTime,
|
|
1906
|
+
theme: artworkData.theme,
|
|
1907
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1908
|
+
};
|
|
1909
|
+
if (artworkData.fileId) {
|
|
1910
|
+
updateData.fileId = artworkData.fileId;
|
|
1911
|
+
updateData.migrationStatus = "completed";
|
|
1912
|
+
updateData.image = null;
|
|
1913
|
+
console.log("\u{1F4C1} [\u6570\u636E\u5E93] \u66F4\u65B0\u901A\u7528\u6587\u4EF6\u670D\u52A1ID:", artworkData.fileId);
|
|
1914
|
+
}
|
|
1915
|
+
const updatedArtwork = await db.update(comicUniverseArtworks).set(updateData).where(and(
|
|
1916
|
+
eq(comicUniverseArtworks.id, artworkId),
|
|
1917
|
+
eq(comicUniverseArtworks.collectionId, collectionId)
|
|
1918
|
+
)).returning();
|
|
1919
|
+
if (updatedArtwork.length === 0) {
|
|
1920
|
+
throw new Error("\u66F4\u65B0\u4F5C\u54C1\u5931\u8D25\uFF0C\u672A\u8FD4\u56DE\u6570\u636E");
|
|
1921
|
+
}
|
|
1922
|
+
this.collectionsService.clearCache();
|
|
1923
|
+
return {
|
|
1924
|
+
id: updatedArtwork[0].id,
|
|
1925
|
+
title: updatedArtwork[0].title,
|
|
1926
|
+
number: updatedArtwork[0].number,
|
|
1927
|
+
image: updatedArtwork[0].image || "",
|
|
1928
|
+
fileId: updatedArtwork[0].fileId || void 0,
|
|
1929
|
+
description: updatedArtwork[0].description || "",
|
|
1930
|
+
createdTime: updatedArtwork[0].createdTime || "",
|
|
1931
|
+
theme: updatedArtwork[0].theme || "",
|
|
1932
|
+
pageOrder: updatedArtwork[0].pageOrder || 0
|
|
1933
|
+
};
|
|
1934
|
+
}
|
|
1935
|
+
// 删除作品
|
|
1936
|
+
async deleteArtwork(collectionId, artworkId) {
|
|
1937
|
+
const artworkWithCollection = await db.select({
|
|
1938
|
+
artworkId: comicUniverseArtworks.id,
|
|
1939
|
+
artworkTitle: comicUniverseArtworks.title,
|
|
1940
|
+
collectionId: comicUniverseCollections.id,
|
|
1941
|
+
collectionTitle: comicUniverseCollections.title
|
|
1942
|
+
}).from(comicUniverseArtworks).leftJoin(comicUniverseCollections, eq(comicUniverseArtworks.collectionId, comicUniverseCollections.id)).where(and(
|
|
1943
|
+
eq(comicUniverseArtworks.id, artworkId),
|
|
1944
|
+
eq(comicUniverseArtworks.collectionId, collectionId)
|
|
1945
|
+
)).limit(1);
|
|
1946
|
+
if (!artworkWithCollection.length) {
|
|
1947
|
+
throw new Error("\u4F5C\u54C1\u4E0D\u5B58\u5728\u6216\u4E0D\u5C5E\u4E8E\u6307\u5B9A\u753B\u96C6");
|
|
1948
|
+
}
|
|
1949
|
+
const artwork = artworkWithCollection[0];
|
|
1950
|
+
console.log(`\u{1F5D1}\uFE0F [deleteArtwork] \u5220\u9664\u4F5C\u54C1 ID:${artworkId} "${artwork.artworkTitle}" \u4ECE\u753B\u96C6 ID:${collectionId} "${artwork.collectionTitle}"`);
|
|
1951
|
+
await db.delete(comicUniverseArtworks).where(and(
|
|
1952
|
+
eq(comicUniverseArtworks.id, artworkId),
|
|
1953
|
+
eq(comicUniverseArtworks.collectionId, collectionId)
|
|
1954
|
+
));
|
|
1955
|
+
this.collectionsService.clearCache();
|
|
1956
|
+
}
|
|
1957
|
+
// 更新作品显示顺序
|
|
1958
|
+
async updateArtworkOrder(collectionId, artworkOrders) {
|
|
1959
|
+
try {
|
|
1960
|
+
await db.transaction(async (tx) => {
|
|
1961
|
+
for (const { id, pageOrder } of artworkOrders) {
|
|
1962
|
+
await tx.update(comicUniverseArtworks).set({
|
|
1963
|
+
pageOrder,
|
|
1964
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1965
|
+
}).where(and(
|
|
1966
|
+
eq(comicUniverseArtworks.id, id),
|
|
1967
|
+
eq(comicUniverseArtworks.collectionId, collectionId)
|
|
1968
|
+
));
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
this.collectionsService.clearCache();
|
|
1972
|
+
} catch (error) {
|
|
1973
|
+
console.error("\u66F4\u65B0\u4F5C\u54C1\u987A\u5E8F\u5931\u8D25:", error);
|
|
1974
|
+
throw error;
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
// 移动作品到指定位置
|
|
1978
|
+
async moveArtwork(collectionId, artworkId, targetOrder) {
|
|
1979
|
+
try {
|
|
1980
|
+
const artworks = await db.select({
|
|
1981
|
+
id: comicUniverseArtworks.id,
|
|
1982
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
1983
|
+
}).from(comicUniverseArtworks).where(and(
|
|
1984
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
1985
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
1986
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder));
|
|
1987
|
+
const targetArtwork = artworks.find((a) => a.id === artworkId);
|
|
1988
|
+
if (!targetArtwork) {
|
|
1989
|
+
throw new Error("\u4F5C\u54C1\u4E0D\u5B58\u5728");
|
|
1990
|
+
}
|
|
1991
|
+
if (targetOrder < 0 || targetOrder >= artworks.length) {
|
|
1992
|
+
throw new Error("\u76EE\u6807\u4F4D\u7F6E\u65E0\u6548");
|
|
1993
|
+
}
|
|
1994
|
+
const sortedArtworks = artworks.filter((a) => a.id !== artworkId);
|
|
1995
|
+
sortedArtworks.splice(targetOrder, 0, targetArtwork);
|
|
1996
|
+
const updates = sortedArtworks.map((artwork, index3) => ({
|
|
1997
|
+
id: artwork.id,
|
|
1998
|
+
pageOrder: index3
|
|
1999
|
+
}));
|
|
2000
|
+
await this.updateArtworkOrder(collectionId, updates);
|
|
2001
|
+
} catch (error) {
|
|
2002
|
+
console.error("\u79FB\u52A8\u4F5C\u54C1\u5931\u8D25:", error);
|
|
2003
|
+
throw error;
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
// 上移作品
|
|
2007
|
+
async moveArtworkUp(collectionId, artworkId) {
|
|
2008
|
+
try {
|
|
2009
|
+
const artworks = await db.select({
|
|
2010
|
+
id: comicUniverseArtworks.id,
|
|
2011
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2012
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2013
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2014
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2015
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder), asc(comicUniverseArtworks.id));
|
|
2016
|
+
const pageOrders = artworks.map((a) => a.pageOrder);
|
|
2017
|
+
const hasDuplicates = pageOrders.length !== new Set(pageOrders).size;
|
|
2018
|
+
if (hasDuplicates || artworks.some((a) => a.pageOrder === null)) {
|
|
2019
|
+
console.log("\u68C0\u6D4B\u5230\u91CD\u590DpageOrder\uFF0C\u5148\u4FEE\u590D\u987A\u5E8F...");
|
|
2020
|
+
const fixUpdates = artworks.map((artwork, index3) => ({
|
|
2021
|
+
id: artwork.id,
|
|
2022
|
+
pageOrder: index3
|
|
2023
|
+
}));
|
|
2024
|
+
await this.updateArtworkOrder(collectionId, fixUpdates);
|
|
2025
|
+
const fixedArtworks = await db.select({
|
|
2026
|
+
id: comicUniverseArtworks.id,
|
|
2027
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2028
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2029
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2030
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2031
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder));
|
|
2032
|
+
artworks.splice(0, artworks.length, ...fixedArtworks);
|
|
2033
|
+
}
|
|
2034
|
+
const currentIndex = artworks.findIndex((a) => a.id === artworkId);
|
|
2035
|
+
if (currentIndex === -1) {
|
|
2036
|
+
throw new Error("\u4F5C\u54C1\u4E0D\u5B58\u5728");
|
|
2037
|
+
}
|
|
2038
|
+
if (currentIndex === 0) {
|
|
2039
|
+
throw new Error("\u4F5C\u54C1\u5DF2\u7ECF\u5728\u6700\u524D\u9762");
|
|
2040
|
+
}
|
|
2041
|
+
const targetIndex = currentIndex - 1;
|
|
2042
|
+
const currentOrder = artworks[targetIndex].pageOrder;
|
|
2043
|
+
const targetOrder = artworks[currentIndex].pageOrder;
|
|
2044
|
+
const updates = [
|
|
2045
|
+
{ id: artworks[currentIndex].id, pageOrder: currentOrder },
|
|
2046
|
+
{ id: artworks[targetIndex].id, pageOrder: targetOrder }
|
|
2047
|
+
];
|
|
2048
|
+
await this.updateArtworkOrder(collectionId, updates);
|
|
2049
|
+
} catch (error) {
|
|
2050
|
+
console.error("\u4E0A\u79FB\u4F5C\u54C1\u5931\u8D25:", error);
|
|
2051
|
+
throw error;
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
// 下移作品
|
|
2055
|
+
async moveArtworkDown(collectionId, artworkId) {
|
|
2056
|
+
try {
|
|
2057
|
+
const artworks = await db.select({
|
|
2058
|
+
id: comicUniverseArtworks.id,
|
|
2059
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2060
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2061
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2062
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2063
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder), asc(comicUniverseArtworks.id));
|
|
2064
|
+
const pageOrders = artworks.map((a) => a.pageOrder);
|
|
2065
|
+
const hasDuplicates = pageOrders.length !== new Set(pageOrders).size;
|
|
2066
|
+
if (hasDuplicates || artworks.some((a) => a.pageOrder === null)) {
|
|
2067
|
+
console.log("\u68C0\u6D4B\u5230\u91CD\u590DpageOrder\uFF0C\u5148\u4FEE\u590D\u987A\u5E8F...");
|
|
2068
|
+
const fixUpdates = artworks.map((artwork, index3) => ({
|
|
2069
|
+
id: artwork.id,
|
|
2070
|
+
pageOrder: index3
|
|
2071
|
+
}));
|
|
2072
|
+
await this.updateArtworkOrder(collectionId, fixUpdates);
|
|
2073
|
+
const fixedArtworks = await db.select({
|
|
2074
|
+
id: comicUniverseArtworks.id,
|
|
2075
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2076
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2077
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2078
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2079
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder));
|
|
2080
|
+
artworks.splice(0, artworks.length, ...fixedArtworks);
|
|
2081
|
+
}
|
|
2082
|
+
console.log("\u4E0B\u79FB\u4F5C\u54C1\u540E\u7AEF\u8C03\u8BD5\u4FE1\u606F:", {
|
|
2083
|
+
collectionId,
|
|
2084
|
+
artworkId,
|
|
2085
|
+
totalArtworks: artworks.length,
|
|
2086
|
+
artworkOrders: artworks.map((a) => ({ id: a.id, pageOrder: a.pageOrder }))
|
|
2087
|
+
});
|
|
2088
|
+
const currentIndex = artworks.findIndex((a) => a.id === artworkId);
|
|
2089
|
+
if (currentIndex === -1) {
|
|
2090
|
+
throw new Error("\u4F5C\u54C1\u4E0D\u5B58\u5728");
|
|
2091
|
+
}
|
|
2092
|
+
if (currentIndex === artworks.length - 1) {
|
|
2093
|
+
throw new Error("\u4F5C\u54C1\u5DF2\u7ECF\u5728\u6700\u540E\u9762");
|
|
2094
|
+
}
|
|
2095
|
+
const targetIndex = currentIndex + 1;
|
|
2096
|
+
const currentOrder = artworks[targetIndex].pageOrder;
|
|
2097
|
+
const targetOrder = artworks[currentIndex].pageOrder;
|
|
2098
|
+
console.log("\u4E0B\u79FB\u4EA4\u6362\u4FE1\u606F:", {
|
|
2099
|
+
currentIndex,
|
|
2100
|
+
targetIndex,
|
|
2101
|
+
currentOrder,
|
|
2102
|
+
targetOrder,
|
|
2103
|
+
currentArtworkId: artworks[currentIndex].id,
|
|
2104
|
+
targetArtworkId: artworks[targetIndex].id
|
|
2105
|
+
});
|
|
2106
|
+
const updates = [
|
|
2107
|
+
{ id: artworks[currentIndex].id, pageOrder: currentOrder },
|
|
2108
|
+
{ id: artworks[targetIndex].id, pageOrder: targetOrder }
|
|
2109
|
+
];
|
|
2110
|
+
await this.updateArtworkOrder(collectionId, updates);
|
|
2111
|
+
} catch (error) {
|
|
2112
|
+
console.error("\u4E0B\u79FB\u4F5C\u54C1\u5931\u8D25:", error);
|
|
2113
|
+
throw error;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
// 获取指定画集的所有作品(按顺序)
|
|
2117
|
+
async getArtworksByCollection(collectionId) {
|
|
2118
|
+
try {
|
|
2119
|
+
const artworks = await db.select({
|
|
2120
|
+
id: comicUniverseArtworks.id,
|
|
2121
|
+
title: comicUniverseArtworks.title,
|
|
2122
|
+
number: comicUniverseArtworks.number,
|
|
2123
|
+
fileId: comicUniverseArtworks.fileId,
|
|
2124
|
+
// 只查询fileId,不查询Base64图片
|
|
2125
|
+
description: comicUniverseArtworks.description,
|
|
2126
|
+
createdTime: comicUniverseArtworks.createdTime,
|
|
2127
|
+
theme: comicUniverseArtworks.theme,
|
|
2128
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2129
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2130
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2131
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2132
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder), asc(comicUniverseArtworks.id));
|
|
2133
|
+
const pageOrders = artworks.map((a) => a.pageOrder);
|
|
2134
|
+
const hasDuplicates = pageOrders.length !== new Set(pageOrders).size;
|
|
2135
|
+
if (hasDuplicates || artworks.some((a) => a.pageOrder === null)) {
|
|
2136
|
+
console.log("\u68C0\u6D4B\u5230\u91CD\u590D\u6216\u7A7A\u7684pageOrder\uFF0C\u5F00\u59CB\u4FEE\u590D...");
|
|
2137
|
+
const updates = artworks.map((artwork, index3) => ({
|
|
2138
|
+
id: artwork.id,
|
|
2139
|
+
pageOrder: index3
|
|
2140
|
+
}));
|
|
2141
|
+
await this.updateArtworkOrder(collectionId, updates);
|
|
2142
|
+
const fixedArtworks = await db.select({
|
|
2143
|
+
id: comicUniverseArtworks.id,
|
|
2144
|
+
title: comicUniverseArtworks.title,
|
|
2145
|
+
number: comicUniverseArtworks.number,
|
|
2146
|
+
fileId: comicUniverseArtworks.fileId,
|
|
2147
|
+
// 只查询fileId,不查询Base64图片
|
|
2148
|
+
description: comicUniverseArtworks.description,
|
|
2149
|
+
createdTime: comicUniverseArtworks.createdTime,
|
|
2150
|
+
theme: comicUniverseArtworks.theme,
|
|
2151
|
+
pageOrder: comicUniverseArtworks.pageOrder
|
|
2152
|
+
}).from(comicUniverseArtworks).where(and(
|
|
2153
|
+
eq(comicUniverseArtworks.collectionId, collectionId),
|
|
2154
|
+
eq(comicUniverseArtworks.isActive, true)
|
|
2155
|
+
)).orderBy(asc(comicUniverseArtworks.pageOrder));
|
|
2156
|
+
return await this.buildArtworkPagesWithUrls(fixedArtworks, collectionId);
|
|
2157
|
+
}
|
|
2158
|
+
return await this.buildArtworkPagesWithUrls(artworks, collectionId);
|
|
2159
|
+
} catch (error) {
|
|
2160
|
+
console.error("\u83B7\u53D6\u4F5C\u54C1\u5217\u8868\u5931\u8D25:", error);
|
|
2161
|
+
throw error;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
// 构建作品页面数据,包含正确的图片URL
|
|
2165
|
+
async buildArtworkPagesWithUrls(artworks, collectionId) {
|
|
2166
|
+
const fileIdToUrlMap = /* @__PURE__ */ new Map();
|
|
2167
|
+
const artworksWithFileId = artworks.filter((artwork) => artwork.fileId);
|
|
2168
|
+
if (artworksWithFileId.length > 0) {
|
|
2169
|
+
try {
|
|
2170
|
+
const { getShowMasterpieceFileConfig: getShowMasterpieceFileConfig2 } = await import('./fileService-O3W6YXCI.mjs');
|
|
2171
|
+
const configManager = await getShowMasterpieceFileConfig2();
|
|
2172
|
+
const { UniversalFileService } = await import('./UniversalFileService-TNYKO6JN.mjs');
|
|
2173
|
+
const fileService = new UniversalFileService(configManager.getConfig());
|
|
2174
|
+
await fileService.initialize();
|
|
2175
|
+
const urlPromises = artworksWithFileId.map(async (artwork) => {
|
|
2176
|
+
try {
|
|
2177
|
+
const fileUrl = await fileService.getFileUrl(artwork.fileId);
|
|
2178
|
+
return { fileId: artwork.fileId, url: fileUrl };
|
|
2179
|
+
} catch (error) {
|
|
2180
|
+
console.warn(`\u26A0\uFE0F [ArtworksDbService] \u83B7\u53D6\u6587\u4EF6URL\u5931\u8D25: ${artwork.fileId}`, error);
|
|
2181
|
+
return { fileId: artwork.fileId, url: null };
|
|
2182
|
+
}
|
|
2183
|
+
});
|
|
2184
|
+
const urlResults = await Promise.all(urlPromises);
|
|
2185
|
+
urlResults.forEach((result) => {
|
|
2186
|
+
if (result.url) {
|
|
2187
|
+
fileIdToUrlMap.set(result.fileId, result.url);
|
|
2188
|
+
}
|
|
2189
|
+
});
|
|
2190
|
+
} catch (error) {
|
|
2191
|
+
console.warn("\u26A0\uFE0F [ArtworksDbService] \u6279\u91CF\u83B7\u53D6\u6587\u4EF6URL\u5931\u8D25:", error);
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return artworks.map((artwork) => {
|
|
2195
|
+
let imageUrl;
|
|
2196
|
+
if (artwork.fileId && fileIdToUrlMap.has(artwork.fileId)) {
|
|
2197
|
+
imageUrl = fileIdToUrlMap.get(artwork.fileId);
|
|
2198
|
+
} else {
|
|
2199
|
+
imageUrl = `/api/showmasterpiece/collections/${collectionId}/artworks/${artwork.id}/image`;
|
|
2200
|
+
}
|
|
2201
|
+
return {
|
|
2202
|
+
id: artwork.id,
|
|
2203
|
+
title: artwork.title,
|
|
2204
|
+
number: artwork.number,
|
|
2205
|
+
image: imageUrl,
|
|
2206
|
+
// 使用OSS URL或API路径
|
|
2207
|
+
fileId: artwork.fileId || void 0,
|
|
2208
|
+
description: artwork.description || "",
|
|
2209
|
+
createdTime: artwork.createdTime || "",
|
|
2210
|
+
theme: artwork.theme || "",
|
|
2211
|
+
pageOrder: artwork.pageOrder
|
|
2212
|
+
};
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
};
|
|
2216
|
+
var masterpiecesConfigDbService = new MasterpiecesConfigDbService2();
|
|
2217
|
+
var categoriesDbService = new CategoriesDbService2();
|
|
2218
|
+
var tagsDbService = new TagsDbService2();
|
|
2219
|
+
var collectionsDbService = new CollectionsDbService();
|
|
2220
|
+
var artworksDbService = new ArtworksDbService(collectionsDbService);
|
|
2221
|
+
var BookingQueryService = class {
|
|
2222
|
+
constructor(db2) {
|
|
2223
|
+
this.db = db2;
|
|
2224
|
+
}
|
|
2225
|
+
buildAdminConditions(input) {
|
|
2226
|
+
const conditions = [];
|
|
2227
|
+
if (input.qqNumber) {
|
|
2228
|
+
conditions.push(like(comicUniverseBookings.qqNumber, `%${input.qqNumber}%`));
|
|
2229
|
+
}
|
|
2230
|
+
if (input.phoneNumber) {
|
|
2231
|
+
conditions.push(like(comicUniverseBookings.phoneNumber, `%${input.phoneNumber}%`));
|
|
2232
|
+
}
|
|
2233
|
+
if (input.status && input.status !== "all") {
|
|
2234
|
+
conditions.push(eq(comicUniverseBookings.status, input.status));
|
|
2235
|
+
}
|
|
2236
|
+
return conditions;
|
|
2237
|
+
}
|
|
2238
|
+
formatAdminBooking(booking) {
|
|
2239
|
+
return {
|
|
2240
|
+
id: booking.id,
|
|
2241
|
+
collectionId: booking.collectionId,
|
|
2242
|
+
qqNumber: booking.qqNumber,
|
|
2243
|
+
phoneNumber: booking.phoneNumber,
|
|
2244
|
+
quantity: booking.quantity,
|
|
2245
|
+
status: booking.status,
|
|
2246
|
+
notes: booking.notes,
|
|
2247
|
+
pickupMethod: booking.pickupMethod,
|
|
2248
|
+
adminNotes: booking.adminNotes,
|
|
2249
|
+
createdAt: booking.createdAt instanceof Date ? booking.createdAt.toISOString() : booking.createdAt,
|
|
2250
|
+
updatedAt: booking.updatedAt instanceof Date ? booking.updatedAt.toISOString() : booking.updatedAt,
|
|
2251
|
+
confirmedAt: booking.confirmedAt instanceof Date ? booking.confirmedAt.toISOString() : booking.confirmedAt,
|
|
2252
|
+
completedAt: booking.completedAt instanceof Date ? booking.completedAt.toISOString() : booking.completedAt,
|
|
2253
|
+
cancelledAt: booking.cancelledAt instanceof Date ? booking.cancelledAt.toISOString() : booking.cancelledAt,
|
|
2254
|
+
collection: {
|
|
2255
|
+
id: booking.collectionId,
|
|
2256
|
+
title: booking.collectionTitle || "\u672A\u77E5\u753B\u96C6",
|
|
2257
|
+
number: booking.collectionNumber || "\u672A\u77E5\u7F16\u53F7",
|
|
2258
|
+
coverImage: booking.collectionCoverImage || "",
|
|
2259
|
+
price: booking.collectionPrice || 0
|
|
2260
|
+
},
|
|
2261
|
+
totalPrice: (booking.collectionPrice || 0) * booking.quantity
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
async getAdminBookings(input = {}) {
|
|
2265
|
+
const {
|
|
2266
|
+
qqNumber,
|
|
2267
|
+
phoneNumber,
|
|
2268
|
+
status,
|
|
2269
|
+
applyFiltersToStats = true
|
|
2270
|
+
} = input;
|
|
2271
|
+
const conditions = this.buildAdminConditions({ qqNumber, phoneNumber, status });
|
|
2272
|
+
const bookings = await this.db.select({
|
|
2273
|
+
id: comicUniverseBookings.id,
|
|
2274
|
+
collectionId: comicUniverseBookings.collectionId,
|
|
2275
|
+
qqNumber: comicUniverseBookings.qqNumber,
|
|
2276
|
+
phoneNumber: comicUniverseBookings.phoneNumber,
|
|
2277
|
+
quantity: comicUniverseBookings.quantity,
|
|
2278
|
+
status: comicUniverseBookings.status,
|
|
2279
|
+
notes: comicUniverseBookings.notes,
|
|
2280
|
+
pickupMethod: comicUniverseBookings.pickupMethod,
|
|
2281
|
+
adminNotes: comicUniverseBookings.adminNotes,
|
|
2282
|
+
createdAt: comicUniverseBookings.createdAt,
|
|
2283
|
+
updatedAt: comicUniverseBookings.updatedAt,
|
|
2284
|
+
confirmedAt: comicUniverseBookings.confirmedAt,
|
|
2285
|
+
completedAt: comicUniverseBookings.completedAt,
|
|
2286
|
+
cancelledAt: comicUniverseBookings.cancelledAt,
|
|
2287
|
+
collectionTitle: comicUniverseCollections.title,
|
|
2288
|
+
collectionNumber: comicUniverseCollections.number,
|
|
2289
|
+
collectionCoverImage: comicUniverseCollections.coverImage,
|
|
2290
|
+
collectionPrice: comicUniverseCollections.price
|
|
2291
|
+
}).from(comicUniverseBookings).leftJoin(comicUniverseCollections, eq(comicUniverseBookings.collectionId, comicUniverseCollections.id)).where(conditions.length > 0 ? and(...conditions) : void 0).orderBy(desc(comicUniverseBookings.createdAt));
|
|
2292
|
+
const baseStatsQuery = this.db.select({
|
|
2293
|
+
totalBookings: sql`count(*)`,
|
|
2294
|
+
pendingBookings: sql`count(*) filter (where ${comicUniverseBookings.status} = 'pending')`,
|
|
2295
|
+
confirmedBookings: sql`count(*) filter (where ${comicUniverseBookings.status} = 'confirmed')`,
|
|
2296
|
+
completedBookings: sql`count(*) filter (where ${comicUniverseBookings.status} = 'completed')`,
|
|
2297
|
+
cancelledBookings: sql`count(*) filter (where ${comicUniverseBookings.status} = 'cancelled')`,
|
|
2298
|
+
totalQuantity: sql`coalesce(sum(${comicUniverseBookings.quantity}), 0)`,
|
|
2299
|
+
totalRevenue: sql`coalesce(sum(${comicUniverseBookings.quantity} * coalesce(${comicUniverseCollections.price}, 0)), 0)`
|
|
2300
|
+
}).from(comicUniverseBookings).leftJoin(comicUniverseCollections, eq(comicUniverseBookings.collectionId, comicUniverseCollections.id));
|
|
2301
|
+
const stats = applyFiltersToStats && conditions.length > 0 ? await baseStatsQuery.where(and(...conditions)) : await baseStatsQuery;
|
|
2302
|
+
return {
|
|
2303
|
+
bookings: bookings.map((booking) => this.formatAdminBooking(booking)),
|
|
2304
|
+
stats: {
|
|
2305
|
+
totalBookings: stats[0]?.totalBookings || 0,
|
|
2306
|
+
pendingBookings: stats[0]?.pendingBookings || 0,
|
|
2307
|
+
confirmedBookings: stats[0]?.confirmedBookings || 0,
|
|
2308
|
+
completedBookings: stats[0]?.completedBookings || 0,
|
|
2309
|
+
cancelledBookings: stats[0]?.cancelledBookings || 0,
|
|
2310
|
+
totalQuantity: stats[0]?.totalQuantity || 0,
|
|
2311
|
+
totalRevenue: stats[0]?.totalRevenue || 0
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
async getBookableCollections(input = {}) {
|
|
2316
|
+
const conditions = [eq(comicUniverseCollections.isPublished, true)];
|
|
2317
|
+
if (input.categoryId) {
|
|
2318
|
+
conditions.push(eq(comicUniverseCollections.categoryId, input.categoryId));
|
|
2319
|
+
}
|
|
2320
|
+
let orderByClause;
|
|
2321
|
+
switch (input.orderBy) {
|
|
2322
|
+
case "createdAt":
|
|
2323
|
+
orderByClause = desc(comicUniverseCollections.createdAt);
|
|
2324
|
+
break;
|
|
2325
|
+
case "title":
|
|
2326
|
+
orderByClause = asc(comicUniverseCollections.title);
|
|
2327
|
+
break;
|
|
2328
|
+
case "displayOrder":
|
|
2329
|
+
default:
|
|
2330
|
+
orderByClause = asc(comicUniverseCollections.displayOrder);
|
|
2331
|
+
break;
|
|
2332
|
+
}
|
|
2333
|
+
const limit = Math.min(100, Math.max(1, input.limit ?? 50));
|
|
2334
|
+
const collections = await this.db.select({
|
|
2335
|
+
id: comicUniverseCollections.id,
|
|
2336
|
+
title: comicUniverseCollections.title,
|
|
2337
|
+
number: comicUniverseCollections.number,
|
|
2338
|
+
coverImage: comicUniverseCollections.coverImage,
|
|
2339
|
+
price: comicUniverseCollections.price,
|
|
2340
|
+
description: comicUniverseCollections.description,
|
|
2341
|
+
displayOrder: comicUniverseCollections.displayOrder,
|
|
2342
|
+
createdAt: comicUniverseCollections.createdAt
|
|
2343
|
+
}).from(comicUniverseCollections).where(and(...conditions)).orderBy(orderByClause).limit(limit);
|
|
2344
|
+
return collections.map((collection) => ({
|
|
2345
|
+
id: collection.id,
|
|
2346
|
+
title: collection.title,
|
|
2347
|
+
number: collection.number,
|
|
2348
|
+
coverImage: collection.coverImage,
|
|
2349
|
+
price: collection.price,
|
|
2350
|
+
description: collection.description,
|
|
2351
|
+
displayOrder: collection.displayOrder,
|
|
2352
|
+
createdAt: collection.createdAt?.toISOString()
|
|
2353
|
+
}));
|
|
2354
|
+
}
|
|
2355
|
+
async exportBookingsCsv() {
|
|
2356
|
+
const bookings = await this.db.select({
|
|
2357
|
+
id: comicUniverseBookings.id,
|
|
2358
|
+
qqNumber: comicUniverseBookings.qqNumber,
|
|
2359
|
+
phoneNumber: comicUniverseBookings.phoneNumber,
|
|
2360
|
+
collectionId: comicUniverseBookings.collectionId,
|
|
2361
|
+
status: comicUniverseBookings.status,
|
|
2362
|
+
quantity: comicUniverseBookings.quantity,
|
|
2363
|
+
notes: comicUniverseBookings.notes,
|
|
2364
|
+
pickupMethod: comicUniverseBookings.pickupMethod,
|
|
2365
|
+
adminNotes: comicUniverseBookings.adminNotes,
|
|
2366
|
+
createdAt: comicUniverseBookings.createdAt,
|
|
2367
|
+
updatedAt: comicUniverseBookings.updatedAt,
|
|
2368
|
+
confirmedAt: comicUniverseBookings.confirmedAt,
|
|
2369
|
+
completedAt: comicUniverseBookings.completedAt,
|
|
2370
|
+
cancelledAt: comicUniverseBookings.cancelledAt,
|
|
2371
|
+
collectionTitle: comicUniverseCollections.title,
|
|
2372
|
+
collectionNumber: comicUniverseCollections.number,
|
|
2373
|
+
collectionPrice: comicUniverseCollections.price
|
|
2374
|
+
}).from(comicUniverseBookings).leftJoin(comicUniverseCollections, eq(comicUniverseBookings.collectionId, comicUniverseCollections.id)).orderBy(comicUniverseBookings.createdAt);
|
|
2375
|
+
const headers = [
|
|
2376
|
+
"\u9884\u8BA2ID",
|
|
2377
|
+
"QQ\u53F7",
|
|
2378
|
+
"\u624B\u673A\u53F7",
|
|
2379
|
+
"\u753B\u96C6ID",
|
|
2380
|
+
"\u753B\u96C6\u6807\u9898",
|
|
2381
|
+
"\u753B\u96C6\u7F16\u53F7",
|
|
2382
|
+
"\u753B\u96C6\u4EF7\u683C",
|
|
2383
|
+
"\u9884\u8BA2\u72B6\u6001",
|
|
2384
|
+
"\u9884\u8BA2\u6570\u91CF",
|
|
2385
|
+
"\u7528\u6237\u5907\u6CE8",
|
|
2386
|
+
"\u9886\u53D6\u65B9\u5F0F",
|
|
2387
|
+
"\u7BA1\u7406\u5458\u5907\u6CE8",
|
|
2388
|
+
"\u521B\u5EFA\u65F6\u95F4",
|
|
2389
|
+
"\u66F4\u65B0\u65F6\u95F4",
|
|
2390
|
+
"\u786E\u8BA4\u65F6\u95F4",
|
|
2391
|
+
"\u5B8C\u6210\u65F6\u95F4",
|
|
2392
|
+
"\u53D6\u6D88\u65F6\u95F4"
|
|
2393
|
+
];
|
|
2394
|
+
const statusMap = {
|
|
2395
|
+
pending: "\u5F85\u786E\u8BA4",
|
|
2396
|
+
confirmed: "\u5DF2\u786E\u8BA4",
|
|
2397
|
+
completed: "\u5DF2\u5B8C\u6210",
|
|
2398
|
+
cancelled: "\u5DF2\u53D6\u6D88"
|
|
2399
|
+
};
|
|
2400
|
+
const formatTime = (value) => {
|
|
2401
|
+
if (!value) return "";
|
|
2402
|
+
return new Date(value).toLocaleString("zh-CN");
|
|
2403
|
+
};
|
|
2404
|
+
const rows = bookings.map((booking) => [
|
|
2405
|
+
booking.id,
|
|
2406
|
+
booking.qqNumber || "",
|
|
2407
|
+
booking.phoneNumber || "",
|
|
2408
|
+
booking.collectionId,
|
|
2409
|
+
booking.collectionTitle || "",
|
|
2410
|
+
booking.collectionNumber || "",
|
|
2411
|
+
booking.collectionPrice || "",
|
|
2412
|
+
statusMap[booking.status] || booking.status,
|
|
2413
|
+
booking.quantity,
|
|
2414
|
+
booking.notes || "",
|
|
2415
|
+
booking.pickupMethod || "",
|
|
2416
|
+
booking.adminNotes || "",
|
|
2417
|
+
formatTime(booking.createdAt),
|
|
2418
|
+
formatTime(booking.updatedAt),
|
|
2419
|
+
formatTime(booking.confirmedAt),
|
|
2420
|
+
formatTime(booking.completedAt),
|
|
2421
|
+
formatTime(booking.cancelledAt)
|
|
2422
|
+
]);
|
|
2423
|
+
const BOM = "\uFEFF";
|
|
2424
|
+
return BOM + headers.join(",") + "\n" + rows.map(
|
|
2425
|
+
(row) => row.map((cell) => {
|
|
2426
|
+
const cellStr = String(cell || "");
|
|
2427
|
+
if (cellStr.includes(",") || cellStr.includes('"') || cellStr.includes("\n")) {
|
|
2428
|
+
return `"${cellStr.replace(/"/g, '""')}"`;
|
|
2429
|
+
}
|
|
2430
|
+
return cellStr;
|
|
2431
|
+
}).join(",")
|
|
2432
|
+
).join("\n");
|
|
2433
|
+
}
|
|
2434
|
+
async getBookingsList(input = {}) {
|
|
2435
|
+
const conditions = [];
|
|
2436
|
+
if (input.collectionId) {
|
|
2437
|
+
conditions.push(eq(comicUniverseBookings.collectionId, input.collectionId));
|
|
2438
|
+
}
|
|
2439
|
+
if (input.qqNumber) {
|
|
2440
|
+
conditions.push(like(comicUniverseBookings.qqNumber, `%${input.qqNumber}%`));
|
|
2441
|
+
}
|
|
2442
|
+
if (input.phoneNumber) {
|
|
2443
|
+
conditions.push(like(comicUniverseBookings.phoneNumber, `%${input.phoneNumber}%`));
|
|
2444
|
+
}
|
|
2445
|
+
if (input.status) {
|
|
2446
|
+
conditions.push(eq(comicUniverseBookings.status, input.status));
|
|
2447
|
+
}
|
|
2448
|
+
const page = Math.max(1, input.page || 1);
|
|
2449
|
+
const limit = Math.min(100, Math.max(1, input.limit || 20));
|
|
2450
|
+
const offset = (page - 1) * limit;
|
|
2451
|
+
const totalResult = await this.db.select({ count: sql`count(*)` }).from(comicUniverseBookings).where(conditions.length > 0 ? and(...conditions) : void 0);
|
|
2452
|
+
const total = totalResult[0]?.count || 0;
|
|
2453
|
+
const bookings = await this.db.select({
|
|
2454
|
+
id: comicUniverseBookings.id,
|
|
2455
|
+
collectionId: comicUniverseBookings.collectionId,
|
|
2456
|
+
qqNumber: comicUniverseBookings.qqNumber,
|
|
2457
|
+
phoneNumber: comicUniverseBookings.phoneNumber,
|
|
2458
|
+
quantity: comicUniverseBookings.quantity,
|
|
2459
|
+
status: comicUniverseBookings.status,
|
|
2460
|
+
notes: comicUniverseBookings.notes,
|
|
2461
|
+
adminNotes: comicUniverseBookings.adminNotes,
|
|
2462
|
+
createdAt: comicUniverseBookings.createdAt,
|
|
2463
|
+
updatedAt: comicUniverseBookings.updatedAt,
|
|
2464
|
+
confirmedAt: comicUniverseBookings.confirmedAt,
|
|
2465
|
+
completedAt: comicUniverseBookings.completedAt,
|
|
2466
|
+
cancelledAt: comicUniverseBookings.cancelledAt,
|
|
2467
|
+
collectionTitle: comicUniverseCollections.title,
|
|
2468
|
+
collectionNumber: comicUniverseCollections.number,
|
|
2469
|
+
collectionCoverImage: comicUniverseCollections.coverImage,
|
|
2470
|
+
collectionPrice: comicUniverseCollections.price
|
|
2471
|
+
}).from(comicUniverseBookings).leftJoin(comicUniverseCollections, eq(comicUniverseBookings.collectionId, comicUniverseCollections.id)).where(conditions.length > 0 ? and(...conditions) : void 0).orderBy(desc(comicUniverseBookings.createdAt)).limit(limit).offset(offset);
|
|
2472
|
+
return {
|
|
2473
|
+
bookings: bookings.map((booking) => ({
|
|
2474
|
+
id: booking.id,
|
|
2475
|
+
collectionId: booking.collectionId,
|
|
2476
|
+
qqNumber: booking.qqNumber,
|
|
2477
|
+
phoneNumber: booking.phoneNumber,
|
|
2478
|
+
quantity: booking.quantity,
|
|
2479
|
+
status: booking.status,
|
|
2480
|
+
notes: booking.notes,
|
|
2481
|
+
adminNotes: booking.adminNotes,
|
|
2482
|
+
createdAt: booking.createdAt?.toISOString(),
|
|
2483
|
+
updatedAt: booking.updatedAt?.toISOString(),
|
|
2484
|
+
confirmedAt: booking.confirmedAt?.toISOString(),
|
|
2485
|
+
completedAt: booking.completedAt?.toISOString(),
|
|
2486
|
+
cancelledAt: booking.cancelledAt?.toISOString(),
|
|
2487
|
+
collection: {
|
|
2488
|
+
id: booking.collectionId,
|
|
2489
|
+
title: booking.collectionTitle,
|
|
2490
|
+
number: booking.collectionNumber,
|
|
2491
|
+
coverImage: booking.collectionCoverImage,
|
|
2492
|
+
price: booking.collectionPrice
|
|
2493
|
+
}
|
|
2494
|
+
})),
|
|
2495
|
+
total,
|
|
2496
|
+
page,
|
|
2497
|
+
limit,
|
|
2498
|
+
totalPages: Math.ceil(total / limit)
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
async getBookingById(id) {
|
|
2502
|
+
const bookings = await this.db.select({
|
|
2503
|
+
id: comicUniverseBookings.id,
|
|
2504
|
+
collectionId: comicUniverseBookings.collectionId,
|
|
2505
|
+
qqNumber: comicUniverseBookings.qqNumber,
|
|
2506
|
+
phoneNumber: comicUniverseBookings.phoneNumber,
|
|
2507
|
+
quantity: comicUniverseBookings.quantity,
|
|
2508
|
+
status: comicUniverseBookings.status,
|
|
2509
|
+
notes: comicUniverseBookings.notes,
|
|
2510
|
+
adminNotes: comicUniverseBookings.adminNotes,
|
|
2511
|
+
createdAt: comicUniverseBookings.createdAt,
|
|
2512
|
+
updatedAt: comicUniverseBookings.updatedAt,
|
|
2513
|
+
confirmedAt: comicUniverseBookings.confirmedAt,
|
|
2514
|
+
completedAt: comicUniverseBookings.completedAt,
|
|
2515
|
+
cancelledAt: comicUniverseBookings.cancelledAt,
|
|
2516
|
+
collectionTitle: comicUniverseCollections.title,
|
|
2517
|
+
collectionNumber: comicUniverseCollections.number,
|
|
2518
|
+
collectionCoverImage: comicUniverseCollections.coverImage,
|
|
2519
|
+
collectionPrice: comicUniverseCollections.price,
|
|
2520
|
+
collectionDescription: comicUniverseCollections.description
|
|
2521
|
+
}).from(comicUniverseBookings).leftJoin(comicUniverseCollections, eq(comicUniverseBookings.collectionId, comicUniverseCollections.id)).where(eq(comicUniverseBookings.id, id)).limit(1);
|
|
2522
|
+
if (bookings.length === 0) {
|
|
2523
|
+
return null;
|
|
2524
|
+
}
|
|
2525
|
+
const booking = bookings[0];
|
|
2526
|
+
return {
|
|
2527
|
+
id: booking.id,
|
|
2528
|
+
collectionId: booking.collectionId,
|
|
2529
|
+
qqNumber: booking.qqNumber,
|
|
2530
|
+
phoneNumber: booking.phoneNumber,
|
|
2531
|
+
quantity: booking.quantity,
|
|
2532
|
+
status: booking.status,
|
|
2533
|
+
notes: booking.notes,
|
|
2534
|
+
adminNotes: booking.adminNotes,
|
|
2535
|
+
createdAt: booking.createdAt?.toISOString(),
|
|
2536
|
+
updatedAt: booking.updatedAt?.toISOString(),
|
|
2537
|
+
confirmedAt: booking.confirmedAt?.toISOString(),
|
|
2538
|
+
completedAt: booking.completedAt?.toISOString(),
|
|
2539
|
+
cancelledAt: booking.cancelledAt?.toISOString(),
|
|
2540
|
+
collection: {
|
|
2541
|
+
id: booking.collectionId,
|
|
2542
|
+
title: booking.collectionTitle,
|
|
2543
|
+
number: booking.collectionNumber,
|
|
2544
|
+
coverImage: booking.collectionCoverImage,
|
|
2545
|
+
price: booking.collectionPrice,
|
|
2546
|
+
description: booking.collectionDescription
|
|
2547
|
+
}
|
|
2548
|
+
};
|
|
2549
|
+
}
|
|
2550
|
+
};
|
|
2551
|
+
function createBookingQueryService(db2) {
|
|
2552
|
+
return new BookingQueryService(db2);
|
|
2553
|
+
}
|
|
2554
|
+
var BookingCommandError = class extends Error {
|
|
2555
|
+
constructor(code, message) {
|
|
2556
|
+
super(message);
|
|
2557
|
+
this.code = code;
|
|
2558
|
+
this.name = "BookingCommandError";
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2561
|
+
var BookingCommandService = class {
|
|
2562
|
+
constructor(db2) {
|
|
2563
|
+
this.db = db2;
|
|
2564
|
+
}
|
|
2565
|
+
async ensureBookingExists(id) {
|
|
2566
|
+
const existingBooking = await this.db.select({ id: comicUniverseBookings.id }).from(comicUniverseBookings).where(eq(comicUniverseBookings.id, id)).limit(1);
|
|
2567
|
+
if (existingBooking.length === 0) {
|
|
2568
|
+
throw new BookingCommandError("BOOKING_NOT_FOUND", "\u9884\u8BA2\u4E0D\u5B58\u5728");
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
async ensureCollectionExists(collectionId) {
|
|
2572
|
+
const collection = await this.db.select({ id: comicUniverseCollections.id }).from(comicUniverseCollections).where(eq(comicUniverseCollections.id, collectionId)).limit(1);
|
|
2573
|
+
if (collection.length === 0) {
|
|
2574
|
+
throw new BookingCommandError("COLLECTION_NOT_FOUND", "\u753B\u96C6\u4E0D\u5B58\u5728");
|
|
2575
|
+
}
|
|
2576
|
+
}
|
|
2577
|
+
validatePhone(phoneNumber) {
|
|
2578
|
+
const phoneRegex = /^1[3-9]\d{9}$/;
|
|
2579
|
+
if (!phoneRegex.test(phoneNumber)) {
|
|
2580
|
+
throw new BookingCommandError("INVALID_PHONE", "\u624B\u673A\u53F7\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
validateQq(qqNumber) {
|
|
2584
|
+
const qqRegex = /^\d{5,11}$/;
|
|
2585
|
+
if (!qqRegex.test(qqNumber)) {
|
|
2586
|
+
throw new BookingCommandError("INVALID_QQ", "QQ\u53F7\u683C\u5F0F\u4E0D\u6B63\u786E");
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
async createBooking(body) {
|
|
2590
|
+
if (!body.collectionId || !body.qqNumber || !body.phoneNumber || !body.quantity) {
|
|
2591
|
+
throw new BookingCommandError("INVALID_PAYLOAD", "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570\uFF1A\u753B\u96C6ID\u3001QQ\u53F7\u3001\u624B\u673A\u53F7\u3001\u9884\u8BA2\u6570\u91CF");
|
|
2592
|
+
}
|
|
2593
|
+
this.validatePhone(body.phoneNumber);
|
|
2594
|
+
this.validateQq(body.qqNumber);
|
|
2595
|
+
if (body.quantity < 1) {
|
|
2596
|
+
throw new BookingCommandError("INVALID_QUANTITY", "\u9884\u8BA2\u6570\u91CF\u5FC5\u987B\u5927\u4E8E0");
|
|
2597
|
+
}
|
|
2598
|
+
await this.ensureCollectionExists(body.collectionId);
|
|
2599
|
+
const existingBooking = await this.db.select({
|
|
2600
|
+
id: comicUniverseBookings.id,
|
|
2601
|
+
quantity: comicUniverseBookings.quantity,
|
|
2602
|
+
notes: comicUniverseBookings.notes
|
|
2603
|
+
}).from(comicUniverseBookings).where(
|
|
2604
|
+
and(
|
|
2605
|
+
eq(comicUniverseBookings.qqNumber, body.qqNumber),
|
|
2606
|
+
eq(comicUniverseBookings.phoneNumber, body.phoneNumber),
|
|
2607
|
+
eq(comicUniverseBookings.collectionId, body.collectionId)
|
|
2608
|
+
)
|
|
2609
|
+
).limit(1);
|
|
2610
|
+
let resultBooking;
|
|
2611
|
+
if (existingBooking.length > 0) {
|
|
2612
|
+
const existing = existingBooking[0];
|
|
2613
|
+
const newQuantity = existing.quantity + body.quantity;
|
|
2614
|
+
const combinedNotes = existing.notes ? `${existing.notes}; \u65B0\u589E\u9884\u8BA2: ${body.notes || "\u65E0\u5907\u6CE8"}` : body.notes || null;
|
|
2615
|
+
const [updatedBooking] = await this.db.update(comicUniverseBookings).set({
|
|
2616
|
+
quantity: newQuantity,
|
|
2617
|
+
notes: combinedNotes,
|
|
2618
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2619
|
+
}).where(
|
|
2620
|
+
and(
|
|
2621
|
+
eq(comicUniverseBookings.qqNumber, body.qqNumber),
|
|
2622
|
+
eq(comicUniverseBookings.phoneNumber, body.phoneNumber),
|
|
2623
|
+
eq(comicUniverseBookings.collectionId, body.collectionId)
|
|
2624
|
+
)
|
|
2625
|
+
).returning();
|
|
2626
|
+
resultBooking = updatedBooking;
|
|
2627
|
+
} else {
|
|
2628
|
+
const [newBooking] = await this.db.insert(comicUniverseBookings).values({
|
|
2629
|
+
collectionId: body.collectionId,
|
|
2630
|
+
qqNumber: body.qqNumber,
|
|
2631
|
+
phoneNumber: body.phoneNumber,
|
|
2632
|
+
quantity: body.quantity,
|
|
2633
|
+
notes: body.notes || null,
|
|
2634
|
+
status: "pending"
|
|
2635
|
+
}).returning();
|
|
2636
|
+
resultBooking = newBooking;
|
|
2637
|
+
}
|
|
2638
|
+
return {
|
|
2639
|
+
id: resultBooking.id,
|
|
2640
|
+
collectionId: resultBooking.collectionId,
|
|
2641
|
+
qqNumber: resultBooking.qqNumber,
|
|
2642
|
+
phoneNumber: resultBooking.phoneNumber,
|
|
2643
|
+
quantity: resultBooking.quantity,
|
|
2644
|
+
status: resultBooking.status,
|
|
2645
|
+
notes: resultBooking.notes,
|
|
2646
|
+
createdAt: resultBooking.createdAt instanceof Date ? resultBooking.createdAt.toISOString() : resultBooking.createdAt,
|
|
2647
|
+
updatedAt: resultBooking.updatedAt instanceof Date ? resultBooking.updatedAt.toISOString() : resultBooking.updatedAt
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
async batchCreateBookings(body) {
|
|
2651
|
+
const { qqNumber, phoneNumber, items, notes, pickupMethod } = body;
|
|
2652
|
+
if (!qqNumber || !phoneNumber || !Array.isArray(items) || items.length === 0) {
|
|
2653
|
+
throw new BookingCommandError("INVALID_PAYLOAD", "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570\uFF1AQQ\u53F7\u3001\u624B\u673A\u53F7\u3001\u9884\u8BA2\u9879\u5217\u8868");
|
|
2654
|
+
}
|
|
2655
|
+
this.validateQq(qqNumber);
|
|
2656
|
+
this.validatePhone(phoneNumber);
|
|
2657
|
+
const bookingIds = [];
|
|
2658
|
+
const failures = [];
|
|
2659
|
+
let successCount = 0;
|
|
2660
|
+
let failCount = 0;
|
|
2661
|
+
for (const item of items) {
|
|
2662
|
+
try {
|
|
2663
|
+
if (!item.collectionId || !item.quantity) {
|
|
2664
|
+
failures.push({ collectionId: item.collectionId, reason: "\u7F3A\u5C11\u5FC5\u8981\u53C2\u6570" });
|
|
2665
|
+
failCount++;
|
|
2666
|
+
continue;
|
|
2667
|
+
}
|
|
2668
|
+
if (item.quantity < 1) {
|
|
2669
|
+
failures.push({ collectionId: item.collectionId, reason: "\u9884\u8BA2\u6570\u91CF\u5FC5\u987B\u5927\u4E8E0" });
|
|
2670
|
+
failCount++;
|
|
2671
|
+
continue;
|
|
2672
|
+
}
|
|
2673
|
+
await this.ensureCollectionExists(item.collectionId);
|
|
2674
|
+
const [newBooking] = await this.db.insert(comicUniverseBookings).values({
|
|
2675
|
+
collectionId: item.collectionId,
|
|
2676
|
+
qqNumber,
|
|
2677
|
+
phoneNumber,
|
|
2678
|
+
quantity: item.quantity,
|
|
2679
|
+
notes: notes || null,
|
|
2680
|
+
pickupMethod: pickupMethod || null,
|
|
2681
|
+
status: "pending"
|
|
2682
|
+
}).returning();
|
|
2683
|
+
bookingIds.push(newBooking.id);
|
|
2684
|
+
successCount++;
|
|
2685
|
+
} catch {
|
|
2686
|
+
failures.push({ collectionId: item.collectionId, reason: "\u521B\u5EFA\u9884\u8BA2\u5931\u8D25" });
|
|
2687
|
+
failCount++;
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
return {
|
|
2691
|
+
bookingIds,
|
|
2692
|
+
successCount,
|
|
2693
|
+
failCount,
|
|
2694
|
+
failures: failures.length > 0 ? failures : void 0
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
async updateBooking(id, body) {
|
|
2698
|
+
await this.ensureBookingExists(id);
|
|
2699
|
+
const updateData = {
|
|
2700
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2701
|
+
};
|
|
2702
|
+
if (body.status) {
|
|
2703
|
+
updateData.status = body.status;
|
|
2704
|
+
switch (body.status) {
|
|
2705
|
+
case "confirmed":
|
|
2706
|
+
updateData.confirmedAt = /* @__PURE__ */ new Date();
|
|
2707
|
+
break;
|
|
2708
|
+
case "completed":
|
|
2709
|
+
updateData.completedAt = /* @__PURE__ */ new Date();
|
|
2710
|
+
break;
|
|
2711
|
+
case "cancelled":
|
|
2712
|
+
updateData.cancelledAt = /* @__PURE__ */ new Date();
|
|
2713
|
+
break;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
if (body.adminNotes !== void 0) {
|
|
2717
|
+
updateData.adminNotes = body.adminNotes;
|
|
2718
|
+
}
|
|
2719
|
+
const [updatedBooking] = await this.db.update(comicUniverseBookings).set(updateData).where(eq(comicUniverseBookings.id, id)).returning();
|
|
2720
|
+
return {
|
|
2721
|
+
id: updatedBooking.id,
|
|
2722
|
+
collectionId: updatedBooking.collectionId,
|
|
2723
|
+
qqNumber: updatedBooking.qqNumber,
|
|
2724
|
+
quantity: updatedBooking.quantity,
|
|
2725
|
+
status: updatedBooking.status,
|
|
2726
|
+
notes: updatedBooking.notes,
|
|
2727
|
+
adminNotes: updatedBooking.adminNotes,
|
|
2728
|
+
createdAt: updatedBooking.createdAt?.toISOString(),
|
|
2729
|
+
updatedAt: updatedBooking.updatedAt?.toISOString(),
|
|
2730
|
+
confirmedAt: updatedBooking.confirmedAt?.toISOString(),
|
|
2731
|
+
completedAt: updatedBooking.completedAt?.toISOString(),
|
|
2732
|
+
cancelledAt: updatedBooking.cancelledAt?.toISOString()
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
async updateBookingStatus(id, status, adminNotes) {
|
|
2736
|
+
if (!status || !["pending", "confirmed", "completed", "cancelled"].includes(status)) {
|
|
2737
|
+
throw new BookingCommandError("INVALID_STATUS", "\u65E0\u6548\u7684\u9884\u8BA2\u72B6\u6001");
|
|
2738
|
+
}
|
|
2739
|
+
await this.ensureBookingExists(id);
|
|
2740
|
+
const updateData = {
|
|
2741
|
+
status,
|
|
2742
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2743
|
+
};
|
|
2744
|
+
if (adminNotes !== void 0) {
|
|
2745
|
+
updateData.adminNotes = adminNotes;
|
|
2746
|
+
}
|
|
2747
|
+
switch (status) {
|
|
2748
|
+
case "confirmed":
|
|
2749
|
+
updateData.confirmedAt = /* @__PURE__ */ new Date();
|
|
2750
|
+
break;
|
|
2751
|
+
case "completed":
|
|
2752
|
+
updateData.completedAt = /* @__PURE__ */ new Date();
|
|
2753
|
+
break;
|
|
2754
|
+
case "cancelled":
|
|
2755
|
+
updateData.cancelledAt = /* @__PURE__ */ new Date();
|
|
2756
|
+
break;
|
|
2757
|
+
}
|
|
2758
|
+
const updatedBookings = await this.db.update(comicUniverseBookings).set(updateData).where(eq(comicUniverseBookings.id, id)).returning();
|
|
2759
|
+
return updatedBookings[0];
|
|
2760
|
+
}
|
|
2761
|
+
async deleteBooking(id) {
|
|
2762
|
+
await this.ensureBookingExists(id);
|
|
2763
|
+
await this.db.delete(comicUniverseBookings).where(eq(comicUniverseBookings.id, id));
|
|
2764
|
+
}
|
|
2765
|
+
};
|
|
2766
|
+
function createBookingCommandService(db2) {
|
|
2767
|
+
return new BookingCommandService(db2);
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
export { BookingCommandError, BookingCommandService, BookingQueryService, CategoriesDbService, MasterpiecesConfigDbService, PopupConfigService, ShowmasterConfigService, TagsDbService, artworksDbService, categoriesDbService, collectionsDbService, comicUniverseArtworks, comicUniverseArtworksRelations, comicUniverseBookings, comicUniverseBookingsRelations, comicUniverseCategories, comicUniverseCategoriesRelations, comicUniverseCollectionTags, comicUniverseCollectionTagsRelations, comicUniverseCollections, comicUniverseCollectionsRelations, comicUniverseConfigs, comicUniverseConfigsRelations, comicUniverseTags, comicUniverseTagsRelations, createBookingCommandService, createBookingQueryService, createCategoriesDbService, createMasterpiecesConfigDbService, createPopupConfigService, createShowmasterConfigService, createTagsDbService, initializeShowmasterpieceDb, masterpiecesConfigDbService, popupConfigs, popupConfigsRelations, showmasterConfigCategories, showmasterConfigHistory, showmasterConfigItems, showmasterConfigPermissions, tagsDbService };
|
|
2771
|
+
//# sourceMappingURL=chunk-VBQFVXOW.mjs.map
|
|
2772
|
+
//# sourceMappingURL=chunk-VBQFVXOW.mjs.map
|