官网内容管理-后端接口开发

This commit is contained in:
eafonyang
2026-07-30 17:33:08 +08:00
parent b1c88fc5e6
commit e71d18b331
34 changed files with 4246 additions and 0 deletions
+3
View File
@@ -10,3 +10,6 @@ export { dashboardUsers } from './dashboardUser.js';
export { shareCodeLogs } from './shareCodeLog.js';
export { userActives } from './userActive.js';
export { userDevices } from './userDevice.js';
// 官网 CMS
export * from './www/index.js';
@@ -0,0 +1,34 @@
import { mysqlTable, bigint, varchar, tinyint, int, json, datetime } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwFormSettings = mysqlTable('www_form_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
recipientEmail: varchar('recipient_email', { length: 100 }).notNull().default(''),
successMessageZh: varchar('success_message_zh', { length: 300 }).notNull().default('感谢您的留言,我们会尽快回复!'),
successMessageEn: varchar('success_message_en', { length: 300 }).notNull().default('Thank you for your message. We will get back to you soon!'),
errorMessageZh: varchar('error_message_zh', { length: 300 }).notNull().default('提交失败,请稍后重试。'),
errorMessageEn: varchar('error_message_en', { length: 300 }).notNull().default('Submission failed. Please try again later.'),
cooldownSeconds: int('cooldown_seconds').notNull().default(60),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwFormFields = mysqlTable('www_form_fields', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
nameZh: varchar('name_zh', { length: 50 }).notNull(),
nameEn: varchar('name_en', { length: 50 }).notNull(),
fieldType: varchar('field_type', { length: 20 }).notNull(),
isRequired: tinyint('is_required').notNull().default(0),
placeholderZh: varchar('placeholder_zh', { length: 100 }).notNull().default(''),
placeholderEn: varchar('placeholder_en', { length: 100 }).notNull().default(''),
optionsJson: json('options_json'),
sortOrder: int('sort_order').notNull().default(0),
});
export const wwwFormSubmissions = mysqlTable('www_form_submissions', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
formData: json('form_data').notNull(),
visitorIp: varchar('visitor_ip', { length: 45 }).notNull().default(''),
userAgent: varchar('user_agent', { length: 500 }).notNull().default(''),
isRead: tinyint('is_read').notNull().default(0),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
});
@@ -0,0 +1,39 @@
import { mysqlTable, bigint, varchar, datetime, int } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwSiteSettings = mysqlTable('www_site_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
siteTitle: varchar('site_title', { length: 100 }).notNull().default(''),
faviconUrl: varchar('favicon_url', { length: 500 }).notNull().default(''),
logoDarkUrl: varchar('logo_dark_url', { length: 500 }).notNull().default(''),
logoLightUrl: varchar('logo_light_url', { length: 500 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwFooterSettings = mysqlTable('www_footer_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
companyName: varchar('company_name', { length: 200 }).notNull().default(''),
companyAddress: varchar('company_address', { length: 500 }).notNull().default(''),
contactPhone: varchar('contact_phone', { length: 50 }).notNull().default(''),
contactEmail: varchar('contact_email', { length: 100 }).notNull().default(''),
copyrightText: varchar('copyright_text', { length: 200 }).notNull().default(''),
icpNumber: varchar('icp_number', { length: 50 }).notNull().default(''),
policeNumber: varchar('police_number', { length: 50 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwSocialLinks = mysqlTable('www_social_links', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
platform: varchar('platform', { length: 30 }).notNull().unique(),
url: varchar('url', { length: 500 }).notNull().default(''),
qrcodeUrl: varchar('qrcode_url', { length: 500 }).notNull().default(''),
sortOrder: int('sort_order').notNull().default(0),
});
export const wwwSeoDefaults = mysqlTable('www_seo_defaults', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
metaDescription: varchar('meta_description', { length: 160 }).notNull().default(''),
metaKeywords: varchar('meta_keywords', { length: 300 }).notNull().default(''),
ogImageUrl: varchar('og_image_url', { length: 500 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
@@ -0,0 +1,9 @@
import { mysqlTable, bigint, varchar } from 'drizzle-orm/mysql-core';
export const wwwI18nEntries = mysqlTable('www_i18n_entries', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
dictKey: varchar('dict_key', { length: 100 }).notNull().unique(),
valueZh: varchar('value_zh', { length: 500 }).notNull().default(''),
valueEn: varchar('value_en', { length: 500 }).notNull().default(''),
description: varchar('description', { length: 200 }).notNull().default(''),
});
@@ -0,0 +1,12 @@
/**
* 官网 CMS Schemas 统一导出
*/
export * from './globalSettings.js';
export * from './nav.js';
export * from './sections.js';
export * from './products.js';
export * from './news.js';
export * from './media.js';
export * from './i18n.js';
export * from './pages.js';
export * from './contact.js';
@@ -0,0 +1,31 @@
import { mysqlTable, bigint, varchar, int, datetime, primaryKey } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwMedia = mysqlTable('www_media', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
filename: varchar('filename', { length: 255 }).notNull(),
filePath: varchar('file_path', { length: 500 }).notNull(),
fileType: varchar('file_type', { length: 10 }).notNull(),
mimeType: varchar('mime_type', { length: 50 }).notNull().default(''),
fileSize: bigint('file_size', { mode: 'number', unsigned: true }).notNull().default(0),
width: int('width'),
height: int('height'),
category: varchar('category', { length: 20 }).notNull().default('other'),
thumbnailUrl: varchar('thumbnail_url', { length: 500 }).notNull().default(''),
webpUrl: varchar('webp_url', { length: 500 }).notNull().default(''),
refCount: int('ref_count').notNull().default(0),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
deletedAt: datetime('deleted_at'),
});
export const wwwMediaTags = mysqlTable('www_media_tags', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
tagName: varchar('tag_name', { length: 50 }).notNull().unique(),
});
export const wwwMediaTagMap = mysqlTable('www_media_tag_map', {
mediaId: bigint('media_id', { mode: 'number', unsigned: true }).notNull(),
tagId: bigint('tag_id', { mode: 'number', unsigned: true }).notNull(),
}, (table) => [
primaryKey({ columns: [table.mediaId, table.tagId] }),
]);
+24
View File
@@ -0,0 +1,24 @@
import { mysqlTable, bigint, varchar, tinyint, int, datetime } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwNavItems = mysqlTable('www_nav_items', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
nameZh: varchar('name_zh', { length: 50 }).notNull(),
nameEn: varchar('name_en', { length: 50 }).notNull(),
link: varchar('link', { length: 500 }).notNull(),
isVisible: tinyint('is_visible').notNull().default(1),
sortOrder: int('sort_order').notNull().default(0),
displayMode: varchar('display_mode', { length: 20 }).notNull().default('text'),
iconName: varchar('icon_name', { length: 50 }).notNull().default(''),
imageUrl: varchar('image_url', { length: 500 }).notNull().default(''),
openNewTab: tinyint('open_new_tab').notNull().default(0),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwNavAppearance = mysqlTable('www_nav_appearance', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
homepageStyle: varchar('homepage_style', { length: 20 }).notNull().default('transparent'),
nonHomepageStyle: varchar('non_homepage_style', { length: 20 }).notNull().default('transparent'),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
+25
View File
@@ -0,0 +1,25 @@
import { mysqlTable, bigint, varchar, int, datetime, mediumtext } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwNewsArticles = mysqlTable('www_news_articles', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
titleZh: varchar('title_zh', { length: 200 }).notNull(),
titleEn: varchar('title_en', { length: 200 }).notNull(),
slug: varchar('slug', { length: 200 }).notNull().unique(),
summaryZh: varchar('summary_zh', { length: 300 }).notNull().default(''),
summaryEn: varchar('summary_en', { length: 300 }).notNull().default(''),
coverUrl: varchar('cover_url', { length: 500 }).notNull().default(''),
contentZh: mediumtext('content_zh'),
contentEn: mediumtext('content_en'),
status: varchar('status', { length: 20 }).notNull().default('draft'),
publishedAt: datetime('published_at'),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwNewsRecommendations = mysqlTable('www_news_recommendations', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
articleId: bigint('article_id', { mode: 'number', unsigned: true }).notNull(),
recommendedId: bigint('recommended_id', { mode: 'number', unsigned: true }).notNull(),
sortOrder: int('sort_order').notNull().default(0),
});
@@ -0,0 +1,80 @@
import { mysqlTable, bigint, varchar, tinyint, int, text, json, datetime } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwPageSeo = mysqlTable('www_page_seo', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
pageType: varchar('page_type', { length: 20 }).notNull(),
entityId: bigint('entity_id', { mode: 'number', unsigned: true }),
metaTitle: varchar('meta_title', { length: 200 }).notNull().default(''),
metaDescription: varchar('meta_description', { length: 160 }).notNull().default(''),
metaKeywords: varchar('meta_keywords', { length: 300 }).notNull().default(''),
ogImageUrl: varchar('og_image_url', { length: 500 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwProductListSettings = mysqlTable('www_product_list_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
heroTitleZh: varchar('hero_title_zh', { length: 100 }).notNull().default('产品中心'),
heroTitleEn: varchar('hero_title_en', { length: 100 }).notNull().default('Products'),
heroSubtitleZh: varchar('hero_subtitle_zh', { length: 200 }).notNull().default('探索高保真音频设备,寻找您的理想之声'),
heroSubtitleEn: varchar('hero_subtitle_en', { length: 200 }).notNull().default('Explore Hi-Fi audio devices, find your ideal sound'),
heroOverlineZh: varchar('hero_overline_zh', { length: 50 }).notNull().default('LUXSIN PRODUCTS'),
heroOverlineEn: varchar('hero_overline_en', { length: 50 }).notNull().default('LUXSIN PRODUCTS'),
heroBgUrl: varchar('hero_bg_url', { length: 500 }).notNull().default(''),
maxColumns: tinyint('max_columns').notNull().default(3),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwNewsListSettings = mysqlTable('www_news_list_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
heroTitleZh: varchar('hero_title_zh', { length: 100 }).notNull().default('新闻中心'),
heroTitleEn: varchar('hero_title_en', { length: 100 }).notNull().default('News'),
heroSubtitleZh: varchar('hero_subtitle_zh', { length: 200 }).notNull().default('获取乐笙最新资讯与行业动态'),
heroSubtitleEn: varchar('hero_subtitle_en', { length: 200 }).notNull().default('Get the latest Luxsin news and industry insights'),
heroBgUrl: varchar('hero_bg_url', { length: 500 }).notNull().default(''),
pageSize: int('page_size').notNull().default(9),
paginationMode: varchar('pagination_mode', { length: 20 }).notNull().default('paginator'),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwAboutSettings = mysqlTable('www_about_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
heroTitleZh: varchar('hero_title_zh', { length: 100 }).notNull().default('关于我们'),
heroTitleEn: varchar('hero_title_en', { length: 100 }).notNull().default('About Us'),
heroSubtitleZh: varchar('hero_subtitle_zh', { length: 200 }).notNull().default(''),
heroSubtitleEn: varchar('hero_subtitle_en', { length: 200 }).notNull().default(''),
heroBgUrl: varchar('hero_bg_url', { length: 500 }).notNull().default(''),
s1TitleZh: varchar('s1_title_zh', { length: 200 }).notNull().default(''),
s1TitleEn: varchar('s1_title_en', { length: 200 }).notNull().default(''),
s1ContentZh: text('s1_content_zh'),
s1ContentEn: text('s1_content_en'),
s1ImageUrl: varchar('s1_image_url', { length: 500 }).notNull().default(''),
s1CtaZh: varchar('s1_cta_zh', { length: 100 }).notNull().default(''),
s1CtaEn: varchar('s1_cta_en', { length: 100 }).notNull().default(''),
s1CtaUrl: varchar('s1_cta_url', { length: 500 }).notNull().default(''),
s2TitleZh: varchar('s2_title_zh', { length: 200 }).notNull().default(''),
s2TitleEn: varchar('s2_title_en', { length: 200 }).notNull().default(''),
s2Features: json('s2_features'),
s3TitleZh: varchar('s3_title_zh', { length: 200 }).notNull().default(''),
s3TitleEn: varchar('s3_title_en', { length: 200 }).notNull().default(''),
s3CtaZh: varchar('s3_cta_zh', { length: 100 }).notNull().default(''),
s3CtaEn: varchar('s3_cta_en', { length: 100 }).notNull().default(''),
s3CtaUrl: varchar('s3_cta_url', { length: 500 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwSupportSettings = mysqlTable('www_support_settings', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
heroTitleZh: varchar('hero_title_zh', { length: 100 }).notNull().default('技术支持'),
heroTitleEn: varchar('hero_title_en', { length: 100 }).notNull().default('Support'),
heroSubtitleZh: varchar('hero_subtitle_zh', { length: 200 }).notNull().default(''),
heroSubtitleEn: varchar('hero_subtitle_en', { length: 200 }).notNull().default(''),
heroBgUrl: varchar('hero_bg_url', { length: 500 }).notNull().default(''),
s1FaqCategories: json('s1_faq_categories'),
s2Downloads: json('s2_downloads'),
s3Contact: json('s3_contact'),
s4CtaZh: varchar('s4_cta_zh', { length: 100 }).notNull().default(''),
s4CtaEn: varchar('s4_cta_en', { length: 100 }).notNull().default(''),
s4CtaUrl: varchar('s4_cta_url', { length: 500 }).notNull().default(''),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
@@ -0,0 +1,31 @@
import { mysqlTable, bigint, varchar, tinyint, int, datetime } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwProductSeries = mysqlTable('www_product_series', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
nameZh: varchar('name_zh', { length: 100 }).notNull(),
nameEn: varchar('name_en', { length: 100 }).notNull(),
overline: varchar('overline', { length: 50 }).notNull().default(''),
subtitleZh: varchar('subtitle_zh', { length: 200 }).notNull().default(''),
subtitleEn: varchar('subtitle_en', { length: 200 }).notNull().default(''),
coverUrl: varchar('cover_url', { length: 500 }).notNull().default(''),
sortOrder: int('sort_order').notNull().default(0),
isVisible: tinyint('is_visible').notNull().default(1),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwProducts = mysqlTable('www_products', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
seriesId: bigint('series_id', { mode: 'number', unsigned: true }).notNull(),
nameZh: varchar('name_zh', { length: 100 }).notNull(),
nameEn: varchar('name_en', { length: 100 }).notNull(),
slug: varchar('slug', { length: 100 }).notNull().unique(),
introZh: varchar('intro_zh', { length: 200 }).notNull().default(''),
introEn: varchar('intro_en', { length: 200 }).notNull().default(''),
coverUrl: varchar('cover_url', { length: 500 }).notNull().default(''),
sortOrder: int('sort_order').notNull().default(0),
isVisible: tinyint('is_visible').notNull().default(1),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
@@ -0,0 +1,55 @@
import { mysqlTable, bigint, varchar, tinyint, int, text, decimal, json, datetime } from 'drizzle-orm/mysql-core';
import { sql } from 'drizzle-orm';
export const wwwSectionBlocks = mysqlTable('www_section_blocks', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
pageType: varchar('page_type', { length: 20 }).notNull(),
productId: bigint('product_id', { mode: 'number', unsigned: true }),
layout: varchar('layout', { length: 30 }).notNull(),
theme: varchar('theme', { length: 10 }).notNull().default('light'),
bgType: varchar('bg_type', { length: 10 }).notNull().default('color'),
bgValue: varchar('bg_value', { length: 500 }).notNull().default(''),
overlayEnabled: tinyint('overlay_enabled').notNull().default(0),
overlayOpacity: decimal('overlay_opacity', { precision: 3, scale: 2 }).notNull().default('0.00'),
overlineZh: varchar('overline_zh', { length: 100 }).notNull().default(''),
overlineEn: varchar('overline_en', { length: 100 }).notNull().default(''),
titleZh: varchar('title_zh', { length: 200 }).notNull().default(''),
titleEn: varchar('title_en', { length: 200 }).notNull().default(''),
subtitleZh: varchar('subtitle_zh', { length: 300 }).notNull().default(''),
subtitleEn: varchar('subtitle_en', { length: 300 }).notNull().default(''),
contentZh: text('content_zh'),
contentEn: text('content_en'),
ctaPrimaryZh: varchar('cta_primary_zh', { length: 100 }).notNull().default(''),
ctaPrimaryEn: varchar('cta_primary_en', { length: 100 }).notNull().default(''),
ctaPrimaryUrl: varchar('cta_primary_url', { length: 500 }).notNull().default(''),
ctaSecondaryZh: varchar('cta_secondary_zh', { length: 100 }).notNull().default(''),
ctaSecondaryEn: varchar('cta_secondary_en', { length: 100 }).notNull().default(''),
ctaSecondaryUrl: varchar('cta_secondary_url', { length: 500 }).notNull().default(''),
mediaUrlZh: varchar('media_url_zh', { length: 500 }).notNull().default(''),
mediaUrlEn: varchar('media_url_en', { length: 500 }).notNull().default(''),
videoUrl: varchar('video_url', { length: 500 }).notNull().default(''),
config: json('config'),
isVisible: tinyint('is_visible').notNull().default(1),
sortOrder: int('sort_order').notNull().default(0),
createdAt: datetime('created_at').notNull().default(sql`CURRENT_TIMESTAMP`),
updatedAt: datetime('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`),
});
export const wwwSpecGroups = mysqlTable('www_spec_groups', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
sectionBlockId: bigint('section_block_id', { mode: 'number', unsigned: true }).notNull(),
titleZh: varchar('title_zh', { length: 100 }).notNull(),
titleEn: varchar('title_en', { length: 100 }).notNull(),
sortOrder: int('sort_order').notNull().default(0),
defaultVisible: int('default_visible').notNull().default(5),
});
export const wwwSpecItems = mysqlTable('www_spec_items', {
id: bigint('id', { mode: 'number', unsigned: true }).primaryKey().autoincrement(),
specGroupId: bigint('spec_group_id', { mode: 'number', unsigned: true }).notNull(),
nameZh: varchar('name_zh', { length: 100 }).notNull(),
nameEn: varchar('name_en', { length: 100 }).notNull(),
valueZh: varchar('value_zh', { length: 500 }).notNull(),
valueEn: varchar('value_en', { length: 500 }).notNull(),
sortOrder: int('sort_order').notNull().default(0),
});